Skip to content

Commit 67957c5

Browse files
author
Simon Stone
committed
[FAB-16602] Fix Node.js chaincode event publishing
The event name was being sent in snake_case, not in camelCase, so it was being ignored. This change was incorrectly made recently (by me!) when migrating to the new protobufjs library. There are no tests that check chaincode events work, so I've added a test at the same time so nobody can do this in the future. Signed-off-by: Simon Stone <sstone1@uk.ibm.com> Change-Id: Ia202c59065587f9bcf36b02c2770f591e8a5c988
1 parent e48d70c commit 67957c5

7 files changed

Lines changed: 110 additions & 3 deletions

File tree

fabric-shim/lib/stub.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,8 +734,11 @@ class ChaincodeStub {
734734
throw new Error('Event name must be a non-empty string');
735735
}
736736

737+
// Because this is passed directly into gRPC as an object, rather
738+
// than a serialized protocol buffer message, it uses snake_case
739+
// rather than camelCase like the rest of the code base.
737740
this.chaincodeEvent = {
738-
eventName: name,
741+
event_name: name,
739742
payload
740743
};
741744
}

fabric-shim/test/unit/stub.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@ describe('Stub', () => {
939939

940940
it ('should set an event', () => {
941941
stub.setEvent('some name', Buffer.from('some payload'));
942-
expect(stub.chaincodeEvent.eventName).to.equal('some name');
942+
expect(stub.chaincodeEvent.event_name).to.equal('some name');
943943
expect(stub.chaincodeEvent.payload).to.deep.equal(Buffer.from('some payload'));
944944
});
945945
});

test/fv/events.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
# Copyright IBM Corp. All Rights Reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
*/
6+
'use strict';
7+
8+
const chai = require('chai');
9+
chai.use(require('chai-as-promised'));
10+
const expect = chai.expect;
11+
const utils = require('./utils');
12+
const {LONG_STEP} = utils.TIMEOUTS;
13+
14+
describe('Chaincode events', async function () {
15+
const suite = 'events';
16+
17+
before(async function () {
18+
this.timeout(LONG_STEP);
19+
20+
return utils.installAndInstantiate(suite, 'org.mynamespace.events:instantiate');
21+
});
22+
23+
it('should publish an event', async function () {
24+
this.timeout(LONG_STEP);
25+
26+
const date = new Date().toISOString();
27+
await utils.invoke(suite, 'org.mynamespace.events:emit', [`my event data @ ${date}`]);
28+
const block = await utils.getLastBlock();
29+
expect(block.data.data.length).to.equal(1); // only one transaction
30+
const transaction = block.data.data[0];
31+
const actions = transaction.payload.data.actions;
32+
expect(actions.length).to.equal(1); // only one action
33+
const action = actions[0];
34+
const proposalResponsePayload = action.payload.action.proposal_response_payload;
35+
const events = proposalResponsePayload.extension.events;
36+
expect(events.chaincode_id).to.equal('events');
37+
expect(events.event_name).to.equal('myevent');
38+
const payload = Buffer.from(events.payload, 'base64').toString();
39+
expect(payload).to.equal(`my event data @ ${date}`);
40+
});
41+
42+
});

test/fv/events/chaincode.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
# Copyright IBM Corp. All Rights Reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
*/
6+
'use strict';
7+
8+
const {Contract} = require('fabric-contract-api');
9+
10+
class EventsChaincode extends Contract {
11+
12+
constructor() {
13+
super('org.mynamespace.events');
14+
this.logBuffer = {output: []};
15+
}
16+
17+
async instantiate(ctx) {
18+
19+
}
20+
21+
async emit(ctx, value) {
22+
const buffer = Buffer.from(value);
23+
ctx.stub.setEvent('myevent', buffer);
24+
}
25+
26+
}
27+
module.exports = EventsChaincode;

test/fv/events/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
'use strict';
2+
3+
const Chaincode = require('./chaincode');
4+
5+
module.exports.contracts = [Chaincode];

test/fv/events/package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "chaincode",
3+
"description": "Chaincode testing events functionality",
4+
"engines": {
5+
"node": ">=8.4.0",
6+
"npm": ">=5.3.0"
7+
},
8+
"scripts": {
9+
"start": "fabric-chaincode-node start"
10+
},
11+
"main": "index.js",
12+
"engine-strict": true,
13+
"engineStrict": true,
14+
"version": "1.0.0",
15+
"author": "",
16+
"license": "Apache-2.0",
17+
"dependencies": {
18+
"fabric-shim": "unstable",
19+
"fabric-contract-api": "unstable"
20+
}
21+
}

test/fv/utils.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ async function installAndInstantiate(ccName, instantiateFunc, instantiateArgs) {
8787
return instantiate(ccName, instantiateFunc, instantiateArgs);
8888
}
8989

90+
async function getLastBlock() {
91+
const cmd = 'docker exec org1_cli bash -c "peer channel fetch newest -c mychannel /tmp/mychannel.block && configtxlator proto_decode --type common.Block --input=/tmp/mychannel.block"';
92+
const {error, stdout, stderr} = await exec(cmd);
93+
if (error) {
94+
throw new Error(error, stderr);
95+
}
96+
return JSON.parse(stdout.trim());
97+
}
98+
9099
const TIMEOUTS = {
91100
LONGEST_STEP : 24000 * 1000 * multiplier,
92101
LONG_STEP : 240 * 1000 * multiplier,
@@ -96,4 +105,4 @@ const TIMEOUTS = {
96105
MED_INC : 10 * 1000 * multiplier,
97106
SHORT_INC: 5 * 1000 * multiplier
98107
};
99-
module.exports = {installAndInstantiate, invoke, query, TIMEOUTS};
108+
module.exports = {installAndInstantiate, invoke, query, getLastBlock, TIMEOUTS};

0 commit comments

Comments
 (0)