HyperLeDger Fabric智能合约与私人数据在VSCODE中起作用,但在外部应用中不起作用。如何将数据写入多个隐式集合?

发布于 2025-02-05 20:55:30 字数 6192 浏览 1 评论 0 原文

摘要:外部应用程序可以提交一项交易,该交易将其写入单个隐式私人集合,但在写作2个隐式集合时失败。使用VSCODE区块链扩展而不是外部应用程序时,一切正常。

细节: 我使用VSCODE区块链扩展名(v2.0.8)时,它会安装Microfab版本0.0.11。 我正在使用使用2-ORG模板在VSCODE扩展中创建的2-ORG网络。 我有一份智能合约,将数据写入2个隐式私人收藏(对于org1和org2)。

这是智能合约的相关部分(Typescript):

    @Transaction()
    public async createMyPrivateAsset(ctx: Context, myPrivateAssetId: string): Promise<void> {
        const exists: boolean = await this.myPrivateAssetExists(ctx, myPrivateAssetId);
        if (exists) {
            throw new Error(`The asset my private asset ${myPrivateAssetId} already exists`);
        }

        const privateAsset: MyPrivateAsset = new MyPrivateAsset();

        const transientData: Map<string, Uint8Array> = ctx.stub.getTransient();
        if (transientData.size === 0 || !transientData.has('privateValue')) {
            throw new Error('The privateValue key was not specified in transient data. Please try again.');
        }
        privateAsset.privateValue = transientData.get('privateValue').toString();

        const collectionName: string = await getCollectionName(ctx, ctx.clientIdentity.getMSPID());
        await ctx.stub.putPrivateData(collectionName, myPrivateAssetId, Buffer.from(JSON.stringify(privateAsset)));
    }

    @Transaction()
    public async createMyPrivateAssetMultiple(ctx: Context, myPrivateAssetId: string): Promise<void> {
        const exists: boolean = await this.myPrivateAssetExists(ctx, myPrivateAssetId);
        if (exists) {
            throw new Error(`The asset my private asset ${myPrivateAssetId} already exists`);
        }

        const privateAsset: MyPrivateAsset = new MyPrivateAsset();

        const transientData: Map<string, Uint8Array> = ctx.stub.getTransient();
        if (transientData.size === 0 || !transientData.has('privateValue')) {
            throw new Error('The privateValue key was not specified in transient data. Please try again.');
        }
        privateAsset.privateValue = transientData.get('privateValue').toString();

        for (const mspid of ['Org1MSP', 'Org2MSP']) {
            var collectionName: string = await getCollectionName(ctx, mspid);
            await ctx.stub.putPrivateData(collectionName, myPrivateAssetId, Buffer.from(JSON.stringify(privateAsset)));
        }
    }

    @Transaction(false)
    @Returns('MyPrivateAsset')
    public async readMyPrivateAsset(ctx: Context, myPrivateAssetId: string): Promise<string> {
        const exists: boolean = await this.myPrivateAssetExists(ctx, myPrivateAssetId);
        if (!exists) {
            throw new Error(`The asset my private asset ${myPrivateAssetId} does not exist`);
        }

        let privateDataString: string;

        const collectionName: string = await getCollectionName(ctx, ctx.clientIdentity.getMSPID());
        const privateData: Uint8Array = await ctx.stub.getPrivateData(collectionName, myPrivateAssetId);

        privateDataString = JSON.parse(privateData.toString());
        return privateDataString;
    }

createmyprivateasset 写信给单个隐式集合:一切正常。 createMyPrivateAssetMultiple 写信给2个隐式集合:外部应用中的失败。

当我使用VSCODE交易视图提交交易时,这两项交易都可以很好地工作。 对于 createMyPrivateAssetMultiple ,我使用org1网关提交,然后使用org1网关调用 readmyprivateasset ,还使用org2网关,私有数据正确返回。

