share facebook facebook twitter menu hatena pocket slack

2019.06.25 TUE

Hyperledger Fabricのチェーンコードで`getStateByRange` の仕様が微妙っぽかったので調べてみたら微妙だった

甲斐 甲

WRITTEN BY 甲斐 甲

Hyperledger Fabricのチェーンコードを実装していて気になったのでメモ。

Hyperledger Fabricってなんぞ?という方はこちらをご参考ください。

Amazon Managed BlockchainがリリースされたのでHyperledger Fabricも合わせて情報をまとめてみた – Qiita
https://cloudpack.media/46950

Amazon Managed BlockchainでHyperledger Fabricのブロックチェーンネットワークを構築してみた – Qiita
https://cloudpack.media/46963

getStateByRange メソッドの範囲指定でendKey は取得範囲に入らない

ひとまず再現コード抜粋。TypeScriptで実装しています。

TypeScriptを利用した実装方法については下記をご参考ください。

Hyperledger Fabricのチェーンコード(Node.js)をTypeScriptで実装できるようにしてみた – Qiita
https://cloudpack.media/47504

チェーンコード実装(抜粋)

(略)

  async Invoke(stub: ChaincodeStub): Promise<ChaincodeResponse> {
    let ret = stub.getFunctionAndParameters();
    const {fcn, params} =  stub.getFunctionAndParameters();
    console.info(ret);

    const method = (this as any)[fcn];
    if (!method) {
      throw new Error('Received unknown function ' + ret.fcn + ' invocation');
    }

    try {
      let payload = await method(stub, params);
      return Shim.success(payload);
    } catch (err) {
      return Shim.error(err);
    }
  }

  async queryByRange(stub: ChaincodeStub, args: string[]): Promise<Buffer> {
    if (args.length != 2) {
      throw new Error('Incorrect number of arguments.');
    }

    let startKey = args[0];
    let endKey = args[1];
    let results = [];

    let iterator = await stub.getStateByRange(startKey, endKey);
    while(true) {
      const res = await iterator.next();
      if (res.value && res.value.value.toString()) {
        let item = JSON.parse(res.value.value.toString('utf8'));
        results.push(item);
      }

      if (res.done) {
        await iterator.close();
        return Buffer.from(JSON.stringify(results));
      }
    }
  }
(略)
  • value.value とか気持ち悪いなぁ
  • .toString('utf8')って'utf8'を指定しないと’JSON.parse’ できなくてハマります。

ステートDBには以下のようなデータが保存されている前提です。

ステートDBの中身

[
  {"id":"hoge01","hoge":"hoge"},
  {"id":"hoge02","hoge":"hoge"},
  {"id":"hoge03","hoge":"hoge"}
]

で、チェーンコードのqueryByRangeを実行して情報を取得してみます。
※Fablic CLIで実行、パラメータはいろいろ省略しています。

> docker exec cli peer chaincode query \
  -o $ORDERER -C mychannel -n $cc_name \
  -c '{"function":"queryByRange","Args":["hoge01", "hoge01"]}'

[]

あれ取れない。

> docker exec cli peer chaincode query \
  -o $ORDERER -C mychannel -n $cc_name \
  -c '{"function":"queryByRange","Args":["hoge01", "hoge02"]}'

[{"id":"hoge01","hoge":"hoge"}]

お、まさか。。。

> docker exec cli peer chaincode query \
  -o $ORDERER -C mychannel -n $cc_name \
  -c '{"function":"queryByRange","Args":["hoge01", "hoge03"]}'

[{"id":"hoge01","hoge":"hoge"},{"id":"hoge02","hoge":"hoge"}]

なるほど。endKeyは取得対象外なのね。。。

気になって仕様を確認してみたら確かにそういう仕様でした。

Hyperledger Fabric Node.js Contract and Shim Class: ChaincodeStub
https://fabric-shim.github.io/master/fabric-shim.ChaincodeStub.html

Returns a range iterator over a set of keys in the ledger. The iterator can be used to iterate over all keys between the startKey (inclusive) and endKey (exclusive).

Google翻訳

元帳の一連のキーに対する範囲反復子を返します。 反復子はstartKey(これを含む)とendKey(これを含まない)の間のすべてのキーを反復処理するために使用できます。

endKey(これを含まない)

oh…
そうですか。

キーに数値を含めてインクリメントする場合ならまあ対応は楽ですが、キーにULIDを利用しようとしてたのでこれはちっと面倒な感じです。むむむぅ。

参考

Hyperledger Fabric Node.js Contract and Shim Class: ChaincodeStub
https://fabric-shim.github.io/master/fabric-shim.ChaincodeStub.html

Amazon Managed BlockchainがリリースされたのでHyperledger Fabricも合わせて情報をまとめてみた – Qiita
https://cloudpack.media/46950

Amazon Managed BlockchainでHyperledger Fabricのブロックチェーンネットワークを構築してみた – Qiita
https://cloudpack.media/46963

Hyperledger Fabricのチェーンコード(Node.js)をTypeScriptで実装できるようにしてみた – Qiita
https://cloudpack.media/47504

元記事はこちら

Hyperledger Fabricのチェーンコードで'getStateByRange'の仕様が微妙っぽかったので調べてみたら微妙だった

甲斐 甲

甲斐 甲

2018/7にJOIN。 最近の好みはサーバレスです。なんでもとりあえず試します。

cloudpack

cloudpackは、Amazon EC2やAmazon S3をはじめとするAWSの各種プロダクトを利用する際の、導入・設計から運用保守を含んだフルマネージドのサービスを提供し、バックアップや24時間365日の監視/障害対応、技術的な問い合わせに対するサポートなどを行っております。
AWS上のインフラ構築およびAWSを活用したシステム開発など、案件のご相談はcloudpack.jpよりご連絡ください。