Цепной код Hyperledger: функция, вызывающая другую функцию из цепного кода?

У меня есть сценарий, в котором мне нужно вызвать какую-то другую (скажем, запрос) функцию из функции цепного кода (скажем, обновление). Имеет ли Hyperledger Fabric какой-либо интерфейс для этого. Например:

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

Я попробовал ответ на следующий пост, но это не сработало. как вызвать функцию цепочки из себя для записи суб транзакций. Хотя с помощью 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());

5 ответов

Возможно, немного поздно для OP, но для всех, кто заинтересован, вы можете вызвать другую функцию из функции того же цепного кода, используя this.<another_function>.

Мы использовали расширение IBM Blockchain Platform для VSCode, и у него есть своего рода мастер для генерации цепного кода в GO, javascript и машинописном тексте. Ниже приводится отрывок цепного кода, созданного для javascript, где вы можете наблюдать, как функция myAssetExists вызывается из функции createMyAsset черезthis.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);
    }
...

Для тех кодеров, которые испытывают трудности с использованием «fabric-contract-api-go/contractapi» в чейнкоде.

      func (s *SmartContract) ChangeCarOwner(ctx contractapi.TransactionContextInterface, carNumber string, newOwner string) error {
    car, err := s.QueryCar(ctx, carNumber)
...
}

func (s *SmartContract) QueryCar(ctx contractapi.TransactionContextInterface, carNumber string) (*Car, error) {
...
}

Надеюсь, это поможет кому-то.

В качестве альтернативного подхода я устанавливаю и создаю один и тот же цепной код с двумя именами, скажем, cc1 и cc2 на одном канале, скажем, ch1. Тогда я использую:

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

из цепочки один (cc1).

Но проблема в том, что мне нужно установить и создать один и тот же цепной код дважды с разными именами на одном канале.

Любые другие идеи приветствуются.

@jama ответ на вопрос правильный. Однако это характерно дляfabric-contract-api. Для людей, использующихfabric-shim package может реализовать то же самое, передав 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.

Все фрагменты кода были взяты из мраморного чейнкода.

Иногда мы должны думать, что это проще. Ну, ответ: позвоните прямо. Например: мы получили две функции A и B

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

если мы хотим вызвать функцию A внутри функции B, просто сделайте это как

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

 s.A(APIstub,args)

}
Другие вопросы по тегам