ブロックチェーンの課題と可能性~BBc-1(Beyond Blockchain One)から学ぶブロックチェーン開発

第12回BBc-1プログラミングガイド ~トランザクション取得

前回は、file_proof.pyに沿ってBBc-1プログラミングの概要を説明しました。説明したfile_proof.pyの処理の流れは、⁠ドメイン作成」⁠鍵生成」⁠トランザクション登録」という3つでした。今回からは、トランザクション登録の中で少しだけ触れた「トランザクション取得」⁠トランザクション検証」および「トランザクション合意」の方法について解説します。引き続きfile_proof.pyのソースコードを用いて説明しますので、お手元にご用意ください。

なお、file_proof.pyのプログラムは、下記URLから確認いただけますが、bbc1リポジトリをgit cloneしていただけば、examples/file_proof/ディレクトリの中に格納されています。

また、BBc-1のアプリケーションプログラミングに関するドキュメント群につきましては、第11回冒頭リード文にまとめていますので、ご参考ください。

トランザクションの取得

coreノードに登録されているトランザクションを取得するための関数が、3つ用意されています。以下にその概要をまとめます。

単一トランザクションの取得
  • 関数名:search_transaction
  • 引数:トランザクション識別子

トランザクション識別子に対応するトランザクションデータを取得します。取得したデータはバイナリデータなので、deserialize関数を用いてBBcTransactionオブジェクトに変換して利用します。また、アセットとしてファイルを同時に登録していた場合はそのファイルコンテンツも取得します。

複数条件指定によるトランザクションの取得
  • 関数名:search_transaction_with_condition
  • 引数:アセットグループ識別子、ユーザ識別子、アセット識別子、検索方向、上限取得数

トランザクション内のBBcEventやBBcRelationおよびBBcAssetオブジェクトに含まれているアセットグループ識別子、ユーザ識別子、アセット識別子を条件として、合致するトランザクション群を取得します。アセットグループ識別子、ユーザ識別子、アセット識別子はいずれか1つ以上指定されていればよく、複数指定した場合はAND条件として検索されます。検索方向を0(デフォルト値)に指定すると新しく登録されたものから順番に検索し、1に指定すると1番古く登録されたものから順番に検索します。また、アセットとしてファイルを同時に登録していた場合はそのファイルコンテンツ群も取得します。

トランザクションツリーの取得
  • 関数名:traverse_transactions
  • 引数:トランザクション識別子、アセットグループ識別子、ユーザ識別子、検索方向、取得上限階層数

トランザクション内のBBcReferenceやBBcPointerオブジェクトによって他のトランザクションとの関係性がある場合に、起点となるトランザクションから指定された階層数まで関連するすべてのトランザクション群を取得します。アセットグループ識別子、ユーザ識別子が指定された場合は、その条件に合致するもののみを検索対象とします。検索方向を1(デフォルト値)に指定すると起点となるトランザクションから古い方向に検索し、0に指定すると起点から新しい方向に検索します。得られる結果は、階層ごとにトランザクションデータがリストになっています。traverse_transactionsで得られる検索結果のイメージを図1図2に示します。四角はトランザクションを示し、A〜Pはそれぞれトランザクション識別子を表しており、図中の矢印はBBcReferenceやBBcPointerオブジェクトで過去のトランザクションを参照していることを示しています。なお、他の関数同様、アセットとしてファイルを同時に登録していた場合はそのファイルコンテンツ群も取得します。

