Skip to content

Commit

Permalink
[FAB-10402] BlockDecoder decodes chaincode input
Browse files Browse the repository at this point in the history
This patchset enhances BlockDecoder to decode an endorsement proposal,
which includes the chaincode name and arguments used in the transaction.

Change-Id: I839ed8d5f83f0b200d54ddaa837cd7d94561b64a
Signed-off-by: Taku Shimosawa <[email protected]>
  • Loading branch information
shimos committed May 25, 2018
1 parent e9f8201 commit 8127cac
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 2 deletions.
85 changes: 83 additions & 2 deletions fabric-client/lib/BlockDecoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var _transProto = grpc.load(__dirname + '/protos/peer/transaction.proto').protos
var _proposalProto = grpc.load(__dirname + '/protos/peer/proposal.proto').protos;
var _responseProto = grpc.load(__dirname + '/protos/peer/proposal_response.proto').protos;
var _peerConfigurationProto = grpc.load(__dirname + '/protos/peer/configuration.proto').protos;
var _chaincodeProto = grpc.load(__dirname + '/protos/peer/chaincode.proto').protos;
var _mspPrProto = grpc.load(__dirname + '/protos/msp/msp_principal.proto').common;
var _commonProto = grpc.load(__dirname + '/protos/common/common.proto').common;
var _configtxProto = grpc.load(__dirname + '/protos/common/configtx.proto').common;
Expand Down Expand Up @@ -171,7 +172,7 @@ actions {array}
header -- {{@link SignatureHeader}}
payload
chaincode_proposal_payload
input -- {byte[]}
input -- {{@link ChaincodeInvocationSpec}} for a endorser transaction
action
proposal_response_payload
proposal_hash -- {byte[]}
Expand Down Expand Up @@ -205,6 +206,27 @@ actions {array}
* @typedef {Object} Transaction
*/

/**
* An endorsement proposal, which includes the name of the chaincode
* to be invoked and the arguments to be passed to the chaincode.
* <br><br>
* A "ChaincodeInvocationSpec" has the following object structure.
<br><pre>
chaincode_spec
type -- {int}
chaincode_id
path -- {string}
name -- {string}
version -- {string}
input
args -- {byte[][]}
decorations -- {map of string to byte[]}
timeout -- {int}
</pre>
*
* @typedef {Object} ChaincodeInvocationSpec
*/

