Versuchen Sie es mit dem Java SDK von Hyperledger Iroha

Artikelinhalt

Ich habe versucht, den Java SDK-Beispielcode in der Hyperledger Iroha-Dokumentation auszuführen. Es hat lange gedauert, es zu bewegen, also werde ich verlassen, was ich getan habe.

Umgebung

Umgebung

Ich habe mich für das Verfahren auf dieses Dokument bezogen. https://iroha.readthedocs.io/ja/latest/getting_started/index.html

Implementierung

Ich habe ein Maven-Projekt in Eclipse erstellt und den Beispielcode ausgeführt. pom.xml Es war ein ziemlich Stolperstein vor dem Beispielcode, aber ich hatte große Probleme, ihn durch die Kompilierung zu bekommen. Als Ergebnis verschiedener Versuche wurde es die folgende pom.xml.

pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <name>iroha</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <maven.compiler.target>${java.version}</maven.compiler.target>
    <maven.compiler.source>${java.version}</maven.compiler.source>
  </properties>
  <repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
    <repository>
      <id>mvn</id>
      <url>https://mvnrepository.com</url>
    </repository>
  </repositories>
  <dependencies>
    <!-- https://mvnrepository.com/artifact/io.grpc/protoc-gen-grpc-java -->
    <dependency>
     <groupId>io.grpc</groupId>
     <artifactId>grpc-protobuf</artifactId>
     <version>1.22.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/io.grpc/grpc-netty -->
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-netty</artifactId>
      <version>1.22.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/io.grpc/grpc-stub -->
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-stub</artifactId>
      <version>1.22.1</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>protoc-gen-grpc-java</artifactId>
      <version>1.12.0</version>
    </dependency>
    <dependency>
      <groupId>com.github.hyperledger</groupId>
      <artifactId>iroha-java</artifactId>
      <version>6.1.0</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/jp.co.soramitsu/iroha -->
    <dependency>
      <groupId>jp.co.soramitsu</groupId>
      <artifactId>iroha</artifactId>
      <version>0.0.8</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
      <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util -->
    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java-util</artifactId>
      <version>3.10.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java</artifactId>
      <version>3.10.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.testinfected.hamcrest-matchers/core-matchers -->
    <dependency>
      <groupId>org.testinfected.hamcrest-matchers</groupId>
      <artifactId>core-matchers</artifactId>
      <version>1.5</version>
    </dependency>

  </dependencies>
  <build>
  <plugins>
  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
      <source>1.8</source>
      <target>1.8</target>
      <encoding>UTF-8</encoding>
      <compilerArgument>-Werror</compilerArgument>
   </configuration>
  </plugin>
  </plugins>
  </build>
</project>

Es gibt zwei Punkte, die gestolpert sind.

Der erste Punkt scheint eine gewisse Abhängigkeit von der JAR-Datei von "protoc-gen-grpc-java" zu haben, und ein Fehler ist aufgetreten, wenn keine JAR-Datei vorhanden war. Ich habe eine Abhängigkeit hinzugefügt, aber die JAR-Datei war im Maven-Repository von "protoc-gen-grpc-java" nicht vorhanden. Nachdem ich verschiedene Dinge ausprobiert hatte, löste ich es, indem ich eine entsprechende JAR-Datei umbenannte und lokal platzierte. Anscheinend hat es eine Abhängigkeit, wurde aber nicht aufgerufen.

Der zweite Punkt scheint sich auf die Klasse "TestRule" von junit im Glas von iroha zu beziehen. Diese Klasse scheint seit Version 4.12 von junit hinzugefügt worden zu sein, und die Version musste 4.12 oder höher sein.

Beispielcode

Dies ist der Beispielcode in der Dokumentation.

Example1.java


