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

第15回BBc-1プログラミングガイド ~アセットの記述

前回までは、トランザクションの作成、署名検証、検索、合意についてのBBc-1プログラミングの概要をfile_proof.pyに沿って説明しました。しかし、アセット、つまりBBc-1に登録したい資産情報そのものについては、詳しく説明していなかったので、今回はアセットの取り扱いについて説明します。

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

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

アセットの記述

BBc-1では、文字列、バイナリデータおよびファイルをアセットと見なすことができます。file_proof.pyでは、⁠Owner is 〇〇⁠という文字列および対象となるファイルをアセットとしました(file_proof.pyの298行目など⁠⁠。つまり、人間が読める形式で所有者名を表記したものとファイル本体の組を「資産」見なしているのです。アセットの考え方、記述の仕方はアプリケーションで自由に決められます。例えば、json文字列でアセットを表記すれば、トークンのような量も簡単に表現できますし、センサーデータのようなバイナリ情報そのものをアセットにすることも可能です。

では、具体的なアセットの記述方法を見ていきましょう。アセットはBBcAssetクラスのオブジェクトとして記述します。BBcAssetオブジェクトは、次のような情報を含みます。

表1 アセットの記述方法
変数名説明
asset_idBBcAssetオブジェクトの識別子(アセットの識別子)
user_idこのアセットの所有者の識別子
nonceランダムな値(オブジェクト作成時に生成される)
asset_file_size外部ファイルのファイルサイズ(バイト)
asset_file_digest外部ファイルのSHA256ダイジェスト
asset_body_sizeこのオブジェクト(asset_body)に格納する情報のサイズ(バイト)
asset_bodyアセット情報本体(文字列、バイナリ)

まず、asset_idとは、このBBcAssetオブジェクト全体(asset_idを含まず)のSHA256ダイジェスト値で、アセット自体の識別子です。トランザクションの識別子を計算する際に同時に自動で計算されます。asset_idは検索キーとすることができ、トランザクションを取得できます。そして、asset_bodyがアセットの本体で、文字列やバイナリデータを格納できます。また、asset_bodyに格納するにはデータサイズが大きすぎる、またはトランザクションとは分離してデータファイルを持っておきたい場合には、ファイルのSHA256ダイジェスト値をasset_file_digestに保存します。これによって、外部ファイルをそのBBcAssetオブジェクトと紐付けることができます。外部ファイルとして分離してしまうと、どのファイルが紐付いているかがわからなくなってしまうかもしれないので、bbc_coreではasset_id(16進文字列表現)をそのファイル名として管理しています。ご興味のある方は、bbc_core.pyが起動しているディレクトリに作成される.bbc1/というワーキングディレクトリ内を探してみてください。なお、bbc_coreでファイルを管理させずに、アプリケーション自体が独自に外部ファイルを管理することも可能です。

アセットは資産情報であり、トランザクションはアセット本体にさまざまな付随情報(他のトランザクションやアセットとの関係や署名)を付加したものです。したがって、BBcAssetオブジェクトは、BBcTransactionオブジェクトの中に格納されるのですが、直接格納されるわけではありません。実際には、BBcRelationまたはBBcEventオブジェクトの中に格納されます。その理由は、第5回第6回でご紹介した、アカウント型(ステート型)またはUTXO型の両方の形式をサポートしているためです。アセットをアカウント型の形式で表現したい場合はBBcRelationオブジェクトを、UTXO型の形式で表現したい場合はBBcEventオブジェクトを用います。ただ、アセットの中身は両方ともBBcAssetオブジェクトとして記述します。

アセットとトランザクションの作成

BBcTransactionオブジェクトの構成概要は、第4回図1でも示しました。

第4回 図1 トランザクションのデータ構造(再掲)
第4回 図1 トランザクションのデータ構造(再掲)

1つのトランザクションにはeventリストおよびrelationリストが含まれ、それぞれのリストの中には0個以上のBBcEventオブジェクトまたはBBcRelationオブジェクトが格納されます。そしてBBcEvent・BBcRelationオブジェクトはBBcAssetオブジェクトを1つ含みます。つまり、BBcEventおよびBBcRelationオブジェクトの個数分だけBBcAssetオブジェクトを作成することになります。実際には、⁠登録したいBBcAssetオブジェクトの数だけBBcEvent・BBcRelationオブジェクトという器を用意する」と説明したほうが正しいのですが、プログラミングはどのような順番でも可能です。ユーティリティとして先に器となるBBcEvent・BBcRelationオブジェクトなどを作成する関数が用意されています。

では、具体的に見ていきましょう。

file_proof.py297~301行目(store_proc関数内)
store_transaction = bbclib.make_transaction(relation_num=1, witness=True)
user_info = "Owner is %s" % user_name
bbclib.add_relation_asset(store_transaction, relation_idx=0, asset_group_id=asset_group_id,
                          user_id=user_id, asset_body=user_info, asset_file=data)
store_transaction.witness.add_witness(user_id)

これは第11回でも説明した関数の一部です。最初のbbclib.make_transaction関数でBBcRelationオブジェクトを1つ含むBBcTransactionオブジェクトを生成します。

user_infoは、アセット本体の文字列情報で、⁠Owner is 〇〇⁠という文字列を設定します。

そしてBBcAssetオブジェクトの生成とBBcRelationオブジェクトへの格納をbbclib.add_relation_asset関数というユーティリティ関数で実施します。第1引数は対象となるBBcTransactionオブジェクトを、第2引数はrelationリストの何番目の要素か(relation_idx=0:0が1番目を表します)を指定します。asset_group_idはBBcRelationオブジェクトにセットされる情報で、格納するアセットがどんな種類のアセットであるかを識別するための情報です(32バイトのバイナリ列です⁠⁠。そして、user_id以降がBBcAssetオブジェクトに格納される情報で、user_idが所有者の識別子、asset_bodyがアセット本体(ここでは、⁠Owner is 〇〇⁠という文字列⁠⁠、asset_fileが外部ファイルとして分離管理するファイルコンテンツ(ファイルの中身)です。なお、BBcAssetオブジェクトにasset_fileをセットすると、自動的にasset_file_sizeの値をセットし、またSHA256ダイジェストを計算してそのダイジェスト値をasset_file_digestにセットしてくれます。外部ファイルが不要な場合は、asset_file=という部分を省略します。同じくasset_bodyが不要な場合もasset_body=という部分を省略します。

このように、ユーティリティ関数を使うと、アセットの登録はとても簡単です。ユーティリティ関数は、本来1つずつオブジェクトを作って格納していく作業をまとめて実施しているだけですので、中でどのような処理をしているかを知りたい方は、以下のファイルを参照ください。

  • bbc1/core/libs/bbclib_utils.py
  • tests/test_bbclib.py

アセットの参照

アセットの参照方法は、BBcAssetオブジェクトのasset_bodyにアクセスする、および手に入れたファイルのSHA256ダイジェストを自分で計算して、BBcAssetオブジェクト内のasset_file_digestおよびasset_file_sizeと比較するだけです。一致していたら、確かにそのファイルはアセットとして登録されたファイルと一致しているといえます。具体的に見ていきましょう。

file_proof.py247~265行目(pick_valid_transaction_info関数内)
def pick_valid_transaction_info(received_data=None, bbc_app_client=None):
    transaction, fmt_type = bbclib.deserialize(received_data[KeyType.transaction_data])
    asset_files = received_data[KeyType.all_asset_files]
    asset_id = transaction.relations[0].asset.asset_id
    if asset_id not in asset_files:
        print("**** No valid file is received...")
        print(received_data)
        bbc_app_client.sendback_denial_of_sign(received_data[KeyType.source_user_id],
                                               transaction.transaction_id,
                                               "No valid file is received.")
        sys.exit(1)

    file_to_obtain = asset_files[asset_id]
    file_digest = hashlib.sha256(file_to_obtain).digest()
    print("--------------------------")
    print("File digest written in the transaction data:  ",
          binascii.b2a_hex(transaction.relations[0].asset.asset_file_digest).decode())
    print("File digest calculated from the received file:", binascii.b2a_hex(file_digest).decode())
    print("--------------------------")

この関数は所有権移転の処理で受信側のユーザで実行される関数です。はじめに受け取ったデータ(received_data[KeyType.transaction_data])をデシリアライズ(deserialize)してBBcTransactionオブジェクトの形に復元します(transactionです⁠⁠。またファイル本体も受け取っているので、asset_filesというdictionary型のオブジェクトに保存します。ここでは、{ファイル名: ファイルデータ}という形式で、ファイル名はasset_idを16進文字列で表記したものです。

その後、受け取ったファイル(file_to_obtain)のダイジェストを計算して、file_digestに代入しています。本来は比較すべきなのですが、比較処理の代わりに単に両方のダイジェスト値を表示するだけです(261~265行目⁠⁠。transaction.relations[0].asset.asset_file_digestのようにすれば、BBcAssetオブジェクトのasset_file_digestを取得できます(263行目⁠⁠。同じようにtransaction.relations[0].asset.asset_bodyと書き加えれば、asset_bodyも取得できます。なお、transaction.relations[0]という部分が、トランザクションのrelationリストの1番目のBBcRelationオブジェクトを表し、さらにtransaction.relations[0].assetでBBcAssetオブジェクトを指しています。

まとめ

今回は、アセットの記述方法についてfile_proof.pyに沿ってBBc-1プログラミングの概要を説明しました。アセットには文字列、バイナリデータおよび外部に分離したファイルのSHA256ダイジェストを設定することができますので、アプリケーションに応じて自由なアセットを定義することができます。

今回でプログラミングに関する解説は終わりです。次回は、BBc-1の今後の技術的な展望を紹介する予定です。

おすすめ記事

記事・ニュース一覧