From ed06c2184ddb18836664c0119e139b0643376269 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 23 Apr 2019 15:55:56 -0700 Subject: [PATCH] indexer: check that blocks are connected There was a rare case that a block could be incorrectly added to the indexer if the indexer was disabled during a reorg to a height that matched the height that was expected, and the `sync` method for the indexer wasn't called that would detect the reorg. --- lib/indexer/indexer.js | 11 ++++ test/indexer-test.js | 116 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/lib/indexer/indexer.js b/lib/indexer/indexer.js index 11187771..0628a641 100644 --- a/lib/indexer/indexer.js +++ b/lib/indexer/indexer.js @@ -286,9 +286,20 @@ class Indexer extends EventEmitter { // instead of reading that information again. if (meta && block && view) { if (meta.height === this.height + 1) { + // Make sure that the block is connected to + // the indexer chain. + const prev = await this.getBlockMeta(this.height); + if (prev.hash.compare(block.prevBlock) !== 0) + return false; + await this._addBlock(meta, block, view); return true; } else if (meta.height === this.height) { + // Make sure that this is the current block. + const current = await this.getBlockMeta(this.height); + if (current.hash.compare(block.hash()) !== 0) + return false; + await this._removeBlock(meta, block, view); return true; } diff --git a/test/indexer-test.js b/test/indexer-test.js index 61b9acb5..a05dc8c2 100644 --- a/test/indexer-test.js +++ b/test/indexer-test.js @@ -119,6 +119,122 @@ describe('Indexer', function() { }); describe('Unit', function() { + it('should connect block', async () => { + const indexer = new AddrIndexer({ + blocks: {}, + chain: {} + }); + + indexer.height = 9; + + indexer.getBlockMeta = (height) => { + return { + hash: Buffer.alloc(32, 0x00), + height: height + }; + }; + + let called = false; + indexer._addBlock = async () => { + called = true; + }; + + const meta = {height: 10}; + const block = {prevBlock: Buffer.alloc(32, 0x00)}; + const view = {}; + + const connected = await indexer._syncBlock(meta, block, view); + assert.equal(connected, true); + assert.equal(called, true); + }); + + it('should not connect block', async () => { + const indexer = new AddrIndexer({ + blocks: {}, + chain: {} + }); + + indexer.height = 9; + + indexer.getBlockMeta = (height) => { + return { + hash: Buffer.alloc(32, 0x02), + height: height + }; + }; + + let called = false; + indexer._addBlock = async () => { + called = true; + }; + + const meta = {height: 10}; + const block = {prevBlock: Buffer.alloc(32, 0x01)}; + const view = {}; + + const connected = await indexer._syncBlock(meta, block, view); + assert.equal(connected, false); + assert.equal(called, false); + }); + + it('should disconnect block', async () => { + const indexer = new AddrIndexer({ + blocks: {}, + chain: {} + }); + + indexer.height = 9; + + indexer.getBlockMeta = (height) => { + return { + hash: Buffer.alloc(32, 0x00), + height: height + }; + }; + + let called = false; + indexer._removeBlock = async () => { + called = true; + }; + + const meta = {height: 9}; + const block = {hash: () => Buffer.alloc(32, 0x00)}; + const view = {}; + + const connected = await indexer._syncBlock(meta, block, view); + assert.equal(connected, true); + assert.equal(called, true); + }); + + it('should not disconnect block', async () => { + const indexer = new AddrIndexer({ + blocks: {}, + chain: {} + }); + + indexer.height = 9; + + indexer.getBlockMeta = (height) => { + return { + hash: Buffer.alloc(32, 0x01), + height: height + }; + }; + + let called = false; + indexer._removeBlock = async () => { + called = true; + }; + + const meta = {height: 9}; + const block = {hash: () => Buffer.alloc(32, 0x02)}; + const view = {}; + + const connected = await indexer._syncBlock(meta, block, view); + assert.equal(connected, false); + assert.equal(called, false); + }); + it('should not index transaction w/ invalid address', async () => { const indexer = new AddrIndexer({ blocks: {},