import iroha.protocol.BlockOuterClass;
import iroha.protocol.Primitive.RolePermission;
import java.math.BigDecimal;
import java.security.KeyPair;
import java.util.Arrays;
import jp.co.soramitsu.crypto.ed25519.Ed25519Sha3;
import jp.co.soramitsu.iroha.testcontainers.IrohaContainer;
import jp.co.soramitsu.iroha.testcontainers.PeerConfig;
import jp.co.soramitsu.iroha.testcontainers.detail.GenesisBlockBuilder;
import lombok.val;

public class Example1 {

  private static final String bankDomain = "bank";
  private static final String userRole = "user";
  private static final String usdName = "usd";

  private static final Ed25519Sha3 crypto = new Ed25519Sha3();

  private static final KeyPair peerKeypair = crypto.generateKeypair();

  private static final KeyPair useraKeypair = crypto.generateKeypair();
  private static final KeyPair userbKeypair = crypto.generateKeypair();

  private static String user(String name) {
    return String.format("%s@%s", name, bankDomain);
  }

  private static final String usd = String.format("%s#%s", usdName, bankDomain);

  /**
   * <pre>
   * Our initial state cosists of:
   * - domain "bank", with default role "user" - can transfer assets and can query their amount
   * - asset usd#bank with precision 2
   * - user_a@bank, which has 100 usd
   * - user_b@bank, which has 0 usd
   * </pre>
   */
  private static BlockOuterClass.Block getGenesisBlock() {
    return new GenesisBlockBuilder()
        // first transaction
        .addTransaction(
            // transactions in genesis block can have no creator
            Transaction.builder(null)
                // by default peer is listening on port 10001
                .addPeer("0.0.0.0:10001", peerKeypair.getPublic())
                // create default "user" role
                .createRole(userRole,
                    Arrays.asList(
                        RolePermission.can_transfer,
                        RolePermission.can_get_my_acc_ast,
                        RolePermission.can_get_my_txs,
                        RolePermission.can_receive
                    )
                )
                .createDomain(bankDomain, userRole)
                // create user A
                .createAccount("user_a", bankDomain, useraKeypair.getPublic())
                // create user B
                .createAccount("user_b", bankDomain, userbKeypair.getPublic())
                // create usd#bank with precision 2
                .createAsset(usdName, bankDomain, 2)
                // transactions in genesis block can be unsigned
                .build() // returns ipj model Transaction
                .build() // returns unsigned protobuf Transaction
        )
        // we want to increase user_a balance by 100 usd
        .addTransaction(
            Transaction.builder(user("user_a"))
                .addAssetQuantity(usd, new BigDecimal("100"))
                .build()
                .build()
        )
        .build();
  }

  public static PeerConfig getPeerConfig() {
    PeerConfig config = PeerConfig.builder()
        .genesisBlock(getGenesisBlock())
        .build();

    // don't forget to add peer keypair to config
    config.withPeerKeyPair(peerKeypair);

    return config;
  }

  /**
   * Custom facade over GRPC Query
   */
  public static int getBalance(IrohaAPI api, String userId, KeyPair keyPair) {
    // build protobuf query, sign it
    val q = Query.builder(userId, 1)
        .getAccountAssets(userId)
        .buildSigned(keyPair);

    // execute query, get response
    val res = api.query(q);

    // get list of assets from our response
    val assets = res.getAccountAssetsResponse().getAccountAssetsList();

    // find usd asset
    val assetUsdOptional = assets
        .stream()
        .filter(a -> a.getAssetId().equals(usd))
        .findFirst();

    // numbers are small, so we use int here for simplicity
    return assetUsdOptional
        .map(a -> Integer.parseInt(a.getBalance()))
        .orElse(0);
  }

