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.
Je me suis référé à ce document pour la procédure. https://iroha.readthedocs.io/ja/latest/getting_started/index.html
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.
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.
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.
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