Essayez d'utiliser le SDK Java d'Hyperledger Iroha

Contenu de l'article

J'ai essayé d'exécuter l'exemple de code Java SDK dans la documentation Hyperledger Iroha. Il a fallu beaucoup de temps pour le déplacer, alors je vais laisser ce que j'ai fait.

environnement

Environnement

Je me suis référé à ce document pour la procédure. https://iroha.readthedocs.io/ja/latest/getting_started/index.html

la mise en oeuvre

J'ai créé un projet maven dans eclipse et exécuté l'exemple de code. pom.xml C'était une jolie pierre d'achoppement avant l'exemple de code, mais j'ai eu beaucoup de mal à le faire passer par la compilation. À la suite de divers essais, il est devenu le pom.xml suivant.

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>

Il y a deux points qui ont trébuché.

Le premier point semble avoir une certaine dépendance sur le fichier jar de "protoc-gen-grpc-java", et une erreur s'est produite s'il n'y avait pas de fichier jar. J'ai ajouté une dépendance, mais le fichier jar n'existait pas dans le référentiel maven pour "protoc-gen-grpc-java". Après avoir essayé diverses choses, je l'ai résolu en renommant un fichier jar approprié et en le plaçant localement. Apparemment, il a une dépendance mais n'a pas été appelé.

Le deuxième point semble se référer à la classe appelée "TestRule" de junit dans le pot d'iroha. Cette classe semble avoir été ajoutée depuis la version 4.12 de junit, et la version devait être 4.12 ou supérieure.

Exemple de code

Ceci est l'exemple de code dans la documentation.

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;
  }
}

Pour le moment, je vais le proposer.

[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

Oui. J'ai une erreur.

「Could not find a valid Docker environment.」 Cette erreur semble se produire lorsque j'essaye d'utiliser Docker à partir de Java et que le "Dockerfile" n'existe pas.

Je crée un environnement avec VirtualBox, pas Docker, donc cela n'a pas fonctionné.

Si vous lisez correctement le programme ici, l'homologue est ajouté, un compte est créé dans l'homologue ajouté et l'actif (jeton) est envoyé.

Supprimez la partie qui exploite Docker du traitement de l'instruction principale et remplacez-la par "admin @ test" et "test @ test" qui sont également créés par défaut pour l'utilisateur.

Example1.java


  public static void main(String[] args) throws Exception{
    URI uri = new URI(null,null, "adresse IP",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;
  }

Le point que j'ai modifié est le constructeur de la classe "IrohaApi". Ce constructeur prend une classe URI, mais obtient uniquement le domaine et le port de la classe URI reçue dans le constructeur. Alors, créez une classe URI qui définit uniquement le domaine et le port, et définissez-la comme argument. Si vous pouvez le faire jusqu'à présent, exécutez-le.

transaction c3d966d1cbc521b99e1cb60cbe444f129947bdfbe348abe7b7262dd81079c505 failed with msg: signatures validation
Complete

J'ai eu une erreur, mais cela a fonctionné pour le moment. La cause de cette erreur est que le KeyPair utilisé pour signer la transaction ne provient pas de admin @ test.

Je connais la cause, mais j'étudie toujours comment y faire face, donc je la mettrai à jour dès que je le saurai.

2019/10/09 postscript

Je sais comment envoyer une transaction, je vais donc l'ajouter.

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] du pub (clé publique)");
    byte[] privByte = Hex.decodeHex("[email protected] de priv (clé privée)");

    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;
  }

En tant que point, créez un objet KeyPair à partir de la clé publique et de la clé privée.

    byte[] pubByte = Hex.decodeHex("[email protected] du pub (clé publique)");
    byte[] privByte = Hex.decodeHex("[email protected] de priv (clé privée)");

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

Définissez ceci dans l'argument de la méthode sign et vous avez terminé. Je vais essayer.

Committed :)
Complete

Cela s'est terminé normalement.

Jetons un coup d'œil au contenu du bloc. Si vous construisez l'environnement selon la procédure du document officiel, il doit être sorti dans le répertoire "/ tmp / block_store". Le contenu est en forme de JSON.

{
  "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"
      }
    ]
  }
}

