Hyperledger Fabric: проверьте, была ли транзакция зафиксирована в реестре

У меня есть три клиентских приложения, которые используют SDK Java, Node.js и Go соответственно для взаимодействия с моей фабрикой блокчейна. Используя их, я могу запрашивать и успешно обновлять бухгалтерскую книгу.

Теперь я хочу измерить задержку при обновлении реестра. Итак, я подумал сделать это, взяв временную метку перед отправкой запроса и еще одну после того, как транзакция была успешно зафиксирована в реестре, а затем вычислить разницу.

Моя проблема в том, что я не могу найти полную документацию по API SDK для Java, Go и Node.js, поэтому я не знаю, могу ли я после возврата метода отправки считать транзакцию правильно зафиксированной в бухгалтерской книге. .

Это код моих трех клиентов. Ява:

NetworkConfig ccp = NetworkConfig.fromJsonFile(networkConfigPath.toFile());
// initialize default cryptosuite and setup the client
CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite();
HFClient client = HFClient.createNewInstance();
client.setCryptoSuite(cryptoSuite);

Channel channel = client.loadChannelFromConfig(ccp.getChannelNames().iterator().next(), ccp);
channel.initialize();

TransactionProposalRequest transactionProposal = client.newTransactionProposalRequest();
// build chaincode id providing the chaincode name
ChaincodeID mychaincodeID = ChaincodeID.newBuilder().setName("mychaincode").build();
transactionProposal.setChaincodeID(mychaincodeID);
// calling chaincode function
transactionProposal.setFcn("mymethod");
transactionProposal.setArgs("a1");

Collection<ProposalResponse> res = channel.sendTransactionProposal(transactionProposal);
channel.sendTransaction(res);

Node.js:

const gateway = new Gateway();
await gateway.connect(ccp, { wallet: wallet, identity: userName, discovery: { enabled: false } });

// 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('mychaincode');

const result = await contract.submitTransaction('mymethod', 'a1');

Go:

sdk, err := fabsdk.New(config.FromFile(configFile))
if err != nil {
    fmt.Printf("failed to create SDK: %v\n", err)
    return
}
fmt.Println("SDK created")

// Prepare channel client context using client context
clientChannelContext := sdk.ChannelContext(channelID, fabsdk.WithUser(userName), fabsdk.WithOrg(orgName))
// ChannelClient is used to query and execute transactions
client, err := channel.New(clientChannelContext)
if err != nil {
    fmt.Printf("failed to create new channel client: %v\n", err)
    return
}
fmt.Println("channel client created")

response, err := client.Execute(channel.Request{ChaincodeID: ccID, Fcn: "mymethod", Args: [][]byte{[]byte("a1")}}, channel.WithRetry(retry.DefaultChannelOpts))
if err != nil {
    fmt.Printf("failed to execute the invoke function: %v\n", err)
} else {
    fmt.Println("Proposal responses: ")
    for _, element := range response.Responses {
        fmt.Printf("Endorser: %s Status: %d ChaincodeStatus: %d\n", element.Endorser, element.Status, element.ChaincodeStatus)
    }
    fmt.Println("chaincode transaction completed: " + string(response.Payload))
}
// Close SDK
sdk.Close()

Эти коды работают. Моя проблема: могу ли я быть уверен, что после строк

channel.sendTransaction(res)

(на Java)

const result = await contract.submitTransaction('mymethod', 'a1');

(в Node.js)

response, err := client.Execute(channel.Request{ChaincodeID: ccID, Fcn: "mymethod", Args: [][]byte{[]byte("a1")}}, channel.WithRetry(retry.DefaultChannelOpts))

(в Go) транзакция была зафиксирована в реестре?

Я нашел это только в документах:

«Отправьте транзакцию в реестр. Имя функции транзакции будет оцениваться на одобряющих партнерах, а затем отправлено в службу заказов для фиксации в реестре». для submitTransaction в Node.js по адресу https://fabric-sdk-node.github.io/release-1.4/module-fabric-network.Contract.html#submitTransaction__anchor

и

«Execute подготавливает и выполняет транзакцию с использованием запроса и дополнительных параметров запроса» для Execute in Go по адресу https://godoc.org/github.com/hyperledger/fabric-sdk-go/pkg/client/channel#Client..Execute.