  public static void main(String[] args) {
    // for simplicity, we will create Iroha peer in place
    IrohaContainer iroha = new IrohaContainer()
        .withPeerConfig(getPeerConfig());

    // start the peer. blocking call
    iroha.start();

    // create API wrapper
    IrohaAPI api = new IrohaAPI(iroha.getToriiAddress());

    // transfer 100 usd from user_a to user_b
    val tx = Transaction.builder("user_a@bank")
        .transferAsset("user_a@bank", "user_b@bank", usd, "For pizza", "10")
        .sign(useraKeypair)
        .build();

    // create transaction observer
    // here you can specify any kind of handlers on transaction statuses
    val observer = TransactionStatusObserver.builder()
        // executed when stateless or stateful validation is failed
        .onTransactionFailed(t -> System.out.println(String.format(
            "transaction %s failed with msg: %s",
            t.getTxHash(),
            t.getErrOrCmdName()
        )))
        // executed when got any exception in handlers or grpc
        .onError(e -> System.out.println("Failed with exception: " + e))
        // executed when we receive "committed" status
        .onTransactionCommitted((t) -> System.out.println("Committed :)"))
        // executed when transfer is complete (failed or succeed) and observable is closed
        .onComplete(() -> System.out.println("Complete"))
        .build();

    // blocking send.
    // use .subscribe() for async sending
    api.transaction(tx)
        .blockingSubscribe(observer);

    /// now lets query balances
    val balanceUserA = getBalance(api, user("user_a"), useraKeypair);
    val balanceUserB = getBalance(api, user("user_b"), userbKeypair);

    // ensure we got correct balances
    assert balanceUserA == 90;
    assert balanceUserB == 10;
  }
}

Vorerst werde ich es verschieben.

[main] INFO org.testcontainers.dockerclient.DockerClientProviderStrategy - Will use 'okhttp' transport
[main] INFO org.testcontainers.dockerclient.DockerClientProviderStrategy - Will use 'okhttp' transport
[main] INFO org.testcontainers.dockerclient.DockerMachineClientProviderStrategy - Found docker-machine, and will use machine named default
[main] INFO org.testcontainers.dockerclient.DockerMachineClientProviderStrategy - Docker daemon IP address for docker machine default is 192.168.99.100
[main] INFO org.testcontainers.dockerclient.DockerClientProviderStrategy - Will use 'okhttp' transport
[main] ERROR org.testcontainers.dockerclient.DockerClientProviderStrategy - Could not find a valid Docker environment. Please check configuration. Attempted configurations were:
[main] ERROR org.testcontainers.dockerclient.DockerClientProviderStrategy -     NpipeSocketClientProviderStrategy: failed with exception InvalidConfigurationException (ping failed). Root cause TimeoutException (null)
[main] ERROR org.testcontainers.dockerclient.DockerClientProviderStrategy -     WindowsClientProviderStrategy: failed with exception TimeoutException (Timeout waiting for result with exception). Root cause ConnectException (Connection refused: connect)
[main] ERROR org.testcontainers.dockerclient.DockerClientProviderStrategy -     DockerMachineClientProviderStrategy: failed with exception TimeoutException (Timeout waiting for result with exception). Root cause ConnectException (Connection refused: connect)
[main] ERROR org.testcontainers.dockerclient.DockerClientProviderStrategy - As no valid configuration was found, execution cannot continue
Exception in thread "main" java.lang.IllegalStateException: Could not find a valid Docker environment. Please see logs and check configuration

Ja. Ich habe einen Fehler bekommen.

「Could not find a valid Docker environment.」 Dieser Fehler scheint aufzutreten, wenn ich versuche, Docker von Java aus zu betreiben, und die "Docker-Datei" nicht vorhanden ist.

Ich erstelle eine Umgebung mit VirtualBox, nicht mit Docker, also hat es nicht funktioniert.

Wenn Sie das Programm hier richtig lesen, wird Peer hinzugefügt, ein Konto im hinzugefügten Peer erstellt und Asset (Token) gesendet.

Löschen Sie den Teil, der Docker betreibt, aus der Verarbeitung der Hauptanweisung und ändern Sie ihn in "admin @ test" und "test @ test", die standardmäßig auch für den Benutzer erstellt werden.

