From d21f06d0bafd50ec1361d2706a18a9228e69c509 Mon Sep 17 00:00:00 2001 From: Matthew Dean Date: Wed, 7 Nov 2018 08:19:01 +0000 Subject: [PATCH] Fix blockchain tests This fixes the last set of blockchain tests: * RPC_API_Test * randomStatetest224BC * randomStatetest234BC * randomStatetest529BC * ExtraData32 * log1_correct * timeDiff0 * timeDiff12 * timeDiff13 * timeDiff14 These were mostly caused by missing block validation and the intentional disparity between the bloom filter implementation and the yellow paper introduced in #295. --- lib/bloom.js | 18 ++---------------- lib/runBlock.js | 11 ++++++++--- tests/api/bloom.js | 2 +- tests/api/runBlock.js | 31 ++++++++++++++++++++++++------- 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/lib/bloom.js b/lib/bloom.js index e123828ad0..f6d0fd03f5 100644 --- a/lib/bloom.js +++ b/lib/bloom.js @@ -2,20 +2,6 @@ const assert = require('assert') const utils = require('ethereumjs-util') const byteSize = 256 -/** - * Drops leading zeroes from a buffer - * @function dropLeadingZeroes - * @param {Buffer} buff - * @returns {Buffer} a slice of the given buffer starting at the first non-zero entry - */ -function dropLeadingZeroes (buff) { - for (var i = 0; i < buff.length; i++) { - if (buff[i] !== 0) { - return buff.slice(i) - } - } -} - /** * Represents a Bloom * @constructor @@ -36,7 +22,7 @@ var Bloom = module.exports = function (bitvector) { * @param {Buffer} e the element to add */ Bloom.prototype.add = function (e) { - e = utils.keccak256(dropLeadingZeroes(e)) + e = utils.keccak256(e) var mask = 2047 // binary 11111111111 for (var i = 0; i < 3; i++) { @@ -55,7 +41,7 @@ Bloom.prototype.add = function (e) { * @returns {boolean} Returns {@code true} if the element is in the bloom */ Bloom.prototype.check = function (e) { - e = utils.keccak256(dropLeadingZeroes(e)) + e = utils.keccak256(e) var mask = 2047 // binary 11111111111 var match = true diff --git a/lib/runBlock.js b/lib/runBlock.js index b0bcdcbd38..603cbd9f77 100644 --- a/lib/runBlock.js +++ b/lib/runBlock.js @@ -36,6 +36,7 @@ module.exports = function (opts, cb) { // parse options const block = opts.block + const skipBlockValidation = opts.skipBlockValidation || false const generateStateRoot = !!opts.generate const validateStateRoot = !generateStateRoot const bloom = new Bloom() @@ -80,10 +81,14 @@ module.exports = function (opts, cb) { } function validateBlock (cb) { - if (new BN(block.header.gasLimit).gte(new BN('8000000000000000', 16))) { - cb(new Error('Invalid block with gas limit greater than (2^63 - 1)')) - } else { + if (skipBlockValidation) { cb() + } else { + if (new BN(block.header.gasLimit).gte(new BN('8000000000000000', 16))) { + cb(new Error('Invalid block with gas limit greater than (2^63 - 1)')) + } else { + block.validate(self.blockchain, cb) + } } } diff --git a/tests/api/bloom.js b/tests/api/bloom.js index f52a061748..77284afd97 100644 --- a/tests/api/bloom.js +++ b/tests/api/bloom.js @@ -69,7 +69,7 @@ tape('bloom', (t) => { bloom.add(Buffer.from('0000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48', 'hex')) st.equal( bloom.bitvector.toString('hex'), - '00000000000000000000080000800000000000000000000000000000000000000000000000000000000000000000000000000000000004000000080000200000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000010008000000000000000002000000000000000000000000008000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000081100200000000000000000000000000000000000000000000000000000000008000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000002000000000000000004000000000000000000000' ) st.end() }) diff --git a/tests/api/runBlock.js b/tests/api/runBlock.js index 47b8b68068..dc7ab112fb 100644 --- a/tests/api/runBlock.js +++ b/tests/api/runBlock.js @@ -41,7 +41,7 @@ tape('runBlock', async (t) => { const suite = setup() t.test('should fail without params', async (st) => { - suite.p.runBlock() + await suite.p.runBlock() .then(() => st.fail('should have returned error')) .catch((e) => st.ok(e.message.includes('invalid input'), 'correct error')) @@ -49,7 +49,7 @@ tape('runBlock', async (t) => { }) t.test('should fail without opts', async (st) => { - suite.p.runBlock({}) + await suite.p.runBlock({}) .then(() => st.fail('should have returned error')) .catch((e) => st.ok(e.message.includes('invalid input'), 'correct error')) @@ -64,7 +64,7 @@ tape('runBlock', async (t) => { // The mocked VM uses a mocked runTx // which always returns an error. - await suite.p.runBlock({ block, root: genesis.header.stateRoot }) + await suite.p.runBlock({ block, root: genesis.header.stateRoot, skipBlockValidation: true }) .then(() => t.fail('should have returned error')) .catch((e) => t.equal(e.message, 'test')) @@ -82,13 +82,27 @@ tape('should fail when block gas limit higher than 2^63-1', async (t) => { gasLimit: Buffer.from('8000000000000000', 16) } }) - suite.p.runBlock({ block, root: genesis.header.stateRoot }) + await suite.p.runBlock({ block, root: genesis.header.stateRoot }) .then(() => t.fail('should have returned error')) .catch((e) => t.ok(e.message.includes('Invalid block'))) t.end() }) +tape('should fail when block validation fails', async (t) => { + const suite = setup() + + const genesis = createGenesis() + const block = new Block(util.rlp.decode(suite.data.blocks[0].rlp)) + block.validate = (_, cb) => cb(new Error('test')) + + await suite.p.runBlock({ block, root: genesis.header.stateRoot }) + .then(() => t.fail('should have returned error')) + .catch((e) => t.ok(e.message.includes('test'))) + + t.end() +}) + tape('should fail when tx gas limit higher than block gas limit', async (t) => { const suite = setup() @@ -98,7 +112,7 @@ tape('should fail when tx gas limit higher than block gas limit', async (t) => { await suite.p.generateCanonicalGenesis() - await suite.p.runBlock({ block, root: genesis.header.stateRoot }) + await suite.p.runBlock({ block, root: genesis.header.stateRoot, skipBlockValidation: true }) .then(() => t.fail('should have returned error')) .catch((e) => t.ok(e.message.includes('higher gas limit'))) @@ -122,7 +136,9 @@ tape('should fail when runCall fails', async (t) => { // which always returns an error. // runTx is a full implementation that works. suite.vm.runTx = runTx - await suite.p.runBlock({ block, root: suite.vm.stateManager._trie.root }) + + await suite.p.runBlock({ block, root: suite.vm.stateManager._trie.root, skipBlockValidation: true }) + .then(() => t.fail('should have returned error')) .catch((e) => t.equal(e.message, 'test')) @@ -145,7 +161,8 @@ tape('should run valid block', async (t) => { 'genesis state root should match calculated state root' ) - let res = await suite.p.runBlock({ block, root: suite.vm.stateManager._trie.root }) + let res = await suite.p.runBlock({ block, root: suite.vm.stateManager._trie.root, skipBlockValidation: true }) + t.error(res.error, 'runBlock shouldn\'t have returned error') t.equal(res.results[0].gasUsed.toString('hex'), '5208', 'actual gas used should equal blockHeader gasUsed')