【问题标题】:How to decode ProposalResponsePayload in fabric-sdk-node如何在 fabric-sdk-node 中解码 ProposalResponsePayload
【发布时间】:2018-05-12 04:26:26
【问题描述】:

我了解发送交易提案(如下面的代码)

    return channel.sendTransactionProposal(request);
}).then((proposalResponse) => {
//need to decode results
});

其中proposalResponse 是ProposalResponseObject (https://fabric-sdk-node.github.io/global.html#ProposalResponseObject__anchor),其中ProposalResponseObject[0] 是ProposalResponse 的数组。

我也明白 proposalResponse[0][i].response.payloadshim.Success的返回信息

但是如何解码proposalResponse[0][i].payloadproposalResponse[1]

我尝试查看 BlockDecoder (https://github.com/hyperledger/fabric-sdk-node/blob/release-1.1/fabric-client/lib/BlockDecoder.js) 但我找不到正确的方法来解码上述项目?

【问题讨论】:

    标签: node.js hyperledger-fabric hyperledger


    【解决方案1】:

    我查看了有效负载响应的 protobuf 结构并使用了 BlockDecoder.js 中的代码。如果有人感兴趣:

    var grpc = require('grpc');
    var _responseProto = grpc.load(__dirname + '/node_modules/fabric-client/lib/protos/peer/proposal_response.proto').protos;
    var _proposalProto = grpc.load(__dirname + '/node_modules/fabric-client/lib/protos/peer/proposal.proto').protos;
    var _rwsetProto = grpc.load(__dirname + '/node_modules/fabric-client/lib/protos/ledger/rwset/rwset.proto').rwset;
    var _kv_rwsetProto = grpc.load(__dirname + '/node_modules/fabric-client/lib/protos/ledger/rwset/kvrwset/kv_rwset.proto').kvrwset;
    var _ccEventProto = grpc.load(__dirname + '/node_modules/fabric-client/lib/protos/peer/chaincode_event.proto').protos;
    
    module.exports = function decodeProposalResponsePayload(proposal_response_payload_bytes) {
    	var proposal_response_payload = {};
    	var proto_proposal_response_payload = _responseProto.ProposalResponsePayload.decode(proposal_response_payload_bytes);
    	proposal_response_payload.proposal_hash = proto_proposal_response_payload.getProposalHash().toBuffer().toString('hex');
    	proposal_response_payload.extension = decodeChaincodeAction(proto_proposal_response_payload.getExtension());
    
    	return proposal_response_payload;
    }
    
    function decodeChaincodeAction(action_bytes) {
    	var chaincode_action = {};
    	var proto_chaincode_action = _proposalProto.ChaincodeAction.decode(action_bytes);
    	chaincode_action.results = decodeReadWriteSets(proto_chaincode_action.getResults());
    	chaincode_action.events = decodeChaincodeEvents(proto_chaincode_action.getEvents());
    	chaincode_action.response = decodeResponse(proto_chaincode_action.getResponse());
    	chaincode_action.chaincode_id = decodeChaincodeID(proto_chaincode_action.getChaincodeId());
    
    	return chaincode_action;
    }
    
    function decodeReadWriteSets(rw_sets_bytes) {
    	var proto_tx_read_write_set = _rwsetProto.TxReadWriteSet.decode(rw_sets_bytes);
    	var tx_read_write_set = {};
    	tx_read_write_set.data_model = proto_tx_read_write_set.getDataModel();
    	if (proto_tx_read_write_set.getDataModel() === _rwsetProto.TxReadWriteSet.DataModel.KV) {
    		tx_read_write_set.ns_rwset = [];
    		let proto_ns_rwset = proto_tx_read_write_set.getNsRwset();
    		for (let i in proto_ns_rwset) {
    			let kv_rw_set = {};
    			let proto_kv_rw_set = proto_ns_rwset[i];
    			kv_rw_set.namespace = proto_kv_rw_set.getNamespace();
    			kv_rw_set.rwset = decodeKVRWSet(proto_kv_rw_set.getRwset());
    			tx_read_write_set.ns_rwset.push(kv_rw_set);
    		}
    	} else {
    		// not able to decode this type of rw set, return the array of byte[]
    		tx_read_write_set.ns_rwset = proto_tx_read_write_set.getNsRwset();
    	}
    
    	return tx_read_write_set;
    }
    
    function decodeKVRWSet(kv_bytes) {
    	var proto_kv_rw_set = _kv_rwsetProto.KVRWSet.decode(kv_bytes);
    	var kv_rw_set = {};
    
    	// KV readwrite set has three arrays
    	kv_rw_set.reads = [];
    	kv_rw_set.range_queries_info = [];
    	kv_rw_set.writes = [];
    
    	// build reads
    	let reads = kv_rw_set.reads;
    	var proto_reads = proto_kv_rw_set.getReads();
    	for (let i in proto_reads) {
    		reads.push(decodeKVRead(proto_reads[i]));
    	}
    
    	// build range_queries_info
    	let range_queries_info = kv_rw_set.range_queries_info;
    	var proto_range_queries_info = proto_kv_rw_set.getRangeQueriesInfo();
    	for (let i in proto_range_queries_info) {
    		range_queries_info.push(decodeRangeQueryInfo(proto_range_queries_info[i]));
    	}
    
    	// build writes
    	let writes = kv_rw_set.writes;
    	var proto_writes = proto_kv_rw_set.getWrites();
    	for (let i in proto_writes) {
    		writes.push(decodeKVWrite(proto_writes[i]));
    	}
    
    	return kv_rw_set;
    }
    
    function decodeKVRead(proto_kv_read) {
    	let kv_read = {};
    	kv_read.key = proto_kv_read.getKey();
    	let proto_version = proto_kv_read.getVersion();
    	if (proto_version) {
    		kv_read.version = {};
    		kv_read.version.block_num = proto_version.getBlockNum().toString();
    		kv_read.version.tx_num = proto_version.getTxNum().toString();
    	} else {
    		kv_read.version = null;
    	}
    
    	return kv_read;
    }
    
    function decodeRangeQueryInfo(proto_range_query_info) {
    	let range_query_info = {};
    	range_query_info.start_key = proto_range_query_info.getStartKey();
    	range_query_info.end_key = proto_range_query_info.getEndKey();
    	range_query_info.itr_exhausted = proto_range_query_info.getItrExhausted();
    
    	// reads_info is one of QueryReads
    	let proto_raw_reads = proto_range_query_info.getRawReads();
    	if (proto_raw_reads) {
    		range_query_info.raw_reads = {};
    		range_query_info.raw_reads.kv_reads = [];
    		for (let i in proto_raw_reads.kv_reads) {
    			let kv_read = decodeKVRead(proto_raw_reads.kv_reads[i]);
    			range_query_info.raw_reads.kv_reads.push(kv_read);
    		}
    	}
    	// or QueryReadsMerkleSummary
    	let proto_reads_merkle_hashes = proto_range_query_info.getReadsMerkleHashes();
    	if (proto_reads_merkle_hashes) {
    		range_query_info.reads_merkle_hashes = {};
    		range_query_info.reads_merkle_hashes.max_degree = proto_reads_merkle_hashes.getMaxDegree();
    		range_query_info.reads_merkle_hashes.max_level = proto_reads_merkle_hashes.getMaxLevel();
    		range_query_info.reads_merkle_hashes.max_level_hashes = proto_reads_merkle_hashes.getMaxLevelHashes();
    	}
    
    	return range_query_info;
    }
    
    function decodeKVWrite(proto_kv_write) {
    	let kv_write = {};
    	kv_write.key = proto_kv_write.getKey();
    	kv_write.is_delete = proto_kv_write.getIsDelete();
    	kv_write.value = proto_kv_write.getValue().toBuffer().toString();
    
    	return kv_write;
    }
    
    function decodeChaincodeEvents(event_bytes) {
    	var events = {};
    	var proto_events = _ccEventProto.ChaincodeEvent.decode(event_bytes);
    	events.chaincode_id = proto_events.getChaincodeId();
    	events.tx_id = proto_events.getTxId();
    	events.event_name = proto_events.getEventName();
    	events.payload = proto_events.getPayload().toBuffer();
    
    	return events;
    }
    
    function decodeResponse(proto_response) {
    	if (!proto_response) return null;
    	var response = {};
    	response.status = proto_response.getStatus();
    	response.message = proto_response.getMessage();
    	response.payload = proto_response.getPayload().toBuffer().toString();
    
    	return response;
    }
    
    function decodeChaincodeID(proto_chaincode_id) {
    	var chaincode_id = {};
    	if(!proto_chaincode_id) {
    		console.log('decodeChaincodeID - no proto_chaincode_id found');
    		return chaincode_id;
    	}
    	chaincode_id.path = proto_chaincode_id.getPath();
    	chaincode_id.name = proto_chaincode_id.getName();
    	chaincode_id.version = proto_chaincode_id.getVersion();
    
    	return chaincode_id;
    }

    【讨论】:

    • 赞成正确性。仍然认为您必须做所有这些才能阅读回复绝对是一种心理......
    【解决方案2】:

    据我所知,ProposalResponse Payload 可以从 TransactionActionInfo 类中获取,并返回一个可以使用实用方法解码的 byte[] 数组。

     void blockWalker(Channel channel) throws InvalidArgumentException, ProposalException, IOException {
            try {
                BlockchainInfo channelInfo = channel.queryBlockchainInfo();
    
                for (long current = channelInfo.getHeight() - 1; current > -1; --current) {
                    BlockInfo returnedBlock = channel.queryBlockByNumber(current);
                    final long blockNumber = returnedBlock.getBlockNumber();
    
                    out("current block number %d has data hash: %s", blockNumber, Hex.encodeHexString(returnedBlock.getDataHash()));
                    out("current block number %d has previous hash id: %s", blockNumber, Hex.encodeHexString(returnedBlock.getPreviousHash()));
                    out("current block number %d has calculated block hash is %s", blockNumber, Hex.encodeHexString(SDKUtils.calculateBlockHash(blockNumber, returnedBlock.getPreviousHash(), returnedBlock.getDataHash())));
    
                    final int envelopCount = returnedBlock.getEnvelopCount();
                    assertEquals(1, envelopCount);
                    out("current block number %d has %d envelope count:", blockNumber, returnedBlock.getEnvelopCount());
                    int i = 0;
                    for (BlockInfo.EnvelopeInfo envelopeInfo : returnedBlock.getEnvelopeInfos()) {
                        ++i;
    
                        out("  Transaction number %d has transaction id: %s", i, envelopeInfo.getTransactionID());
                        final String channelId = envelopeInfo.getChannelId();
    
    
                        out("  Transaction number %d has channel id: %s", i, channelId);
                        out("  Transaction number %d has epoch: %d", i, envelopeInfo.getEpoch());
                        out("  Transaction number %d has transaction timestamp: %tB %<te,  %<tY  %<tT %<Tp", i, envelopeInfo.getTimestamp());
                        out("  Transaction number %d has type id: %s", i, "" + envelopeInfo.getType());
    
                        if (envelopeInfo.getType() == TRANSACTION_ENVELOPE) {
                            BlockInfo.TransactionEnvelopeInfo transactionEnvelopeInfo = (BlockInfo.TransactionEnvelopeInfo) envelopeInfo;
    
                            out("  Transaction number %d has %d actions", i, transactionEnvelopeInfo.getTransactionActionInfoCount());
                            out("  Transaction number %d isValid %b", i, transactionEnvelopeInfo.isValid());
                            out("  Transaction number %d validation code %d", i, transactionEnvelopeInfo.getValidationCode());
    
                            int j = 0;
                            for (BlockInfo.TransactionEnvelopeInfo.TransactionActionInfo transactionActionInfo : transactionEnvelopeInfo.getTransactionActionInfos()) {
                                ++j;
                                out("   Transaction action %d has response status %d", j, transactionActionInfo.getResponseStatus());
                                out("   Transaction action %d has response message bytes as string: %s", j,
                                        printableString(new String(transactionActionInfo.getResponseMessageBytes(), "UTF-8")));
                                out("   Transaction action %d has %d endorsements", j, transactionActionInfo.getEndorsementsCount());
    
    
                                for (int n = 0; n < transactionActionInfo.getEndorsementsCount(); ++n) {
                                    BlockInfo.EndorserInfo endorserInfo = transactionActionInfo.getEndorsementInfo(n);
                                    out("Endorser %d signature: %s", n, Hex.encodeHexString(endorserInfo.getSignature()));
                                    out("Endorser %d endorser: %s", n, new String(endorserInfo.getEndorser(), "UTF-8"));
                                }
                                out("   Transaction action %d has %d chaincode input arguments", j, transactionActionInfo.getChaincodeInputArgsCount());
                                for (int z = 0; z < transactionActionInfo.getChaincodeInputArgsCount(); ++z) {
                                    out("     Transaction action %d has chaincode input argument %d is: %s", j, z,
                                            printableString(new String(transactionActionInfo.getChaincodeInputArgs(z), "UTF-8")));
                                }
    
                                out("   Transaction action %d proposal response status: %d", j,
                                        transactionActionInfo.getProposalResponseStatus());
                                out("   Transaction action %d proposal response payload: %s", j,
                                        printableString(new String(transactionActionInfo.getProposalResponsePayload())));
    
                                TxReadWriteSetInfo rwsetInfo = transactionActionInfo.getTxReadWriteSet();
                                if (null != rwsetInfo) {
                                    out("   Transaction action %d has %d name space read write sets", j, rwsetInfo.getNsRwsetCount());
    
                                    for (TxReadWriteSetInfo.NsRwsetInfo nsRwsetInfo : rwsetInfo.getNsRwsetInfos()) {
                                        final String namespace = nsRwsetInfo.getNaamespace();
                                        KvRwset.KVRWSet rws = nsRwsetInfo.getRwset();
    
                                        int rs = -1;
                                        for (KvRwset.KVRead readList : rws.getReadsList()) {
                                            rs++;
    
                                            out("     Namespace %s read set %d key %s  version [%d:%d]", namespace, rs, readList.getKey(),
                                                    readList.getVersion().getBlockNum(), readList.getVersion().getTxNum());
    
                                            if ("bar".equals(channelId) && blockNumber == 2) {
                                                if ("example_cc_go".equals(namespace)) {
                                                    if (rs == 0) {
                                                        assertEquals("a", readList.getKey());
                                                        assertEquals(1, readList.getVersion().getBlockNum());
                                                        assertEquals(0, readList.getVersion().getTxNum());
                                                    } else if (rs == 1) {
                                                        assertEquals("b", readList.getKey());
                                                        assertEquals(1, readList.getVersion().getBlockNum());
                                                        assertEquals(0, readList.getVersion().getTxNum());
                                                    } else {
                                                        fail(format("unexpected readset %d", rs));
                                                    }
    
                                                    TX_EXPECTED.remove("readset1");
                                                }
                                            }
                                        }
    
                                        rs = -1;
                                        for (KvRwset.KVWrite writeList : rws.getWritesList()) {
                                            rs++;
                                            String valAsString = printableString(new String(writeList.getValue().toByteArray(), "UTF-8"));
    
                                            out("     Namespace %s write set %d key %s has value '%s' ", namespace, rs,
                                                    writeList.getKey(),
                                                    valAsString);
    
                                            if ("bar".equals(channelId) && blockNumber == 2) {
                                                if (rs == 0) {
                                                    assertEquals("a", writeList.getKey());
                                                    assertEquals("400", valAsString);
                                                } else if (rs == 1) {
                                                    assertEquals("b", writeList.getKey());
                                                    assertEquals("400", valAsString);
                                                } else {
                                                    fail(format("unexpected writeset %d", rs));
                                                }
    
                                                TX_EXPECTED.remove("writeset1");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if (!TX_EXPECTED.isEmpty()) {
                  //  fail(TX_EXPECTED.get(0));
                }
            } catch (InvalidProtocolBufferRuntimeException e) {
                throw e.getCause();
            }
        }
    

    实用方法 printableString()

    static String printableString(final String string) {
        int maxLogStringLength = 10000;
        if (string == null || string.length() == 0) {
            return string;
        }
    
        String ret = string.replaceAll("[^\\p{Print}]", "\n");
    
        ret = ret.substring(0, Math.min(ret.length(), maxLogStringLength)) + (ret.length() > maxLogStringLength ? "..." : "");
    
        return ret;
    
    }
    

    【讨论】:

    • 我看到这是Java。你有 Javascript 的等价物吗?
    猜你喜欢
    • 2023-03-29
    • 2019-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    相关资源
    最近更新 更多