Example1.java


  public static void main(String[] args) throws Exception{
    URI uri = new URI(null,null, "IP Adresse",50051,null,null,null);

    // create API wrapper
    IrohaAPI api = new IrohaAPI(uri);

    // transfer 100 usd from user_a to user_b
    val tx = Transaction.builder("admin@test")
        .transferAsset("admin@test", "test@test", usd, "For pizza", "10")
        .sign(useraKeypair)
        .build();

    // create transaction observer
    // here you can specify any kind of handlers on transaction statuses
    val observer = TransactionStatusObserver.builder()
        // executed when stateless or stateful validation is failed
        .onTransactionFailed(t -> System.out.println(String.format(
            "transaction %s failed with msg: %s",
            t.getTxHash(),
            t.getErrOrCmdName()
        )))
        // executed when got any exception in handlers or grpc
        .onError(e -> System.out.println("Failed with exception: " + e))
        // executed when we receive "committed" status
        .onTransactionCommitted((t) -> System.out.println("Committed :)"))
        // executed when transfer is complete (failed or succeed) and observable is closed
        .onComplete(() -> System.out.println("Complete"))
        .build();

    // blocking send.
    // use .subscribe() for async sending
    api.transaction(tx)
        .blockingSubscribe(observer);

    /// now lets query balances
    val balanceUserA = getBalance(api, user("user_a"), useraKeypair);
    val balanceUserB = getBalance(api, user("user_b"), userbKeypair);

    // ensure we got correct balances
    assert balanceUserA == 90;
    assert balanceUserB == 10;
  }

Der Punkt, den ich geändert habe, ist der Konstruktor der Klasse "IrohaApi". Dieser Konstruktor verwendet eine URI-Klasse, ruft jedoch nur die Domäne und den Port von der im Konstruktor empfangenen URI-Klasse ab. Erstellen Sie also eine URI-Klasse, die nur die Domäne und den Port festlegt, und legen Sie sie als Argument fest. Wenn Sie dies bisher tun können, führen Sie es aus.

transaction c3d966d1cbc521b99e1cb60cbe444f129947bdfbe348abe7b7262dd81079c505 failed with msg: signatures validation
Complete

Ich habe einen Fehler bekommen, aber es hat vorerst funktioniert. Die Ursache für diesen Fehler ist, dass das zum Signieren der Transaktion verwendete KeyPair nicht von admin @ test stammt.

Ich kenne die Ursache, aber ich untersuche immer noch, wie ich damit umgehen soll, also werde ich sie aktualisieren, sobald ich es herausfinde.

09.10.2019 Nachtrag

Jetzt, da ich weiß, wie man eine Transaktion sendet, werde ich sie hinzufügen.

Example1.java


  public static void main(String[] args) throws Exception{

    URI uri = new URI(null,null, "192.168.33.10",50051,null,null,null);

    // create API wrapper
    IrohaAPI api = new IrohaAPI(uri);

    byte[] pubByte = Hex.decodeHex("[email protected] der Kneipe (öffentlicher Schlüssel)");
    byte[] privByte = Hex.decodeHex("[email protected] von priv (privater Schlüssel)");

    KeyPair adminKeyPair = Ed25519Sha3.keyPairFromBytes(privByte, pubByte);

    // transfer 100 usd from user_a to user_b
    val tx = Transaction.builder("admin@test")
        .transferAsset("admin@test", "test@test", usd, "For pizza", "10")
        .sign(adminKeyPair)
        .build();

    // create transaction observer
    // here you can specify any kind of handlers on transaction statuses
    val observer = TransactionStatusObserver.builder()
        // executed when stateless or stateful validation is failed
        .onTransactionFailed(t -> System.out.println(String.format(
            "transaction %s failed with msg: %s",
            t.getTxHash(),
            t.getErrOrCmdName()
        )))
        // executed when got any exception in handlers or grpc
        .onError(e -> System.out.println("Failed with exception: " + e))
        // executed when we receive "committed" status
        .onTransactionCommitted((t) -> System.out.println("Committed :)"))
        // executed when transfer is complete (failed or succeed) and observable is closed
        .onComplete(() -> System.out.println("Complete"))
        .build();

    // blocking send.
    // use .subscribe() for async sending
    api.transaction(tx)
        .blockingSubscribe(observer);

    /// now lets query balances
    val balanceUserA = getBalance(api, user("user_a"), useraKeypair);
    val balanceUserB = getBalance(api, user("user_b"), userbKeypair);

    // ensure we got correct balances
    assert balanceUserA == 90;
    assert balanceUserB == 10;
  }

