記事の内容
Hyperledger IrohaのJava SDKを使用してブロック情報を取得するサンプルです。
コードの内容は以下の処理を行っています。
- トランザクションを3件まとめて送信
- ブロックの情報を取得して表示
- ブロックの中からトランザクション情報を取得して表示
環境
- JDK 1.8
- Hyperledger Iroha:1.0.0
サンプルコード
作ったコードです。
public static void main(String[] args) throws Exception{
URI uri = new URI(null,null, "192.168.33.10",50051,null,null,null);
IrohaAPI api = new IrohaAPI(uri);
byte[] pubByte = Hex.decodeHex("313a07e6384776ed95447710d15e59148473ccfc052a681317a72a69f2a49910");
byte[] privByte = Hex.decodeHex("f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70");
KeyPair adminKeyPair = Ed25519Sha3.keyPairFromBytes(privByte, pubByte);
// transfer 100 usd from user_a to user_b
val tx1 = Transaction.builder("admin@test")
.transferAsset("admin@test", "test@test", "odocoin#test", "For pizza", "10")
.sign(adminKeyPair)
.build();
val tx2 = Transaction.builder("admin@test")
.transferAsset("admin@test", "test@test", "odocoin#test", "For sushi", "10")
.sign(adminKeyPair)
.build();
val tx3 = Transaction.builder("admin@test")
.transferAsset("admin@test", "test@test", "odocoin#test", "For hamburger", "10")
.sign(adminKeyPair)
.build();
List<TransactionOuterClass.Transaction> txList = new ArrayList<>();
txList.add(tx1);
txList.add(tx2);
txList.add(tx3);
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();
// 1. トランザクションを3件まとめて送信
api.transactionListSync(txList);
Thread.sleep(10000);
val query = Query.builder("admin@test", 3).getBlock(Long.valueOf("9")).buildSigned(adminKeyPair);
QryResponses.QueryResponse response = api.query(query);
Map<FieldDescriptor, Object> map = response.getAllFields();
// 2. ブロックの情報を取得して表示
for(Map.Entry<Descriptors.FieldDescriptor,Object> entry : map.entrySet()) {
System.out.println("Key:" + entry.getKey() + " Value:" + entry.getValue());
}
// 3. ブロックの中からトランザクション情報を取得して表示
BlockResponse block = response.getBlockResponse();
Payload payload = block.getBlock().getBlockV1().getPayload();
for(int i=0; i < payload.getTransactionsCount(); i++) {
TransactionOuterClass.Transaction tx = payload.getTransactions(i);
ReducedPayload reducePayload = tx.getPayload().getReducedPayload();
System.out.println("/********************* " + (i+1) + "件目 *********************/");
System.out.println("CreatorAccountId :" + reducePayload.getCreatorAccountId());
System.out.println("CreatedTime :" + new Date(reducePayload.getCreatedTime()));
System.out.println("Quorum :" + reducePayload.getQuorum());
System.out.println("CommandCount :" + reducePayload.getCommandsCount());
for(int j=0; j < reducePayload.getCommandsCount(); j++) {
Command command = reducePayload.getCommands(j);
TransferAsset asset = command.getTransferAsset();
System.out.println("SrcAccountId :" + asset.getSrcAccountId());
System.out.println("DestAccountId :" + asset.getDestAccountId());
System.out.println("AssetId :" + asset.getAssetId());
System.out.println("Description :" + asset.getDescription());
System.out.println("Amount :" + asset.getAmount());
}
}
api.close();
}
##1. トランザクションを3件まとめて送信
トランザクション1件だけを送信する場合、「transaction(tx)」、「transactionSync(tx)」がある様です。
違いはブロックに取り込まれるのを待つかどうかです。
ethereumのJavaSDKだと「Async」が付くメソッドはブロックに取り込まれるのを待たずに次に進みます。
IrohaのSDKだと「Sync」が付くメソッドがブロックに取り込まれるのを待たない様です。
現時点でトランザクションをまとめて送信するメソッドは「transactionListSync」しか用意されていないようです。
##2. ブロックの情報を取得して表示
まずはクエリを実行して取得できるQryResponsesの内容を表示してみます。
Key:iroha.protocol.QueryResponse.query_hash Value:429b50118a1d691706408045ea1ac55ed9f4138d10a15450dc70850c7869fe9e
Key:iroha.protocol.QueryResponse.block_response Value:block {
block_v1 {
payload {
transactions {
payload {
reduced_payload {
commands {
transfer_asset {
src_account_id: "admin@test"
dest_account_id: "test@test"
asset_id: "odocoin#test"
description: "For sushi"
amount: "10"
}
}
creator_account_id: "admin@test"
created_time: 1570927096936
quorum: 1
}
}
signatures {
public_key: "313A07E6384776ED95447710D15E59148473CCFC052A681317A72A69F2A49910"
signature: "924FAE8C33A4AFB9B713E443B5C6BBC5B9D26069B71C688112B8BE74DEE40192A096CA6460396D67876A684C1950E0632A4C41B0362D55FEA085706C9B305F0C"
}
}
transactions {
payload {
reduced_payload {
commands {
transfer_asset {
src_account_id: "admin@test"
dest_account_id: "test@test"
asset_id: "odocoin#test"
description: "For pizza"
amount: "10"
}
}
creator_account_id: "admin@test"
created_time: 1570927096854
quorum: 1
}
}
signatures {
public_key: "313A07E6384776ED95447710D15E59148473CCFC052A681317A72A69F2A49910"
signature: "09A3E58AEFF340B2E975049B066B445A14E9F0984D48CEDA8612E4794E51A290A5263AB3C4C3121A4B839CE29262100F349AA08262878A1C53344E1EBCDFD50C"
}
}
transactions {
payload {
reduced_payload {
commands {
transfer_asset {
src_account_id: "admin@test"
dest_account_id: "test@test"
asset_id: "odocoin#test"
description: "For hamburger"
amount: "10"
}
}
creator_account_id: "admin@test"
created_time: 1570927096938
quorum: 1
}
}
signatures {
public_key: "313A07E6384776ED95447710D15E59148473CCFC052A681317A72A69F2A49910"
signature: "1D97980C8A1CDA550CB08E1561127516ABF6A756F4C62A703ACDD1DE91FC3741A7DD4BC5E5995CEC71144622CDA685A1390FBB5C98FBAFB63260CE838F33A80D"
}
}
height: 9
prev_block_hash: "497f75888812ba4cd825322284840051c4ab0c26a1b966839510af86f7aca203"
created_time: 1570927100956
}
signatures {
public_key: "bddd58404d1315e0eb27902c5d7c8eb0602c16238f005773df406bc191308929"
signature: "0eff2986883e19325c33b2b59447e1ece486c981eeb1efcb69c61adf69e77df52228fa9e1ea5ed7aa987c3465e2c055797853e0802dcd6aea6fdf8fa201ce405"
}
}
}
表示された内容はクエリのハッシュ値とブロックの内容が取得出来ました。
この情報だけだと使い勝手が悪いので、個別に情報を取得出来る方法を探しました。
3. ブロックの中からトランザクション情報を取得して表示
ブロックの内容と以下のコードを見比べてみると作りが分かり易くなるかなと思います。
BlockResponse block = response.getBlockResponse();
Payload payload = block.getBlock().getBlockV1().getPayload();
for(int i=0; i < payload.getTransactionsCount(); i++) {
TransactionOuterClass.Transaction tx = payload.getTransactions(i);
ReducedPayload reducePayload = tx.getPayload().getReducedPayload();
responseの中から情報を取得するのですが、ブロックのJSON情報の要素毎にクラスが用意されています。
そのため、Block→Block_v1→Payload→Transactions→Payload→reduced_payload→commandsとデータを取得していくことが可能になります。
サンプルのコードではトランザクションの内容を表示しています。
実行結果は以下のとおりです。
/********************* 1件目 *********************/
CreatorAccountId :admin@test
CreatedTime :Sun Oct 13 09:38:16 JST 2019
Quorum :1
CommandCount :1
SrcAccountId :admin@test
DestAccountId :test@test
AssetId :odocoin#test
Description :For sushi
Amount :10
/********************* 2件目 *********************/
CreatorAccountId :admin@test
CreatedTime :Sun Oct 13 09:38:16 JST 2019
Quorum :1
CommandCount :1
SrcAccountId :admin@test
DestAccountId :test@test
AssetId :odocoin#test
Description :For pizza
Amount :10
/********************* 3件目 *********************/
CreatorAccountId :admin@test
CreatedTime :Sun Oct 13 09:38:16 JST 2019
Quorum :1
CommandCount :1
SrcAccountId :admin@test
DestAccountId :test@test
AssetId :odocoin#test
Description :For hamburger
Amount :10
#感想
トランザクション情報の取得やブロック情報の取得のやり方については個人的にはEthereumのSDKの方が分かり易かったかなという印象を受けました。
本当は最新のブロック情報を取得したかったのですが、取得する方法が分からず、ブロック番号を直接指定するようにしています。
まだまだ、使い方を調べる必要がありそうです。