図1 Gを起点に過去に向かってトランザクションツリーを取得する(検索方向=1、階層数=2)
図1 Gを起点に過去に向かってトランザクションツリーを取得する(検索方
図2 Gを起点に未来に向かってトランザクションツリーを取得する(検索方向=0、階層数=2)
図2 Gを起点に未来に向かってトランザクションツリーを取得する(検索方

実際には検索結果はそれぞれバイナリデータになっていますので、1つずつdeserialize関数でBBcTransactionオブジェクトに変換して利用します。

ここで紹介した検索関数の他に、count_transactions関数もあり、検索条件に合致するトランザクション数のみを返答します(引数には、アセットグループ識別子、ユーザ識別子、アセット識別子を指定します⁠⁠。

トランザクション取得関数の具体例

file_proof.pyではsearch_transaction関数とsearch_transaction_with_condition関数の2つを利用しています。具体例を見てみましょう。

file_proof.py 176~181行目(send_signreq関数内)
bbc_app_client.search_transaction(ref_txid)
response_data = bbc_app_client.callback.synchronize()
if response_data[KeyType.status] < ESUCCESS:
    print("ERROR: ", response_data[KeyType.reason].decode())
    sys.exit(0)
prev_tx, fmt_type = bbclib.deserialize(response_data[KeyType.transaction_data])

search_transaction関数は第11回の中でも説明しました。もう一度おさらいすると、BBcAppClientクラスのオブジェクトを通してcoreプロセスと通信し、トランザクションの検索や登録などの機能を利用します。bbc_app_clientはそのBBcAppClientオブジェクトです。search_transaction(ref_txid)によってref_txidというトランザクション識別子を持つトランザクションを取得します。応答メッセージresponse_data内のresponse_data[KeyType.transaction_data]に検索結果のトランザクションのバイナリデータが格納されています。このバイナリデータをbbclib.deserialize関数に渡すことで1番目の戻り値としてBBcTransactionオブジェクト(prev_tx)を取得できます。また、2番目の戻り値fmt_typeはバイナリデータがどのようなフォーマットだったかを示していますが、通常はデシリアライズした後に利用することはありません。

file_proof.py 346~360行目(get_file関数内)
bbc_app_client = setup_bbc_client()
ret = bbc_app_client.search_transaction_with_condition(asset_group_id=asset_group_id, asset_id=fileinfo["asset_id"])
assert ret
response_data = bbc_app_client.callback.synchronize()
if response_data[KeyType.status] < ESUCCESS:
    print("ERROR: ", response_data[KeyType.reason].decode())
    sys.exit(0)

get_transaction, fmt_type = bbclib.deserialize(response_data[KeyType.transactions][0])
if KeyType.all_asset_files in response_data:
    asset_file_dict = response_data[KeyType.all_asset_files]
    asset_id = get_transaction.relations[0].asset.asset_id
    data = asset_file_dict[asset_id]
else:
    data = get_transaction.relations[0].asset.asset_body

search_transaction_with_condition関数で、アセットグループ識別子とアセット識別子を指定しています。この2つの識別子をAND条件として、これらを含むトランザクションを取得します。なお、アセット識別子が他のアセットと重複することはめったにないため、実際にはアセットグループ識別子を指定しなくても同じ結果が得られますが、file_proof.pyではアプリケーションの目的を明確にするために、あえて明示しています。

応答メッセージresponse_data内のresponse_data[KeyType.transactions]に検索結果であるトランザクションのバイナリデータ群がリスト形式で格納されています。この例では、トランザクションは1つしか含まれないので、response_data[KeyType.transactions][0]]を指定することで1番目の要素を取り出しています。ここでは、search_transaction関数と同様に、bbclib.deserialize関数に渡して、BBcTransactionオブジェクトに変換しています。さらに、ファイルコンテンツがある場合は、response_data[KeyType.all_asset_files]にファイルが格納されています。response_data[KeyType.all_asset_files]はdictionary型オブジェクトなので、ファイルを取り出す場合には、data = asset_file_dict[asset_id]のようにアセット識別子をキーに指定します。

まとめ

今回は、トランザクションを取得するためのBBc-1プログラミング方法について、file_proof.pyに沿って概要を説明しました。トランザクションに付随して登録されたファイルも一緒に取得することができます。BBc-1では、単一のトランザクションの取得、条件指定によるトランザクション群の取得、トランザクションツリーの取得という3種類の検索方法が提供されています。

次回はトランザクションの検証方法について、また次々回は2者間での合意の方法について説明する予定です。

おすすめ記事

記事・ニュース一覧