Der Punkt besteht darin, ein KeyPair-Objekt aus dem öffentlichen und dem privaten Schlüssel zu erstellen.

    byte[] pubByte = Hex.decodeHex("[email protected] der Kneipe (öffentlicher Schlüssel)");
    byte[] privByte = Hex.decodeHex("[email protected] von priv (privater Schlüssel)");

    KeyPair adminKeyPair = Ed25519Sha3.keyPairFromBytes(privByte, pubByte);

Setzen Sie dies in das Argument der sign-Methode und Sie sind fertig. Ich werde es versuchen.

Committed :)
Complete

Es endete normal.

Werfen wir einen Blick auf den Inhalt des Blocks. Wenn Sie die Umgebung gemäß dem Verfahren im offiziellen Dokument erstellen, sollte sie im Verzeichnis "/ tmp / block_store" ausgegeben werden. Der Inhalt ist JSON geformt.

{
  "blockV1": {
    "payload": {
      "transactions": [
        {
          "payload": {
            "reducedPayload": {
              "commands": [
                {
                  "transferAsset": {
                    "srcAccountId": "admin@test",
                    "destAccountId": "test@test",
                    "assetId": "usd#bank",
                    "description": "For pizza",
                    "amount": "10"
                  }
                }
              ],
              "creatorAccountId": "admin@test",
              "createdTime": "1570624170543",
              "quorum": 1
            }
          },
          "signatures": [
            {
              "publicKey": "313A07E6384776ED95447710D15E59148473CCFC052A681317A72A69F2A49910",
              "signature": "4B2B45A4F2FDB9A7DE6F30E110D8DEA5E5AAB30C40F5685CFA71FDC38E72BF3839954DDA13FE027FEA18DA9F97332E5E265822922204D38F1667D60E5F8E9601"
            }
          ]
        }
      ],
      "height": "17",
      "prevBlockHash": "ff33c8483725758e09583e7f670b9c37a091357bc027602a72452d44907861f1",
      "createdTime": "1570624184188"
    },
    "signatures": [
      {
        "publicKey": "bddd58404d1315e0eb27902c5d7c8eb0602c16238f005773df406bc191308929",
        "signature": "680ee97a530314e877ee7518b22975607e328a232a60f963029cb07b18b9101d0de6bf174ecd07ab29bac8123e8c47f12761835a121b301f192c0de9a908670e"
      }
    ]
  }
}

Ich konnte bestätigen, dass es sicher in den Block importiert wurde.

Impressionen

Ich habe kürzlich Ethereum studiert, damit ich es ohne Bergbau in den Block bringen kann, ja? Aber wenn Sie darüber nachdenken, ist es natürlich.

Selbst wenn ich dieses Beispielprogramm ausführe, habe ich den Eindruck, dass es auf Japanisch nur sehr wenige Informationen gibt. Ich denke darüber nach, eine einfache Wallet-App zu erstellen und Kettencode bereitzustellen, daher sollte ich aktiv Informationen hinterlassen.

Recommended Posts