J'ai pu confirmer qu'il a été importé en toute sécurité dans le bloc.

Impressions

J'ai étudié l'éthereum récemment, donc je peux l'introduire dans le bloc sans miner, oui? Mais quand on y pense, c'est naturel.

Même si j'exécute cet exemple de programme, j'ai l'impression qu'il y a très peu d'informations en japonais. Je pense créer une application de portefeuille simple et déployer du code de chaîne, alors j'aimerais laisser activement des informations.

Recommended Posts

Essayez d'utiliser le SDK Java d'Hyperledger Iroha
Résumé Il n'y a rien de particulier. Dois-je y prêter attention? .. .. J'ai ressenti cela, alors j'ai écrit un article. Si vous avez des commentaires, veuillez. Obtenez des informations de bloc avec le SDK Java de Python, Python3, Glossy Hyperledger Iroha
Essayez une recherche similaire de recherche d'images à l'aide du SDK Java [Recherche]
Essayez d'utiliser RocksDB avec Java
Essayez de gratter en utilisant Java [Note]
Essayez la recherche similaire de Recherche d'images à l'aide du SDK Java [Inscription]
Essayez d'utiliser Redis avec Java (jar)
[Java] Essayez de mettre en œuvre à l'aide de génériques
Essayez d'utiliser le traçage de méthode IBM Java
Essayez Spark Submit to EMR à l'aide du kit AWS SDK pour Java
[Java] Où avez-vous essayé d'utiliser java
Essayez d'utiliser le framework Java Nablarch [Application Web]
Essayez d'utiliser l'API Stream en Java
Essayez d'utiliser l'API au format JSON en Java
Essayez d'utiliser l'API REST de JobScheduler - implémentation Java RestClient--
Essayez d'utiliser la télécommande Wii en Java
Essayez d'utiliser libGDX
Essayez d'utiliser Maven
Essayez d'utiliser powermock-mockito2-2.0.2
Essayez d'utiliser GraalVM
Essayez Java 8 Stream
Essayez d'utiliser jmockit 1.48
Essayez d'utiliser SwiftLint
Essayez d'utiliser Log4j 2.0
Essayez grossièrement Java 9
Essayez d'utiliser Firebase Cloud Functions sur Android (Java)
Essayez d'utiliser la classe de test RestClient de JobScheduler REST-API-Java-
Essayez d'utiliser l'API Cloud Vision de GCP en Java
Essayez d'utiliser Sourcetrail (version macOS) avec du code Java
Essayez d'accéder à l'ensemble de données depuis Java en utilisant JZOS
Essayez la communication en utilisant gRPC sur un serveur Android + Java
Tri à l'aide du comparateur java
Essayez d'utiliser l'API REST de JobScheduler
Essayez d'utiliser la méthode java.lang.Math
Essayez d'utiliser la WhiteBox de PowerMock
Essayez d'implémenter le tamis Eratostenes en utilisant la bibliothèque standard de Java
J'ai essayé de faire fonctionner SQS en utilisant AWS Java SDK
Essayez d'utiliser Talend Part 2
Pratique de grattage avec Java ②
Appelons IBM Watson Assistant 2018-07-10 à partir du SDK Java.
Pratique du grattage avec Java ①
Essayez la classification d'image à l'aide de TensorFlow Lite sur Android (JAVA)
Essayez le hooking global en Java à l'aide de la bibliothèque JNativeHook
Essayez d'utiliser Talend Part 1
Essayez d'utiliser la liste F #
Essayez de créer un environnement de développement Java à l'aide de Docker
Essayez d'utiliser la méthode each_with_index
Essayez la valeur de retour Java
Essayez d'utiliser Spring JDBC
Implémentez Thread en Java et essayez d'utiliser la classe anonyme Lambda
[Java] Essayez de modifier les éléments de la chaîne Json à l'aide de la bibliothèque
Essayez d'utiliser GloVe avec Deeplearning4j
Essayez la connexion DB avec Java
Essayez d'appeler JavaScript en Java
Essayez d'utiliser Cocoa de Ruby
Essayez de développer Spresense avec Java (1)
Essayez le type fonctionnel en Java! ①
Essayez gRPC avec Java, Maven