From 727ad2ff501bd1b0460bd477e982de809fbb02d3 Mon Sep 17 00:00:00 2001 From: Cofresi Date: Fri, 31 May 2019 11:53:21 -0400 Subject: [PATCH] Fix and speed up addHeaders() (#21) * add test section for adding testnet headers * add testnet tests * update dark gravity wave * reactivate mainnet headers * reactivate mainnet headers * update dark-gravity-wave * bump version * update package lock * remove bn.js from deps * bump patch version * update eslint-plugin-import dep * update package lock * revert superfluous bump * update package lock * simplify validation for header chunks * disable some tests for quicker testing * disable blockstore tests * add fn getTipHeader() * add fn appendHeaderToLongestChain() * reactivate blockstore tests * disable eslint no-param-reassign * break reduce function on bad header * bump version * update package lock * refactor to prepare for orphan chunks * refactor & fix --- lib/spvchain.js | 64 ++++++++++++++++++++++++++++++++++++++++++----- package-lock.json | 8 +++--- package.json | 2 +- 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/lib/spvchain.js b/lib/spvchain.js index 6172eb9..9cf1d40 100644 --- a/lib/spvchain.js +++ b/lib/spvchain.js @@ -8,6 +8,7 @@ const SpvChain = class { this.root = null; this.allBranches = []; this.orphanBlocks = []; + this.orphanChunks = []; this.confirmsBeforeFinal = confirms; this.init(chainType, startBlock); this.store = new BlockStore(); @@ -87,6 +88,10 @@ const SpvChain = class { return this.getLongestChain().slice(-1)[0].hash; } + getTipHeader() { + return this.getLongestChain().slice(-1)[0]; + } + getHeader(hash) { return this.store.get(hash) .then((blockInDB) => { @@ -123,6 +128,12 @@ const SpvChain = class { } } + appendHeadersToLongestChain(headers) { + const newLongestChain = this.getLongestChain().concat(headers); + this.allBranches = []; + this.allBranches.push(newLongestChain); + } + getAllBranches() { return this.allBranches; } @@ -160,8 +171,7 @@ const SpvChain = class { addHeader(header) { const headerNormalised = utils.normalizeHeader(header); - if (Consensus.isValidBlockHeader(headerNormalised, this.getLongestChain(), this.network) - && !this.isDuplicate(headerNormalised.hash)) { + if (this.isValid(headerNormalised, this.getLongestChain())) { headerNormalised.children = []; this.processValidHeader(headerNormalised); this.setAllBranches(); @@ -171,15 +181,57 @@ const SpvChain = class { return false; } + /* eslint-disable no-param-reassign */ + static isParentChild(header, previousHeader) { + if (utils.getCorrectedHash(header.prevHash) !== previousHeader.hash) { + return false; + } + if (!header.children) { + header.children = []; + } + if (!previousHeader.children) { + previousHeader.children = []; + } + previousHeader.children.push(header); + return true; + } + /* eslint-enable no-param-reassign */ + + isValid(header, previousHeaders) { + return !!(Consensus.isValidBlockHeader(header, previousHeaders, this.network) + && !this.isDuplicate(header.hash)); + } + addHeaders(headers) { const self = this; - const allAdded = headers.reduce( - (acc, header) => acc && self.addHeader(header, this.network), true, + const normalizedHeaders = headers.map(h => utils.normalizeHeader(h)); + const isOrphan = !SpvChain.isParentChild(normalizedHeaders[0], this.getTipHeader()); + + const allValid = normalizedHeaders.reduce( + (acc, header, index, array) => { + const previousHeaders = normalizedHeaders.slice(0, index); + if (index !== 0) { + if (!SpvChain.isParentChild(header, array[index - 1]) + || !self.isValid(header, previousHeaders)) { + throw new Error('Some headers are invalid'); + } + return acc && true; + } + if (!self.isValid(header, self.getLongestChain())) { + throw new Error('Some headers are invalid'); + } + return acc && true; + }, true, ); - - if (!allAdded) { + if (!allValid) { throw new Error('Some headers are invalid'); } + if (isOrphan) { + this.orphanChunks.push(headers); + } else { + self.appendHeadersToLongestChain(normalizedHeaders); + } + this.checkPruneBlocks(); } }; diff --git a/package-lock.json b/package-lock.json index bb54f2e..d14c59f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dash-spv", - "version": "1.1.3", + "version": "1.1.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1427,9 +1427,9 @@ } }, "readable-stream": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", - "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", diff --git a/package.json b/package.json index a193f40..271f787 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dash-spv", - "version": "1.1.3", + "version": "1.1.4", "description": "Temporary repo until spv functions moved into dashcore-lib", "main": "index.js", "scripts": {