From 492c05c3788a3aefdc9e95c06dbc880784c6592c Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Mon, 3 Jul 2017 17:28:36 -0700 Subject: [PATCH] coinview: refactor api. --- lib/blockchain/chain.js | 12 +-- lib/blockchain/chaindb.js | 20 ++-- lib/coins/coinview.js | 195 +++++++++++++++++++++++------------- lib/mempool/mempool.js | 4 +- lib/mempool/mempoolentry.js | 4 +- lib/primitives/mtx.js | 16 +-- lib/primitives/tx.js | 44 ++++---- test/coins-test.js | 2 +- test/tx-test.js | 4 +- test/util/memwallet.js | 2 +- test/wallet-test.js | 2 +- 11 files changed, 181 insertions(+), 124 deletions(-) diff --git a/lib/blockchain/chain.js b/lib/blockchain/chain.js index 70e745d7..f4c19621 100644 --- a/lib/blockchain/chain.js +++ b/lib/blockchain/chain.js @@ -2325,19 +2325,19 @@ Chain.prototype.getLocks = async function getLocks(prev, tx, view, flags) { if (tx.isCoinbase() || tx.version < 2 || !hasFlag) return [minHeight, minTime]; - for (let input of tx.inputs) { + for (let {prevout, sequence} of tx.inputs) { let height, time, entry; - if (input.sequence & disableFlag) + if (sequence & disableFlag) continue; - height = view.getHeight(input); + height = view.getHeight(prevout); if (height === -1) height = this.height + 1; - if ((input.sequence & typeFlag) === 0) { - height += (input.sequence & mask) - 1; + if ((sequence & typeFlag) === 0) { + height += (sequence & mask) - 1; minHeight = Math.max(minHeight, height); continue; } @@ -2347,7 +2347,7 @@ Chain.prototype.getLocks = async function getLocks(prev, tx, view, flags) { assert(entry, 'Database is corrupt.'); time = await entry.getMedianTime(); - time += ((input.sequence & mask) << granularity) - 1; + time += ((sequence & mask) << granularity) - 1; minTime = Math.max(minTime, time); } diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index 60019eb6..59b6691e 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -1728,8 +1728,8 @@ ChainDB.prototype.connectBlock = async function connectBlock(entry, block, view) let tx = block.txs[i]; if (i > 0) { - for (let input of tx.inputs) - this.pending.spend(view.getOutput(input)); + for (let {prevout} of tx.inputs) + this.pending.spend(view.getOutput(prevout)); } for (let output of tx.outputs) { @@ -1780,9 +1780,9 @@ ChainDB.prototype.disconnectBlock = async function disconnectBlock(entry, block) if (i > 0) { for (let j = tx.inputs.length - 1; j >= 0; j--) { - let input = tx.inputs[j]; - undo.apply(view, input.prevout); - this.pending.add(view.getOutput(input)); + let {prevout} = tx.inputs[j]; + undo.apply(view, prevout); + this.pending.add(view.getOutput(prevout)); } } @@ -1884,9 +1884,8 @@ ChainDB.prototype.indexTX = function indexTX(tx, view, entry, index) { return; if (!tx.isCoinbase()) { - for (let input of tx.inputs) { - let prevout = input.prevout; - let addr = view.getOutput(input).getHash(); + for (let {prevout} of tx.inputs) { + let addr = view.getOutput(prevout).getHash(); if (!addr) continue; @@ -1929,9 +1928,8 @@ ChainDB.prototype.unindexTX = function unindexTX(tx, view) { return; if (!tx.isCoinbase()) { - for (let input of tx.inputs) { - let prevout = input.prevout; - let addr = view.getOutput(input).getHash(); + for (let {prevout} of tx.inputs) { + let addr = view.getOutput(prevout).getHash(); if (!addr) continue; diff --git a/lib/coins/coinview.js b/lib/coins/coinview.js index ae6a428b..f71b590d 100644 --- a/lib/coins/coinview.js +++ b/lib/coins/coinview.js @@ -205,73 +205,73 @@ CoinView.prototype.removeOutput = function removeOutput(prevout) { }; /** - * Get a single entry by input. - * @param {Input} input - * @returns {CoinEntry} - */ - -CoinView.prototype.getEntry = function getEntry(input) { - let coins = this.get(input.prevout.hash); - - if (!coins) - return; - - return coins.get(input.prevout.index); -}; - -/** - * Get a single coin by input. - * @param {Input} input - * @returns {Coin} - */ - -CoinView.prototype.getCoin = function getCoin(input) { - let coins = this.get(input.prevout.hash); - - if (!coins) - return; - - return coins.getCoin(input.prevout); -}; - -/** - * Get a single output by input. - * @param {Input} input - * @returns {Output} - */ - -CoinView.prototype.getOutput = function getOutput(input) { - let coins = this.get(input.prevout.hash); - - if (!coins) - return; - - return coins.getOutput(input.prevout.index); -}; - -/** - * Test whether the view has an entry by input. - * @param {Input} input + * Test whether the view has an entry by prevout. + * @param {Outpoint} prevout * @returns {Boolean} */ -CoinView.prototype.hasEntry = function hasEntry(input) { - let coins = this.get(input.prevout.hash); +CoinView.prototype.hasEntry = function hasEntry(prevout) { + let coins = this.get(prevout.hash); if (!coins) return false; - return coins.has(input.prevout.index); + return coins.has(prevout.index); }; /** - * Get coins height by input. - * @param {Input} input + * Get a single entry by input. + * @param {Outpoint} prevout + * @returns {CoinEntry} + */ + +CoinView.prototype.getEntry = function getEntry(prevout) { + let coins = this.get(prevout.hash); + + if (!coins) + return; + + return coins.get(prevout.index); +}; + +/** + * Get a single coin by prevout. + * @param {Outpoint} prevout + * @returns {Coin} + */ + +CoinView.prototype.getCoin = function getCoin(prevout) { + let coins = this.get(prevout.hash); + + if (!coins) + return; + + return coins.getCoin(prevout); +}; + +/** + * Get a single output by prevout. + * @param {Outpoint} prevout + * @returns {Output} + */ + +CoinView.prototype.getOutput = function getOutput(prevout) { + let coins = this.get(prevout.hash); + + if (!coins) + return; + + return coins.getOutput(prevout.index); +}; + +/** + * Get coins height by prevout. + * @param {Outpoint} prevout * @returns {Number} */ -CoinView.prototype.getHeight = function getHeight(input) { - let coin = this.getEntry(input); +CoinView.prototype.getHeight = function getHeight(prevout) { + let coin = this.getEntry(prevout); if (!coin) return -1; @@ -280,13 +280,13 @@ CoinView.prototype.getHeight = function getHeight(input) { }; /** - * Get coins coinbase flag by input. - * @param {Input} input + * Get coins coinbase flag by prevout. + * @param {Outpoint} prevout * @returns {Boolean} */ -CoinView.prototype.isCoinbase = function isCoinbase(input) { - let coin = this.getEntry(input); +CoinView.prototype.isCoinbase = function isCoinbase(prevout) { + let coin = this.getEntry(prevout); if (!coin) return false; @@ -294,17 +294,76 @@ CoinView.prototype.isCoinbase = function isCoinbase(input) { return coin.coinbase; }; +/** + * Test whether the view has an entry by input. + * @param {Input} input + * @returns {Boolean} + */ + +CoinView.prototype.hasEntryFor = function hasEntryFor(input) { + return this.hasEntry(input.prevout); +}; + +/** + * Get a single entry by input. + * @param {Input} input + * @returns {CoinEntry} + */ + +CoinView.prototype.getEntryFor = function getEntryFor(input) { + return this.getEntry(input.prevout); +}; + +/** + * Get a single coin by input. + * @param {Input} input + * @returns {Coin} + */ + +CoinView.prototype.getCoinFor = function getCoinFor(input) { + return this.getCoin(input.prevout); +}; + +/** + * Get a single output by input. + * @param {Input} input + * @returns {Output} + */ + +CoinView.prototype.getOutputFor = function getOutputFor(input) { + return this.getOutput(input.prevout); +}; + +/** + * Get coins height by input. + * @param {Input} input + * @returns {Number} + */ + +CoinView.prototype.getHeightFor = function getHeightFor(input) { + return this.getHeight(input.prevout); +}; + +/** + * Get coins coinbase flag by input. + * @param {Input} input + * @returns {Boolean} + */ + +CoinView.prototype.isCoinbaseFor = function isCoinbaseFor(input) { + return this.isCoinbase(input.prevout); +}; + /** * Retrieve coins from database. * @method * @param {ChainDB} db - * @param {Input} input + * @param {Outpoint} prevout * @returns {Promise} - Returns {@link Coins}. */ -CoinView.prototype.readCoin = async function readCoin(db, input) { - let coin = this.getEntry(input); - let prevout = input.prevout; +CoinView.prototype.readCoin = async function readCoin(db, prevout) { + let coin = this.getEntry(prevout); if (coin) return coin; @@ -330,8 +389,8 @@ CoinView.prototype.readCoin = async function readCoin(db, input) { CoinView.prototype.readInputs = async function readInputs(db, tx) { let found = true; - for (let input of tx.inputs) { - if (!(await this.readCoin(db, input))) + for (let {prevout} of tx.inputs) { + if (!(await this.readCoin(db, prevout))) found = false; } @@ -351,8 +410,8 @@ CoinView.prototype.spendInputs = async function spendInputs(db, tx) { let jobs = []; let coins; - for (let input of tx.inputs) - jobs.push(this.readCoin(db, input)); + for (let {prevout} of tx.inputs) + jobs.push(this.readCoin(db, prevout)); coins = await Promise.all(jobs); @@ -367,8 +426,8 @@ CoinView.prototype.spendInputs = async function spendInputs(db, tx) { return true; } - for (let input of tx.inputs) { - let coin = await this.readCoin(db, input); + for (let {prevout} of tx.inputs) { + let coin = await this.readCoin(db, prevout); if (!coin || coin.spent) return false; diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index ec107791..384fbc7a 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -1691,8 +1691,8 @@ Mempool.prototype.getCoinView = async function getCoinView(tx) { Mempool.prototype.findMissing = function findMissing(tx, view) { let missing = []; - for (let input of tx.inputs) { - if (view.hasEntry(input)) + for (let {prevout} of tx.inputs) { + if (view.hasEntry(prevout)) continue; missing.push(input.prevout.hash); diff --git a/lib/mempool/mempoolentry.js b/lib/mempool/mempoolentry.js index 043fab57..b1a866b0 100644 --- a/lib/mempool/mempoolentry.js +++ b/lib/mempool/mempoolentry.js @@ -99,8 +99,8 @@ MempoolEntry.prototype.fromTX = function fromTX(tx, view, height) { let fee = tx.getFee(view); let dependencies = false; - for (let input of tx.inputs) { - if (view.getHeight(input) === -1) { + for (let {prevout} of tx.inputs) { + if (view.getHeight(prevout) === -1) { dependencies = true; break; } diff --git a/lib/primitives/mtx.js b/lib/primitives/mtx.js index e1716953..fa3dcb77 100644 --- a/lib/primitives/mtx.js +++ b/lib/primitives/mtx.js @@ -841,8 +841,8 @@ MTX.prototype.signVector = function signVector(prev, vector, sig, ring) { MTX.prototype.isSigned = function isSigned() { for (let i = 0; i < this.inputs.length; i++) { - let input = this.inputs[i]; - let coin = this.view.getOutput(input); + let {prevout} = this.inputs[i]; + let coin = this.view.getOutput(prevout); if (!coin) return false; @@ -963,8 +963,8 @@ MTX.prototype.template = function template(ring) { } for (let i = 0; i < this.inputs.length; i++) { - let input = this.inputs[i]; - let coin = this.view.getOutput(input); + let {prevout} = this.inputs[i]; + let coin = this.view.getOutput(prevout); if (!coin) continue; @@ -1002,8 +1002,8 @@ MTX.prototype.sign = function sign(ring, type) { assert(ring.privateKey, 'No private key available.'); for (let i = 0; i < this.inputs.length; i++) { - let input = this.inputs[i]; - let coin = this.view.getOutput(input); + let {prevout} = this.inputs[i]; + let coin = this.view.getOutput(prevout); if (!coin) continue; @@ -1064,8 +1064,8 @@ MTX.prototype.estimateSize = async function estimateSize(estimate) { total += 4; // Add size for signatures and public keys - for (let input of this.inputs) { - let coin = this.view.getOutput(input); + for (let {prevout} of this.inputs) { + let coin = this.view.getOutput(prevout); let size = 0; let prev; diff --git a/lib/primitives/tx.js b/lib/primitives/tx.js index aad294b4..a88e92d1 100644 --- a/lib/primitives/tx.js +++ b/lib/primitives/tx.js @@ -770,8 +770,8 @@ TX.prototype.check = function check(view, flags) { return; for (let i = 0; i < this.inputs.length; i++) { - let input = this.inputs[i]; - let coin = view.getOutput(input); + let {prevout} = this.inputs[i]; + let coin = view.getOutput(prevout); if (!coin) throw new ScriptError('UNKNOWN_ERROR', 'No coin available.'); @@ -979,8 +979,8 @@ TX.prototype.getFee = function getFee(view) { TX.prototype.getInputValue = function getInputValue(view) { let total = 0; - for (let input of this.inputs) { - let coin = view.getOutput(input); + for (let {prevout} of this.inputs) { + let coin = view.getOutput(prevout); if (!coin) return 0; @@ -1020,7 +1020,7 @@ TX.prototype._getInputAddresses = function getInputAddresses(view) { return [addrs, table]; for (let input of this.inputs) { - let coin = view ? view.getOutput(input) : null; + let coin = view ? view.getOutputFor(input) : null; let addr = input.getAddress(coin); let hash; @@ -1200,8 +1200,8 @@ TX.prototype.hasCoins = function hasCoins(view) { if (this.inputs.length === 0) return false; - for (let input of this.inputs) { - if (!view.hasEntry(input)) + for (let {prevout} of this.inputs) { + if (!view.hasEntry(prevout)) return false; } @@ -1342,7 +1342,7 @@ TX.prototype.getScripthashSigops = function getScripthashSigops(view) { return 0; for (let input of this.inputs) { - let coin = view.getOutput(input); + let coin = view.getOutputFor(input); if (!coin) continue; @@ -1380,7 +1380,7 @@ TX.prototype.getSigopsCost = function getSigopsCost(view, flags) { return cost; for (let input of this.inputs) { - let coin = view.getOutput(input); + let coin = view.getOutputFor(input); if (!coin) continue; @@ -1547,7 +1547,7 @@ TX.prototype.hasStandardInputs = function hasStandardInputs(view) { return true; for (let input of this.inputs) { - let coin = view.getOutput(input); + let coin = view.getOutputFor(input); if (!coin) return false; @@ -1587,7 +1587,7 @@ TX.prototype.hasStandardWitness = function hasStandardWitness(view) { for (let input of this.inputs) { let witness = input.witness; - let coin = view.getOutput(input); + let coin = view.getOutputFor(input); let prev; if (!coin) @@ -1730,8 +1730,8 @@ TX.prototype.checkInputs = function checkInputs(view, height) { assert(typeof height === 'number'); - for (let input of this.inputs) { - let coin = view.getEntry(input); + for (let {prevout} of this.inputs) { + let coin = view.getEntry(prevout); if (!coin) return [-1, 'bad-txns-inputs-missingorspent', 0]; @@ -1741,7 +1741,7 @@ TX.prototype.checkInputs = function checkInputs(view, height) { return [-1, 'bad-txns-premature-spend-of-coinbase', 0]; } - coin = view.getOutput(input); + coin = view.getOutput(prevout); assert(coin); if (coin.value < 0 || coin.value > consensus.MAX_MONEY) @@ -1813,14 +1813,14 @@ TX.prototype.getPriority = function getPriority(view, height, size) { if (size == null) size = this.getVirtualSize(); - for (let input of this.inputs) { - let coin = view.getOutput(input); + for (let {prevout} of this.inputs) { + let coin = view.getOutput(prevout); let coinHeight; if (!coin) continue; - coinHeight = view.getHeight(input); + coinHeight = view.getHeight(prevout); if (coinHeight === -1) continue; @@ -1846,14 +1846,14 @@ TX.prototype.getChainValue = function getChainValue(view) { if (this.isCoinbase()) return value; - for (let input of this.inputs) { - let coin = view.getOutput(input); + for (let {prevout} of this.inputs) { + let coin = view.getOutput(prevout); let coinHeight; if (!coin) continue; - coinHeight = view.getHeight(input); + coinHeight = view.getHeight(prevout); if (coinHeight === -1) continue; @@ -2118,7 +2118,7 @@ TX.prototype.format = function format(view, entry, index) { version: this.version, flag: this.flag, inputs: this.inputs.map((input) => { - let coin = view ? view.getOutput(input) : null; + let coin = view ? view.getOutputFor(input) : null; return input.format(coin); }), outputs: this.outputs, @@ -2183,7 +2183,7 @@ TX.prototype.getJSON = function getJSON(network, view, entry, index) { version: this.version, flag: this.flag, inputs: this.inputs.map((input) => { - let coin = view ? view.getCoin(input) : null; + let coin = view ? view.getCoinFor(input) : null; return input.getJSON(network, coin); }), outputs: this.outputs.map((output) => { diff --git a/test/coins-test.js b/test/coins-test.js index 7d4c1468..f55d208b 100644 --- a/test/coins-test.js +++ b/test/coins-test.js @@ -51,7 +51,7 @@ describe('Coins', function() { assert(entry.output instanceof Output); assert.equal(entry.spent, false); - output = view.getOutput(input); + output = view.getOutputFor(input); assert(output); deepCoinsEqual(entry, reserialize(entry)); diff --git a/test/tx-test.js b/test/tx-test.js index 3db8bba3..0f874eae 100644 --- a/test/tx-test.js +++ b/test/tx-test.js @@ -77,7 +77,7 @@ function parseTest(data) { view.addCoin(coin); } - coin = view.getOutput(tx.inputs[0]); + coin = view.getOutputFor(tx.inputs[0]); return { tx: tx, @@ -204,7 +204,7 @@ describe('TX', function() { }); it(`should verify high S value with only DERSIG enabled ${suffix}`, () => { - let coin = tx4.view.getOutput(tx4.tx.inputs[0]); + let coin = tx4.view.getOutputFor(tx4.tx.inputs[0]); let flags = Script.flags.VERIFY_P2SH | Script.flags.VERIFY_DERSIG; clearCache(tx4.tx, noCache); assert(tx4.tx.verifyInput(0, coin, flags)); diff --git a/test/util/memwallet.js b/test/util/memwallet.js index a3bdc1a2..486ed43f 100644 --- a/test/util/memwallet.js +++ b/test/util/memwallet.js @@ -339,7 +339,7 @@ MemWallet.prototype.deriveInputs = function deriveInputs(mtx) { for (i = 0; i < mtx.inputs.length; i++) { input = mtx.inputs[i]; - coin = mtx.view.getOutput(input); + coin = mtx.view.getOutputFor(input); if (!coin) continue; diff --git a/test/wallet-test.js b/test/wallet-test.js index ec9c2155..bf12536a 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -1067,7 +1067,7 @@ describe('Wallet', function() { found = false; for (i = 0; i < t3.inputs.length; i++) { - coin = t3.view.getCoin(t3.inputs[i]); + coin = t3.view.getCoinFor(t3.inputs[i]); if (coin.height === -1) { assert(!found); assert(coin.value < 5460);