Для Java я не могу найти документацию ... и я не уверен также в Node.js и Go.




Ответы (3)


Еще один ответ, который поможет тем, кому, возможно, нужна эта функция из интерфейса командной строки.

По умолчанию CLI возвращает успех, когда заказ получает транзакцию.

Чтобы дождаться коммита на peer chaincode invokeкоммнаде, добавьте флаг --waitForEvent

Таким образом cli будет ждать событий фиксации от одноранговых узлов.

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

person Rodolfo Leal    schedule 14.05.2019
comment
Абсолютно полезно! Спасибо! - person gava; 14.05.2019

Думаю, я решил. В каждом клиентском приложении я пытался добавить запрос в бухгалтерскую книгу через строку после запроса. Результатом этого теста является то, что версия Node.js и Go работает хорошо: после

const result = await contract.submitTransaction('mymethod', 'a1');

и

response, err := client.Execute(channel.Request{ChaincodeID: ccID, Fcn: "mymethod", Args: [][]byte{[]byte("a1")}}, channel.WithRetry(retry.DefaultChannelOpts))

результат запроса в порядке, я получаю правильное новое значение. Это означает, что бухгалтерская книга правильно обновляется после выполнения метода.

Для версии Java я решил так:

NetworkConfig ccp = NetworkConfig.fromJsonFile(networkConfigPath.toFile());
// initialize default cryptosuite and setup the client
CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite();
HFClient client = HFClient.createNewInstance();
client.setCryptoSuite(cryptoSuite);

Channel channel = client.loadChannelFromConfig(ccp.getChannelNames().iterator().next(), ccp);
channel.initialize();

TransactionProposalRequest transactionProposal = client.newTransactionProposalRequest();
// build chaincode id providing the chaincode name
ChaincodeID mychaincodeID = ChaincodeID.newBuilder().setName("mychaincode").build();
transactionProposal.setChaincodeID(mychaincodeID);
// calling chaincode function
transactionProposal.setFcn("mymethod");
transactionProposal.setArgs("a1");

Collection<ProposalResponse> res = channel.sendTransactionProposal(transactionProposal);
CompletableFuture<TransactionEvent> cf = channel.sendTransaction(res);
TransactionEvent te = cf.get();

logger.info("Status: " + te.isValid());
logger.info("Committed the transaction with transactionID + " + te.getTransactionID());

Надеюсь, это может быть полезно. Конечно, если у кого-то есть комментарии, они будут приняты.

person gava    schedule 12.05.2019

Я думаю, что лучший способ сделать это - использовать Fabric EventHub, таким образом вы регистрируете слушателя и получаете событие, когда оно фиксируется. Использование запросов может привести к получению противоречивых результатов и повторным попыткам для отложенных транзакций.

Приведенный ниже фрагмент кода можно использовать с NodeSDK, и я думаю, он будет полезен. Дополнительные примеры и документацию можно найти здесь: https://fabric-sdk-node.github.io/release-1.4/tutorial-listen-to-events.html

var options = {
    wallet_path: path.join(__dirname, './creds'),
    user_id: 'PeerAdmin',
    channel_id: 'mychannel',
    chaincode_id: 'fabcar',
    peer_url: 'grpc://localhost:7051',
    event_url: 'grpc://localhost:7053',
    orderer_url: 'grpc://localhost:7050'
};



    let eh = client.newEventHub();
    eh.setPeerAddr(options.event_url);
    eh.connect();


    let txPromise = new Promise((resolve, reject) => {
        let handle = setTimeout(() => {
            eh.disconnect();
            reject();
        }, 30000);

        eh.registerTxEvent(transactionID, (tx, code) => {
            clearTimeout(handle);
            eh.unregisterTxEvent(transactionID);
            eh.disconnect();

            if (code !== 'VALID') {
                console.error(
                    'The transaction was invalid, code = ' + code);
                reject();
            } else {
                console.log(
                    'The transaction has been committed on peer ' +
                    eh._ep._endpoint.addr);
                resolve();
            }
        });
    });
    eventPromises.push(txPromise);
person Rodolfo Leal    schedule 15.05.2019