diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index 79d87785..9e538f6e 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -242,6 +242,49 @@ Chain.prototype.verifyContext = co(function* verifyContext(block, prev) { return new ContextResult(view, state); }); +/** + * Perform all necessary contextual verification + * on a block, without POW check. + * @method + * @param {Block} block + * @returns {Promise} + */ + +Chain.prototype.verifyBlock = co(function* verifyBlock(block) { + var unlock = yield this.locker.lock(); + try { + return yield this._verifyBlock(block); + } finally { + unlock(); + } +}); + +/** + * Perform all necessary contextual verification + * on a block, without POW check (no lock). + * @method + * @private + * @param {Block} block + * @returns {Promise} + */ + +Chain.prototype._verifyBlock = co(function* verifyBlock(block) { + var valid = block._validHeaders; + var result; + + if (block.prevBlock !== this.tip.hash) + throw new VerifyError(block, 'invalid', 'bad-prevblk', 0); + + try { + block._validHeaders = true; + result = yield this.verifyContext(block, this.tip); + } finally { + block._validHeaders = valid; + } + + return result; +}); + /** * Test whether a block is the genesis block. * @param {Block} block diff --git a/lib/http/rpc.js b/lib/http/rpc.js index 4a16dc99..45a98717 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -136,6 +136,8 @@ RPC.prototype.execute = function execute(json) { return this.getblocktemplate(json.params); case 'submitblock': return this.submitblock(json.params); + case 'verifyblock': + return this.verifyblock(json.params); case 'setgenerate': return this.setgenerate(json.params); @@ -1953,6 +1955,31 @@ RPC.prototype._hashps = co(function* _hashps(lookup, height) { return ps; }); +RPC.prototype.verifyblock = co(function* verifyblock(args) { + var block; + + if (args.help || args.length !== 1) + throw new RPCError('verifyblock "block-hex"'); + + if (typeof args[0] !== 'string') + throw new RPCError('Invalid parameters.'); + + if (this.chain.options.spv) + throw new RPCError('Cannot verify block in SPV mode.'); + + block = Block.fromRaw(args[0], 'hex'); + + try { + yield this.chain.verifyBlock(block); + } catch (e) { + if (e.type === 'VerifyError') + return e.reason; + throw e; + } + + return null; +}); + /* * Coin generation */