Цепной код 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)
}