/**
* An object of a protobuf message "ConfigUpdateEnvelope".
* <br><br>
Expand Down Expand Up @@ -1079,12 +1101,71 @@ function decodeChaincodeActionPayload(payload_bytes) {
function decodeChaincodeProposalPayload(chaincode_proposal_payload_bytes) {
var chaincode_proposal_payload = {};
var proto_chaincode_proposal_payload = _proposalProto.ChaincodeProposalPayload.decode(chaincode_proposal_payload_bytes);
chaincode_proposal_payload.input = proto_chaincode_proposal_payload.getInput().toBuffer();
chaincode_proposal_payload.input = decodeChaincodeProposalPayloadInput(proto_chaincode_proposal_payload.getInput());
//TransientMap is not allowed to be included on ledger

return chaincode_proposal_payload;
}

function decodeChaincodeProposalPayloadInput(chaincode_proposal_payload_input_bytes) {
var chaincode_proposal_payload_input = {};

// For a normal transaction, input is ChaincodeInvocationSpec.
var proto_chaincode_invocation_spec = _chaincodeProto.ChaincodeInvocationSpec.decode(chaincode_proposal_payload_input_bytes);
chaincode_proposal_payload_input.chaincode_spec = decodeChaincodeSpec(proto_chaincode_invocation_spec.getChaincodeSpec().toBuffer());

return chaincode_proposal_payload_input;
}

const chaincode_type_as_string = {
0: 'UNDEFINED',
1: 'GOLANG',
2: 'NODE',
3: 'CAR',
4: 'JAVA'
};

function chaincodeTypeToString(type) {
let type_str = chaincode_type_as_string[type];
if (typeof type_str == 'undefined') {
return 'UNKNOWN';
} else {
return type_str;
}
}

function decodeChaincodeSpec(chaincode_spec_bytes) {
var chaincode_spec = {};
var proto_chaincode_spec = _chaincodeProto.ChaincodeSpec.decode(chaincode_spec_bytes);
chaincode_spec.type = proto_chaincode_spec.getType();
// Add a string for the chaincode type (GOLANG, NODE, etc.)
chaincode_spec.typeString = chaincodeTypeToString(chaincode_spec.type);
chaincode_spec.input = decodeChaincodeInput(proto_chaincode_spec.getInput().toBuffer());
chaincode_spec.chaincode_id = proto_chaincode_spec.getChaincodeId();
chaincode_spec.timeout = proto_chaincode_spec.getTimeout();

return chaincode_spec;
}

function decodeChaincodeInput(chaincode_spec_input_bytes) {
var input = {};
var proto_chaincode_input = _chaincodeProto.ChaincodeInput.decode(chaincode_spec_input_bytes);
var args = proto_chaincode_input.getArgs();

input.args = [];
for (let i in args) {
input.args.push(args[i].toBuffer());
}
let decorations = proto_chaincode_input.getDecorations();
let keys = Object.keys(decorations.map);
input.decorations = {};
for (let i in keys) {
input.decorations[keys[i]] = decorations.map[keys[i]].value.toBuffer();
}

return input;
}

function decodeChaincodeEndorsedAction(proto_chaincode_endorsed_action) {
var action = {};
action.proposal_response_payload = decodeProposalResponsePayload(proto_chaincode_endorsed_action.getProposalResponsePayload());
Expand Down
41 changes: 41 additions & 0 deletions test/unit/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var commonProto = grpc.load(path.join(__dirname, '../../fabric-client/lib/protos
var kv_query_resultProto = grpc.load(path.join(__dirname, '../../fabric-client/lib/protos/ledger/queryresult/kv_query_result.proto')).queryresult;
var rwsetProto = grpc.load(path.join(__dirname, '../../fabric-client/lib/protos/ledger/rwset/rwset.proto')).rwset;
var kvrwsetProto = grpc.load(path.join(__dirname, '../../fabric-client/lib/protos/ledger/rwset/kvrwset/kv_rwset.proto')).kvrwset;
var chaincodeProto = grpc.load(path.join(__dirname, '../../fabric-client/lib/protos/peer/chaincode.proto')).protos;
var utils = require('fabric-client/lib/utils.js');
var logger = utils.getLogger('BlockDecoder');

Expand Down Expand Up @@ -230,3 +231,43 @@ test('\n\n*** BlockDecoder.js test HeaderType ***\n\n', (t) => {
);
t.end();
});

test('\n\n*** BlockDecoder.js test ChaincodeSpec ***\n\n', (t) => {
let chaincodeTypeToString = BlockDecoder.__get__('chaincodeTypeToString');
t.equals(chaincodeTypeToString(0), 'UNDEFINED', 'Check ChaincodeType for UNDEFINED');
t.equals(chaincodeTypeToString(1), 'GOLANG', 'Check ChaincodeType for GOLANG');
t.equals(chaincodeTypeToString(2), 'NODE', 'Check ChaincodeType for NODE');
t.equals(chaincodeTypeToString(99), 'UNKNOWN', 'Check ChaincodeType for UNKNOWN');

let decodeChaincodeInput = BlockDecoder.__get__('decodeChaincodeInput');
let input_proto = new chaincodeProto.ChaincodeInput();
input_proto.setArgs([Buffer.from('Hello'), Buffer.from('World')]);
input_proto.setDecorations({ test: Buffer.from('Good') });

let chaincodeid_proto = new chaincodeProto.ChaincodeID();
chaincodeid_proto.setPath('');
chaincodeid_proto.setName('test-chaincode');
chaincodeid_proto.setVersion('v111');

let decodeChaincodeSpec = BlockDecoder.__get__('decodeChaincodeSpec');
let spec_proto = new chaincodeProto.ChaincodeSpec();
spec_proto.setType(chaincodeProto.ChaincodeSpec.Type.GOLANG);
spec_proto.setChaincodeId(chaincodeid_proto);
spec_proto.setInput(input_proto);
spec_proto.setTimeout(888);

let spec_decoded = decodeChaincodeSpec(spec_proto.toBuffer());
t.equals(spec_decoded.type, chaincodeProto.ChaincodeSpec.Type.GOLANG, 'Check ChaincodeSpec.type');
t.equals(spec_decoded.typeString, 'GOLANG', 'Check string for ChaincodeSpec.type');
t.equals(spec_decoded.chaincode_id.path, '', 'Check ChaincodeSpec.chaincode_id.path');
t.equals(spec_decoded.chaincode_id.name, 'test-chaincode', 'Check ChaincodeSpec.chaincode_id.name');
t.equals(spec_decoded.chaincode_id.version, 'v111', 'Check ChaincodeSpec.chaincode_id.version');
t.equals(spec_decoded.timeout, 888, 'Check ChaincodeSpec.timeout');

let input_decoded = spec_decoded.input;
t.equals(input_decoded.args[0].toString('utf8'), 'Hello', 'Check ChaincodeSpec.input.Args[0]');
t.equals(input_decoded.args[1].toString('utf8'), 'World', 'Check ChaincodeSpec.input.Args[1]');
t.equals(input_decoded.decorations.test.toString('utf8'), 'Good', 'Check ChaincodeSpec.input.decorations[test]');

t.end();
});

0 comments on commit 8127cac

Please sign in to comment.