[Hyperledger Iroha]Python SDKの使い方メモ

#記事の内容
Hyperledger IrohaのPython SDKを使って、
・Assetの作成
・Assetの送信
・ブロック情報の取得
を行ってみます。

#前提
・irohaの公式ガイドに従って環境構築が出来ていること
・Python3が使える環境であること

#参考
Iroha Python Libraryドキュメント
https://iroha.readthedocs.io/en/latest/develop/libraries/python.html

このページのExample CodeはAssetの送信から書かれているので、事前にAssetの作成をしておかないと動きません。
そのコードもこの記事ではPythonを使ってやってみます。

#Assetの作成

~~~ CreateAsset.py
from iroha import Iroha, IrohaCrypto, IrohaGrpc

net = IrohaGrpc('Host IP Address:50051')

iroha = Iroha('admin@test')
admin_priv_key = 'Admin Private Key' # 一行前に指定したアカウントのPrivate Key

# Transactionの作成
create_asset_tx = iroha.transaction(
    [iroha.command(
        'CreateAsset', # Assetの作成 
        asset_name = 'samplecoin',
        domain_id = 'test',
        precision = 10 
    ), iroha.command(
        'AddAssetQuantity', # Assetの初期保有量の設定
        asset_id = 'samplecoin#test',
        amount = '100000000'
    )]
)

# Transactionへ署名
IrohaCrypto.sign_transaction(create_asset_tx, admin_priv_key)

# Transactionの送信
net.send_tx(create_asset_tx)

# 結果の確認
for status in net.tx_status_stream(create_asset_tx):
    print(status)
~~~

このコードでは、「admin@test」アカウントでAssetの作成を行い、「admin@test」アカウントが保有するAssetの量を設定しています。

処理の流れはTransactionの作成→署名→送信→結果の確認という流れになっています。

正常に実行されれば以下の結果になると思います。

~~~
('ENOUGH_SIGNATURES_COLLECTED', 9, 0)
('STATEFUL_VALIDATION_SUCCESS', 3, 0)
('COMMITTED', 5, 0)
~~~

irohaコンテナの「/tmp/block_store」ディレクトリ配下にブロックが追加されています。

~~~
{
  "blockV1": {
    "payload": {
      "transactions": [
        {
          "payload": {
            "reducedPayload": {
              "commands": [
                {
                  "createAsset": {
                    "assetName": "samplecoin",
                    "domainId": "test",
                    "precision": 10
                  }
                },
                {
                  "addAssetQuantity": {
                    "assetId": "samplecoin#test",
                    "amount": "100000000"
                  }
                }
              ],
              "creatorAccountId": "admin@test",
              "createdTime": "1578361629026",
              "quorum": 1
            }
          },
          "signatures": [
            {
              "publicKey": "313a07e6384776ed95447710d15e59148473ccfc052a681317a72a69f2a49910",
              "signature": "a414d71e6b2022a81d375d2a367827800a072b465ace7e919c23336b572e5c7511854c2abcff08736d6a687e261a21e1121180f561b8e18729a0fdeaffbbc401"
            }
          ]
        }
      ],
      "height": "2",
      "prevBlockHash": "9debdb1a70db2cede2222427b849f6bf7ab20845da7c3db1837c0df25ec1c61a",
      "createdTime": "1578361629022"
    },
    "signatures": [
      {
        "publicKey": "bddd58404d1315e0eb27902c5d7c8eb0602c16238f005773df406bc191308929",
        "signature": "20a900f3587ccdadcb128a6d597cd0406e90882cbc9b12017c938d4f0c4a4cd6bd6cd09b674289c5146f1026bfdfc33a922a6cb925429db29e49605ffc392c09"
      }
    ]
  }
}
~~~

# Assetの送信
ここのコードは上述の参考に記載した公式ドキュメントに書かれてあるコードのままです。

~~~ TransferAsset.py
from iroha import Iroha, IrohaCrypto, IrohaGrpc

net = IrohaGrpc('Host IP Address:50051')

iroha = Iroha('admin@test')
admin_priv_key = 'Admin Private Key' # 一行前に指定したアカウントのPrivate Key

# Transactionの作成
transfer_asset_tx = iroha.transaction(
 [iroha.command(
     'TransferAsset',
     src_account_id='admin@test',
     dest_account_id='test@test',
     asset_id='samplecoin#test',
     description='test',
     amount='10000'
 )]
)

# Transactionの署名
IrohaCrypto.sign_transaction(transfer_asset_tx, admin_priv_key)

# Transactionの送信
net.send_tx(transfer_asset_tx)

# 結果の確認
for status in net.tx_status_stream(transfer_asset_tx):
    print(status)
~~~

送信元アカウント（src_account_id）、送信先アカウント（dest_account_id）、アセットID（asset_name # domain_id）を環境に合わせて修正します。

正常に実行されれば以下の結果になると思います。

~~~
('ENOUGH_SIGNATURES_COLLECTED', 9, 0)
('STATEFUL_VALIDATION_SUCCESS', 3, 0)
('COMMITTED', 5, 0)
~~~