现在,当我使用外部应用时,交易 createMyPrivateAsset 有效,但 createMyPrivateAssetMultiple 却没有。 这是应用程序的相关部分(Typescript):

    // connection
    const gateway: Gateway = new Gateway();
    const connectionProfilePath: string = path.resolve(__dirname, '..', connectionFile);
    const connectionProfile = JSON.parse(fs.readFileSync(connectionProfilePath, 'utf8'));
    const connectionOptions: GatewayOptions = { wallet, identity: identity, discovery: { enabled: true, asLocalhost: true } };
    await gateway.connect(connectionProfile, connectionOptions);

    // Get the network (channel) our contract is deployed to.
    const network = await gateway.getNetwork('mychannel');

    // Get the contract from the network.
    const contract = network.getContract('private-contract');

这是CreateMyPrivateAsset的交易提交

      let transientData = {
        'privateValue': Buffer.from(`Private value for asset ${assetId}`)
      };
      const trans:Transaction = contract.createTransaction('createMyPrivateAsset');
      const buffer: Buffer = await trans.setTransient(transientData).submit(assetId);

此应用程序在应用程序中效果很好。 createMyPrivateAssetMultiple的代码

      let transientData = {
        'privateValue': Buffer.from(`Private value for asset ${assetId}`)
      };
      const trans:Transaction = contract.createTransaction('createMyPrivateAssetMultiple');
      const buffer: Buffer = await trans.setTransient(transientData).submit(assetId);

这是该交易的

2022-06-07T13:21:50.727Z - warn: [TransactionEventHandler]: strategyFail: commit failure for transaction "4e9921b590a361ae01bba673e1d3d204d106522780c820055cec0345e1e67e6f": TransactionError: Commit of transaction 4e9921b590a361ae01bba673e1d3d204d106522780c820055cec0345e1e67e6f failed on peer org1peer-api.127-0-0-1.nip.io:8084 with status ENDORSEMENT_POLICY_FAILURE

,该应用程序抛出此(使用org1网关): Microfab Docker容器日志日志包括以下

