Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix historical event subscriptions when made as first provider request #3401

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/web3-core-subscriptions/src/subscription.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,13 @@ Subscription.prototype.subscribe = function() {
// get past logs, if fromBlock is available
if(payload.params[0] === 'logs' && _.isObject(payload.params[1]) && payload.params[1].hasOwnProperty('fromBlock') && isFinite(payload.params[1].fromBlock)) {
// send the subscription request

// copy the params to avoid race-condition with deletion below this block
var blockParams = Object.assign({}, payload.params[1]);

this.options.requestManager.send({
method: 'eth_getLogs',
params: [payload.params[1]]
params: [blockParams]
}, function (err, logs) {
if(!err) {
logs.forEach(function(log){
Expand Down
50 changes: 49 additions & 1 deletion test/e2e.contract.events.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe('contract.events [ @E2E ]', function() {
var accounts;
var basic;
var instance;
var port;

var basicOptions = {
data: Basic.bytecode,
Expand All @@ -21,7 +22,7 @@ describe('contract.events [ @E2E ]', function() {
};

beforeEach(async function(){
var port = utils.getWebsocketPort();
port = utils.getWebsocketPort();

web3 = new Web3('ws://localhost:' + port);
accounts = await web3.eth.getAccounts();
Expand Down Expand Up @@ -73,6 +74,53 @@ describe('contract.events [ @E2E ]', function() {
});
});

// Regression test for a race-condition where a fresh web3 instance
// subscribing to past events would have its call parameters deleted while it
// made initial Websocket handshake and return an incorrect response.
it('can immediately listen for events in the past', async function(){
this.timeout(15000);

const first = await instance
.methods
.firesEvent(accounts[0], 1)
.send({from: accounts[0]});

const second = await instance
.methods
.firesEvent(accounts[0], 1)
.send({from: accounts[0]});

// Go forward one block...
await utils.mine(web3, accounts[0]);
const latestBlock = await web3.eth.getBlockNumber();

assert(first.blockNumber < latestBlock);
assert(second.blockNumber < latestBlock);

// Re-instantiate web3 & instance to simulate
// subscribing to past events as first request
web3 = new Web3('ws://localhost:' + port);
const newInstance = new web3.eth.Contract(Basic.abi, instance.options.address);

let counter = 0;
await new Promise(async resolve => {
newInstance
.events
.BasicEvent({
fromBlock: 0
})
.on('data', function(event) {
counter++;
assert(event.blockNumber < latestBlock);

if (counter === 2){
this.removeAllListeners();
resolve();
}
});
});
});

it('should not hear the error handler when connection.closed() called', function(){
this.timeout(15000);

Expand Down