Hyperledger Fabric Chaincode:函数从Chaincode中调用另一个函数吗?

时间:2019-01-03 06:45:40

标签: hyperledger-fabric hyperledger hyperledger-fabric-sdk-js

我有一个场景,我需要从chaincode函数(例如update)中调用其他函数(例如query)。超级账本结构是否为此提供任何接口。 例如:

   ...
    async query(stub, args) {
    }
    async update(stub, args) {
      if(condition) {
        call query();
      }
    }
    ...

我已经尝试了以下帖子的答案,但是没有用。 how to invoke chaincode function from itself to record sub transactions。 虽然通过使用invokeChaincode(),我可以从另一个链码中调用函数。

谢谢。

邮政编码:

    let Chaincode = class {

    async Init(stub) {
        return shim.success();
    }

    async Invoke(stub) {

        let ret = stub.getFunctionAndParameters();

        console.info(ret);

        let method = this[ret.fcn];

        if (!method) {
            throw new Error('Received unknown function ' + ret.fcn + ' invocation');
        }
        try {
            let payload = await method(stub, ret.params);
            return shim.success(payload);
        } catch (err) {
            return shim.error(err);
        }
    }

    async init(stub, args) {

        if (args.length != 1) {
            throw new Error('Invalid args. Expects no args');
        }
    }

    async query(stub, args) {
        ...
    }

    async dummy(stub, args) {
        return Buffer.from('Hello');
    }


    async update(stub, args) {
    ...
        let resp = await dummy(); // gives error
        //let resp = await stub.invokeChaincode('cc2', ['dummy'] );  // working
        console.log(resp)
    ...
    }    
};
shim.start(new Chaincode());

4 个答案:

答案 0 :(得分:1)

更新:如@ kartik-chauhan在his answer中所述,如果您使用的是fabric-contract-api,则此方法很有用。如果您使用的是fabric-shim,请按照他的回答。

对于OP来说可能有点晚,但是对于其他感兴趣的人,您可以使用this.<another_function>从相同链码的函数中调用另一个函数。

我们一直将IBM Blockchain Platform extension用于VSCode,它具有一种向导,可以在GO,JavaScript和打字稿中生成链码。以下是为javascript生成的链码的摘录,您可以在其中观察如何通过this.myAssetExists从函数createMyAsset调用myAssetExists函数:

const { Contract } = require('fabric-contract-api');

class MyAssetContract extends Contract {

    async myAssetExists(ctx, myAssetId) {
        const buffer = await ctx.stub.getState(myAssetId);
        return (!!buffer && buffer.length > 0);
    }

    async createMyAsset(ctx, myAssetId, value) {
        const exists = await this.myAssetExists(ctx, myAssetId);
        if (exists) {
            throw new Error(`The my asset ${myAssetId} already exists`);
        }
        const asset = { value };
        const buffer = Buffer.from(JSON.stringify(asset));
        await ctx.stub.putState(myAssetId, buffer);
    }
...

答案 1 :(得分:0)

作为一种替代方法,我将在两个通道(例如ch1)上安装并实例化具有两个名称(例如cc1和cc2)的相同链码。然后我正在使用:

 invokeChaicode('cc2', ['function', 'arg1', arg2]);

来自链码1(cc1)。

但是问题是我需要在同一频道上使用不同的名称两次安装并实例化相同的链码。

欢迎其他任何见识。

答案 2 :(得分:0)

Sometimes we should think it more simple.Well, the answer is: call it directly. For example: we got two functions A and B

func (s *SmartContract) A(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {}
func (s *SmartContract) B(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {}

if we want to call function A within function B,just do it as

func (s *SmartContract) B(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {

 s.A(APIstub,args)

}

答案 3 :(得分:0)

@jama对问题的回答是正确的。但是,它特定于fabric-contract-api。对于使用fabric-shim包的人,可以通过在要调用的方法中传递this来实现相同的目的。例如

async Invoke(stub) {
    console.info('Transaction ID: ' + stub.getTxID());
    console.info(util.format('Args: %j', stub.getArgs()));

    let ret = stub.getFunctionAndParameters();
    console.info(ret);

    let method = this[ret.fcn];
    if (!method) {
        console.log('no function of name:' + ret.fcn + ' found');
        throw new Error('Received unknown function ' + ret.fcn + ' invocation');
    }

    try {
        let payload = await method(stub, ret.params, this);
        return shim.success(payload);
    } catch (err) {
        console.log(err);
        return shim.error(err);
    }
}

仅需在this中传递await method()即可将当前类的上下文提供给所调用的方法。

必须从内部调用另一种方法的方法必须接受this作为参数之一,例如

async getMarblesByRange(stub, args, thisClass) {
    if (args.length < 2) {
      throw new Error('Incorrect number of arguments. Expecting 2');
    }

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

    let resultsIterator = await stub.getStateByRange(startKey, endKey);
    let method = thisClass['getAllResults'];
    let results = await method(resultsIterator, false);

    return Buffer.from(JSON.stringify(results));
}

async getAllResults(iterator, isHistory) {
...
}

在上面的代码段中,thisClass作为getMarblesByRange方法中的参数传递,该方法使用该参数调用另一个方法getAllResults()

可以使用thisClass['getAllResults']或仅使用thisClass.getAllResults来调用该方法。

所有代码段均摘自marble chaincode