> WARN 0ff Failed fetching private data from remote peers for dig2src:[map[{b16526e4cd2ac3f431103cda23a6f64adc12acab0550eff18c1f25f1cc0d8bc1 private-contract _implicit_org_Org2MSP 6 0}:[]]], err: Empty membership channel=mychannel
...
[        org2peer] 2022-06-07 13:22:50.794 UTC [gossip.privdata] RetrievePvtdata -> WARN 220 Could not fetch all 1 eligible collection private write sets for block [20] (0 from local cache, 0 from transient store, 0 from other peers). Will commit block with missing private write sets:[txID: 4e9921b590a361ae01bba673e1d3d204d106522780c820055cec0345e1e67e6f, seq: 0, namespace: private-contract, collection: _implicit_org_Org2MSP, hash: 3e0f263d2edcfaf29df346504a40fdbadce0807938f204fe3e6bf753b751d9a3

内容:也,package.json

  "dependencies": {
    "fabric-network": "~2.1.0"
  },

Summary: An external app can submit a transaction that writes to a single implicit private collection but fails when writing to 2 implicit collections. Everything works OK when using the vscode blockchain extension instead of the external app.

Details:
I am using the vscode blockchain extension (v2.0.8) When used, it installs microfab version 0.0.11.
I am using a 2-org network created in the vscode extension using the 2-org template.
I have a Smart Contract that writes data to 2 implicit private collections (for Org1 and Org2).

Here is the relevant portion of the smart contract (typescript):

    @Transaction()
    public async createMyPrivateAsset(ctx: Context, myPrivateAssetId: string): Promise<void> {
        const exists: boolean = await this.myPrivateAssetExists(ctx, myPrivateAssetId);
        if (exists) {
            throw new Error(`The asset my private asset ${myPrivateAssetId} already exists`);
        }

        const privateAsset: MyPrivateAsset = new MyPrivateAsset();

        const transientData: Map<string, Uint8Array> = ctx.stub.getTransient();
        if (transientData.size === 0 || !transientData.has('privateValue')) {
            throw new Error('The privateValue key was not specified in transient data. Please try again.');
        }
        privateAsset.privateValue = transientData.get('privateValue').toString();

        const collectionName: string = await getCollectionName(ctx, ctx.clientIdentity.getMSPID());
        await ctx.stub.putPrivateData(collectionName, myPrivateAssetId, Buffer.from(JSON.stringify(privateAsset)));
    }

    @Transaction()
    public async createMyPrivateAssetMultiple(ctx: Context, myPrivateAssetId: string): Promise<void> {
        const exists: boolean = await this.myPrivateAssetExists(ctx, myPrivateAssetId);
        if (exists) {
            throw new Error(`The asset my private asset ${myPrivateAssetId} already exists`);
        }

        const privateAsset: MyPrivateAsset = new MyPrivateAsset();

        const transientData: Map<string, Uint8Array> = ctx.stub.getTransient();
        if (transientData.size === 0 || !transientData.has('privateValue')) {
            throw new Error('The privateValue key was not specified in transient data. Please try again.');
        }
        privateAsset.privateValue = transientData.get('privateValue').toString();

        for (const mspid of ['Org1MSP', 'Org2MSP']) {
            var collectionName: string = await getCollectionName(ctx, mspid);
            await ctx.stub.putPrivateData(collectionName, myPrivateAssetId, Buffer.from(JSON.stringify(privateAsset)));
        }
    }

    @Transaction(false)
    @Returns('MyPrivateAsset')
    public async readMyPrivateAsset(ctx: Context, myPrivateAssetId: string): Promise<string> {
        const exists: boolean = await this.myPrivateAssetExists(ctx, myPrivateAssetId);
        if (!exists) {
            throw new Error(`The asset my private asset ${myPrivateAssetId} does not exist`);
        }

        let privateDataString: string;

        const collectionName: string = await getCollectionName(ctx, ctx.clientIdentity.getMSPID());
        const privateData: Uint8Array = await ctx.stub.getPrivateData(collectionName, myPrivateAssetId);

        privateDataString = JSON.parse(privateData.toString());
        return privateDataString;
    }

createMyPrivateAsset writes to a single implicit collection: everything OK.
createMyPrivateAssetMultiple writes to 2 implicit collections: fails in external app.

Both transactions work perfectly when I use the vscode Transaction View to submit transactions.
For createMyPrivateAssetMultiple, I submit using the Org1 gateway and then call readMyPrivateAsset using the Org1 gateway and also using the Org2 gateway and the private data is returned correctly.

Now, when I use an external app, the transaction createMyPrivateAsset works but createMyPrivateAssetMultiple does not.
Here is the relevant portion of the app (typescript):

    // connection
    const gateway: Gateway = new Gateway();
    const connectionProfilePath: string = path.resolve(__dirname, '..', connectionFile);
    const connectionProfile = JSON.parse(fs.readFileSync(connectionProfilePath, 'utf8'));
    const connectionOptions: GatewayOptions = { wallet, identity: identity, discovery: { enabled: true, asLocalhost: true } };
    await gateway.connect(connectionProfile, connectionOptions);

    // Get the network (channel) our contract is deployed to.
    const network = await gateway.getNetwork('mychannel');

    // Get the contract from the network.
    const contract = network.getContract('private-contract');

Here is the transaction submission for createMyPrivateAsset

      let transientData = {
        'privateValue': Buffer.from(`Private value for asset ${assetId}`)
      };
      const trans:Transaction = contract.createTransaction('createMyPrivateAsset');
      const buffer: Buffer = await trans.setTransient(transientData).submit(assetId);

This works fine in the app.
Here is the code for createMyPrivateAssetMultiple

      let transientData = {
        'privateValue': Buffer.from(`Private value for asset ${assetId}`)
      };
      const trans:Transaction = contract.createTransaction('createMyPrivateAssetMultiple');
      const buffer: Buffer = await trans.setTransient(transientData).submit(assetId);

For this transaction, the app throws this (using Org1 gateway):

2022-06-07T13:21:50.727Z - warn: [TransactionEventHandler]: strategyFail: commit failure for transaction "4e9921b590a361ae01bba673e1d3d204d106522780c820055cec0345e1e67e6f": TransactionError: Commit of transaction 4e9921b590a361ae01bba673e1d3d204d106522780c820055cec0345e1e67e6f failed on peer org1peer-api.127-0-0-1.nip.io:8084 with status ENDORSEMENT_POLICY_FAILURE

The microfab docker container log includes this:

> WARN 0ff Failed fetching private data from remote peers for dig2src:[map[{b16526e4cd2ac3f431103cda23a6f64adc12acab0550eff18c1f25f1cc0d8bc1 private-contract _implicit_org_Org2MSP 6 0}:[]]], err: Empty membership channel=mychannel
...
[        org2peer] 2022-06-07 13:22:50.794 UTC [gossip.privdata] RetrievePvtdata -> WARN 220 Could not fetch all 1 eligible collection private write sets for block [20] (0 from local cache, 0 from transient store, 0 from other peers). Will commit block with missing private write sets:[txID: 4e9921b590a361ae01bba673e1d3d204d106522780c820055cec0345e1e67e6f, seq: 0, namespace: private-contract, collection: _implicit_org_Org2MSP, hash: 3e0f263d2edcfaf29df346504a40fdbadce0807938f204fe3e6bf753b751d9a3

Also, package.json includes this:

  "dependencies": {
    "fabric-network": "~2.1.0"
  },

Can anyone shed light on this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

祁梦 2025-02-12 20:55:30

您绝对应该使用 [emagy&nbsp;

我怀疑发生了什么事是VS代码客户端不使用服务发现并向所有网络同行发送建议,而独立客户端应用程序默认情况下使用服务发现,而仅将建议发送给链码认可策略所需的ORG。要考虑到收集认可策略,您需要在提交交易之前向合同对象添加链码兴趣:

https://hyperledger.github.github.io/fabric-sdk-node/release-2.2/module-fabric-network.contrip-network.contract.contract.Contract.Contract.contrim.htmluververyInterest

There is a working example of this in the Fabric samples:

https://github.com/hyperledger/fabric-samples/blob/8ca50df4ffec311e59451c2a7ebe210d9e6f0004/asset-transfer-private-data/application-javascript/app.js# L166-L178

或者您可以:

  1. 在网关连接选项中禁用服务发现。
  2. 明确设置给定交易调用的认可组织:

通常,使用服务发现的方法最好是

最好的方法 。实际上是使用Fabric v2.4+和Fabric Gateway Client API:

https:// hyperledger。 github.io/fabric-gateway/

使用此API,客户(通常)不必担心使用私人数据收集或基于州/基于州/密钥的认可策略时的认可所需的组织。事情只是自动起作用。

You should definitely be using [email protected], not 2.1.x.

I suspect what is happening is the VS Code client is not using service discovery and sending proposals for endorsement to all network peers, whereas the standalone client application is using service discovery by default and only sending proposals to orgs required by the chaincode endorsement policy. To get it to consider the collection endorsement policy you would need to add a chaincode interest to the Contract object before submitting transactions:

https://hyperledger.github.io/fabric-sdk-node/release-2.2/module-fabric-network.Contract.html#addDiscoveryInterest

There is a working example of this in the Fabric samples:

https://github.com/hyperledger/fabric-samples/blob/8ca50df4ffec311e59451c2a7ebe210d9e6f0004/asset-transfer-private-data/application-javascript/app.js#L166-L178

Alternatively you could either:

  1. Disable service discovery in the Gateway connection options.
  2. Explicitly set the endorsing orgs for a given transaction invocation:
    https://hyperledger.github.io/fabric-sdk-node/release-2.2/module-fabric-network.Transaction.html#setEndorsingOrganizations

In general it's much better to be using service discovery so I would not recommend option 1.

The best approach would actually be to use Fabric v2.4+ and the Fabric Gateway client API:

https://hyperledger.github.io/fabric-gateway/

With this API the client (generally) does not need to worry about the organizations required for endorsement when using private data collections or state-/key-based endorsement policies. Things just work automagically.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文