UNPKG

ganache-core

Version:

[![npm Version](https://img.shields.io/npm/v/ganache-core.svg)](https://www.npmjs.com/package/ganache-core) [![npm Downloads](https://img.shields.io/npm/dm/ganache-core.svg)](https://www.npmjs.com/package/ganache-core) [![Build Status](https://travis-ci.o

154 lines (136 loc) 4.45 kB
// It's unforutnate we have to have this subprovider, but it's because // we instamine, and web3 isn't written in a way that supports instamining // (i.e., it sets up the filter after the transaction has been processed). // This block filter will ensure that each block filter will always see // the change from the last block to the current block. // // Note: An added benefit of this is that it shaves off a signifcant // amount of time from tests that use web3 and block filters. var Subprovider = require("web3-provider-engine/subproviders/subprovider.js"); var inherits = require("util").inherits; var async = require("async"); var to = require("../utils/to"); inherits(DelayedBlockFilter, Subprovider); module.exports = DelayedBlockFilter; function DelayedBlockFilter() { this.watching = {}; } DelayedBlockFilter.prototype.handleRequest = function(payload, next, end) { if (payload.method === "eth_newBlockFilter") { return this.handleNewBlockFilter(payload, next, end); } if (payload.method === "eth_getFilterChanges") { return this.handleGetFilterChanges(payload, next, end); } next(); }; DelayedBlockFilter.prototype.handleNewBlockFilter = function(payload, next, end) { var self = this; // Let this filter process and add it to our watch list. next(function(err, result, cb) { if (err) { return cb(); } self.watching[result] = true; cb(); }); }; DelayedBlockFilter.prototype.handleGetFilterChanges = function(payload, next, end) { var self = this; var filterId = payload.params[0]; if (!this.watching[filterId]) { return next(); } // Get the changes, and then alter the result. next(function(err, result, cb) { if (err) { return cb(); } var currentBlockHash; var previousBlockHash; var blockNumber; async.series( [ function(c) { // If we have a result, use it. if (result.length !== 0) { currentBlockHash = result[0]; c(); } else { // Otherwise, get the current block number. self.emitPayload( { method: "eth_blockNumber" }, function(err, res) { if (err) { return c(err); } blockNumber = to.number(res.result); c(); } ); } }, function(c) { // If we got a block number above, meaning, we didn't get a block hash, // skip this step. if (blockNumber) { return c(); } // If not skipped, then we got a block hash, and we need to get a block number from it. self.emitPayload( { method: "eth_getBlockByHash", params: [currentBlockHash, false] }, function(err, res) { if (err) { return c(err); } blockNumber = to.number(res.result.number); c(); } ); }, function(c) { // If we're at block 0, return no changes. See final function below. blockNumber = to.number(blockNumber); if (blockNumber === 0) { previousBlockHash = undefined; return c(); } // If at this point, we do have a block number, so let's subtract one // from it and get the block hash of the block before it. blockNumber = blockNumber - 1; self.emitPayload( { method: "eth_getBlockByNumber", params: [blockNumber, false] }, function(err, res) { if (err) { return c(err); } previousBlockHash = res.result.hash; c(); } ); } ], function(err) { if (err) { // Unfortunately the subprovider code doesn't let us return an error // through the callback cb(). So we'll just ignore it.... (famous last words). } // If we got the previous block, use it. Otherwise do nothing. // Then stop watching because we only want on getFilterChanges to react this way. if (previousBlockHash) { result[0] = previousBlockHash; } delete self.watching[filterId]; cb(); } ); }); };