irohaコンテナの「/tmp/block_store」ディレクトリ配下にブロックが追加されています。

~~~
{
  "blockV1": {
    "payload": {
      "transactions": [
        {
          "payload": {
            "reducedPayload": {
              "commands": [
                {
                  "transferAsset": {
                    "srcAccountId": "admin@test",
                    "destAccountId": "test@test",
                    "assetId": "samplecoin#test",
                    "description": "test",
                    "amount": "10000"
                  }
                }
              ],
              "creatorAccountId": "admin@test",
              "createdTime": "1578362174344",
              "quorum": 1
            }
          },
          "signatures": [
            {
              "publicKey": "313a07e6384776ed95447710d15e59148473ccfc052a681317a72a69f2a49910",
              "signature": "7bf5bec8110cbe618b05cd3bf8b69d0eb1e6e2eb4f3efcc41d0573b8e3638bc220b49c251c0f3238bb753d85d4b7a3e032f420f5c0e4f0e8fe18a72c9ec0800e"
            }
          ]
        }
      ],
      "height": "3",
      "prevBlockHash": "ac0f2ad5cdbea3c6cd8eb0e4e1b7679b595a9c26ddda1acc75a5ff031abf9c91",
      "createdTime": "1578362175915"
    },
    "signatures": [
      {
        "publicKey": "bddd58404d1315e0eb27902c5d7c8eb0602c16238f005773df406bc191308929",
        "signature": "507a96cbb0ac99fada62cf36097204fc166a4635b70e68b9c87d007300ca0f7b231f4787cc9fe8751cc640a9cf2b7c161cc0bedb31e606363d4c18256268660f"
      }
    ]
  }
}
~~~


# Block情報の取得

Block情報の取得はこれまでと少しコードが変わります。

~~~ GetBlock.py
from iroha import Iroha, IrohaCrypto, IrohaGrpc

net = IrohaGrpc('Host IP Address:50051')

iroha = Iroha('admin@test')
admin_priv_key = 'Admin Private Key' # 一行前に指定したアカウントのPrivate Key

# Queryの作成
get_block_query = iroha.query(
        'GetBlock',
        height = 3  # 取得するBlock Height（番号）を指定する
)

# Queryへ署名
IrohaCrypto.sign_query(get_block_query, admin_priv_key)

# Queryの送信
response = net.send_query(get_block_query)

# Responseの出力
print(response)
~~~

やってることはQueryの作成→署名→送信→結果の確認なのでTransactionの送信と変わりません。
少し使うFunctionが変わってきます。

実行結果

~~~
query_hash: "eb7035cdde49e26f2271b7991933a5eb8321f1a3176014a73f53a1c86d91b8bc"
block_response {
  block {
    block_v1 {
      payload {
        transactions {
          payload {
            reduced_payload {
              commands {
                transfer_asset {
                  src_account_id: "admin@test"
                  dest_account_id: "test@test"
                  asset_id: "samplecoin#test"
                  description: "test"
                  amount: "10000"
                }
              }
              creator_account_id: "admin@test"
              created_time: 1578362174344
              quorum: 1
            }
          }
          signatures {
            public_key: "313a07e6384776ed95447710d15e59148473ccfc052a681317a72a69f2a49910"
            signature: "7bf5bec8110cbe618b05cd3bf8b69d0eb1e6e2eb4f3efcc41d0573b8e3638bc220b49c251c0f3238bb753d85d4b7a3e032f420f5c0e4f0e8fe18a72c9ec0800e"
          }
        }
        height: 3
        prev_block_hash: "ac0f2ad5cdbea3c6cd8eb0e4e1b7679b595a9c26ddda1acc75a5ff031abf9c91"
        created_time: 1578362175915
      }
      signatures {
        public_key: "bddd58404d1315e0eb27902c5d7c8eb0602c16238f005773df406bc191308929"
        signature: "507a96cbb0ac99fada62cf36097204fc166a4635b70e68b9c87d007300ca0f7b231f4787cc9fe8751cc640a9cf2b7c161cc0bedb31e606363d4c18256268660f"
      }
    }
  }
}
~~~

Block Height（番号）が3の情報を取得できました。

ドキュメントを読んでる限りだと、最新のBlockを取得する、最新のBlock Height（番号）を取得するというライブラリは用意されてなさそうです。
上記のコードでqueryの「height」を指定すると必須項目未入力でエラーになりました。


# 感想
IrohaのJava SDKを使ってみるという記事も書きましたが、Python初心者の私でも断然Pythonの方が楽に使えました。
コマンドの組み立て方も公式ドキュメントのAPIページに詳細が書かれているので割と分かり易いです。

公式ドキュメント
https://iroha.readthedocs.io/en/latest/develop/api.html

[Hyperledger IrohaのJava SDKでブロック情報を取得する](https://qiita.com/bc_yuuuuuki/items/700cb2853c2c05c9bd9a)