Versuchen Sie es mit dem Java SDK von Hyperledger Iroha
Blockinformationen erhalten Sie mit dem Java SDK von Hyperledger Iroha
Versuchen Sie eine ähnliche Suche in der Bildsuche mit dem Java SDK [Suche]
Versuchen Sie es mit RocksDB mit Java
Versuchen Sie, mit Java zu kratzen [Hinweis]
Probieren Sie die ähnliche Suche von Image Search mit Java SDK [Registrierung] aus.
Versuchen Sie es mit Redis mit Java (jar)
[Java] Versuchen Sie, mithilfe von Generika zu implementieren
Versuchen Sie es mit der IBM Java-Methodenverfolgung
Versuchen Sie Spark Submit to EMR mit AWS SDK für Java
[Java] Wo haben Sie versucht, Java zu verwenden?
Versuchen Sie es mit dem Java Framework Nablarch [Web Application]
Versuchen Sie es mit der Stream-API in Java
Versuchen Sie es mit der JSON-Format-API in Java
Versuchen Sie es mit der REST-API von JobScheduler - Java RestClient-Implementierung -
Versuchen Sie es mit der Wii-Fernbedienung in Java
Versuchen Sie es mit libGDX
Versuchen Sie es mit Maven
Versuchen Sie es mit powermock-mockito2-2.0.2
Versuchen Sie es mit GraalVM
Probieren Sie Java 8 Stream aus
Versuchen Sie es mit jmockit 1.48
Versuchen Sie es mit SwiftLint
Versuchen Sie es mit Log4j 2.0
Versuchen Sie es mit Java 9
Versuchen Sie, Firebase Cloud-Funktionen unter Android (Java) zu verwenden.
Versuchen Sie es mit der RestClient Test-Klasse der REST-API-Java von JobScheduler.
Versuchen Sie, die Cloud Vision-API von GCP in Java zu verwenden
Versuchen Sie es mit Sourcetrail (MacOS-Version) mit Java-Code
Versuchen Sie, mit JZOS von Java aus auf das Dataset zuzugreifen
Versuchen Sie die Kommunikation mit gRPC auf einem Android + Java-Server
Sortieren mit Java-Komparator
Versuchen Sie es mit der REST-API von JobScheduler
Versuchen Sie es mit der Methode java.lang.Math
Versuchen Sie es mit der WhiteBox von PowerMock
Versuchen Sie, das Eratostenes-Sieb mithilfe der Java-Standardbibliothek zu implementieren
Ich habe versucht, SQS mit AWS Java SDK zu betreiben
Versuchen Sie es mit Talend Teil 2
Schrottpraxis mit Java ②
Rufen wir IBM Watson Assistant 2018-07-10 aus dem Java SDK auf.
Schrottpraxis mit Java ①
Versuchen Sie die Bildklassifizierung mit TensorFlow Lite unter Android (JAVA).
Versuchen Sie es mit globalem Hooking in Java mithilfe der JNativeHook-Bibliothek
Versuchen Sie es mit Talend Teil 1
Versuchen Sie es mit der F # -Liste
Versuchen Sie, mit Docker eine Java-Entwicklungsumgebung zu erstellen
Versuchen Sie es mit der Methode each_with_index
Versuchen Sie es mit dem Java-Rückgabewert
Versuchen Sie es mit Spring JDBC
Implementieren Sie Thread in Java und versuchen Sie, die anonyme Klasse Lambda zu verwenden
[Java] Versuchen Sie, die Elemente der Json-Zeichenfolge mithilfe der Bibliothek zu bearbeiten
Versuchen Sie es mit GloVe mit Deeplearning4j
Versuchen Sie eine DB-Verbindung mit Java
Versuchen Sie, JavaScript in Java aufzurufen
Versuchen Sie es mit Cocoa von Ruby
Lassen Sie uns Spresense mit Java entwickeln (1)
Probieren Sie den Funktionstyp in Java aus! ①
Versuchen Sie gRPC mit Java, Maven