diff --git a/lib/coins/coins.js b/lib/coins/coins.js index 37c0b547..287ecfe0 100644 --- a/lib/coins/coins.js +++ b/lib/coins/coins.js @@ -13,13 +13,12 @@ const CoinEntry = require('./coinentry'); * Represents the outputs for a single transaction. * @alias module:coins.Coins * @constructor - * @property {Hash} hash - Transaction hash. - * @property {CoinEntry[]} outputs - Coins. + * @property {Map[]} outputs - Coins. */ -function Coins(options) { +function Coins() { if (!(this instanceof Coins)) - return new Coins(options); + return new Coins(); this.outputs = new Map(); } @@ -28,35 +27,39 @@ function Coins(options) { * Add a single entry to the collection. * @param {Number} index * @param {CoinEntry} coin + * @returns {CoinEntry} */ Coins.prototype.add = function add(index, coin) { assert(index >= 0); - assert(!this.outputs.has(index)); this.outputs.set(index, coin); + + return coin; }; /** * Add a single output to the collection. * @param {Number} index * @param {Output} output + * @returns {CoinEntry} */ Coins.prototype.addOutput = function addOutput(index, output) { assert(!output.script.isUnspendable()); - this.add(index, CoinEntry.fromOutput(output)); + return this.add(index, CoinEntry.fromOutput(output)); }; /** * Add a single coin to the collection. * @param {Coin} coin + * @returns {CoinEntry} */ Coins.prototype.addCoin = function addCoin(coin) { assert(!coin.script.isUnspendable()); - this.add(coin.index, CoinEntry.fromCoin(coin)); + return this.add(coin.index, CoinEntry.fromCoin(coin)); }; /** @@ -87,24 +90,24 @@ Coins.prototype.isUnspent = function isUnspent(index) { /** * Get a coin entry. * @param {Number} index - * @returns {CoinEntry} + * @returns {CoinEntry|null} */ Coins.prototype.get = function get(index) { - return this.outputs.get(index); + return this.outputs.get(index) || null; }; /** * Get an output. * @param {Number} index - * @returns {Output} + * @returns {Output|null} */ Coins.prototype.getOutput = function getOutput(index) { let coin = this.outputs.get(index); if (!coin) - return; + return null; return coin.output; }; @@ -112,14 +115,14 @@ Coins.prototype.getOutput = function getOutput(index) { /** * Get a coin. * @param {Outpoint} prevout - * @returns {Coin} + * @returns {Coin|null} */ Coins.prototype.getCoin = function getCoin(prevout) { let coin = this.outputs.get(prevout.index); if (!coin) - return; + return null; return coin.toCoin(prevout); }; @@ -127,14 +130,14 @@ Coins.prototype.getCoin = function getCoin(prevout) { /** * Spend a coin entry and return it. * @param {Number} index - * @returns {CoinEntry} + * @returns {CoinEntry|null} */ Coins.prototype.spend = function spend(index) { let coin = this.get(index); if (!coin || coin.spent) - return; + return null; coin.spent = true; @@ -144,38 +147,20 @@ Coins.prototype.spend = function spend(index) { /** * Remove a coin entry and return it. * @param {Number} index - * @returns {CoinEntry} + * @returns {CoinEntry|null} */ Coins.prototype.remove = function remove(index) { let coin = this.get(index); if (!coin) - return false; + return null; this.outputs.delete(index); return coin; }; -/** - * Calculate unspent length of coins. - * @returns {Number} - */ - -Coins.prototype.length = function length() { - let len = -1; - - for (let [index, coin] of this.outputs) { - if (!coin.spent) { - if (index > len) - len = index; - } - } - - return len + 1; -}; - /** * Test whether the coins are fully spent. * @returns {Boolean} @@ -190,6 +175,7 @@ Coins.prototype.isEmpty = function isEmpty() { * @private * @param {TX} tx * @param {Number} height + * @returns {Coins} */ Coins.prototype.fromTX = function fromTX(tx, height) { diff --git a/lib/coins/coinview.js b/lib/coins/coinview.js index 029611c7..2b30ac5f 100644 --- a/lib/coins/coinview.js +++ b/lib/coins/coinview.js @@ -51,6 +51,7 @@ CoinView.prototype.has = function has(hash) { * Add coins to the collection. * @param {Hash} hash * @param {Coins} coins + * @returns {Coins} */ CoinView.prototype.add = function add(hash, coins) { @@ -61,49 +62,55 @@ CoinView.prototype.add = function add(hash, coins) { /** * Remove coins from the collection. * @param {Coins} coins - * @returns {Boolean} + * @returns {Coins|null} */ CoinView.prototype.remove = function remove(hash) { - if (!this.map.has(hash)) - return false; + let coins = this.map.get(hash); + + if (!coins) + return null; this.map.delete(hash); - return true; + return coins; }; /** * Add a tx to the collection. * @param {TX} tx * @param {Number} height + * @returns {Coins} */ CoinView.prototype.addTX = function addTX(tx, height) { + let hash = tx.hash('hex'); let coins = Coins.fromTX(tx, height); - return this.add(tx.hash('hex'), coins); + return this.add(hash, coins); }; /** * Remove a tx from the collection. * @param {TX} tx * @param {Number} height + * @returns {Coins} */ CoinView.prototype.removeTX = function removeTX(tx, height) { + let hash = tx.hash('hex'); let coins = Coins.fromTX(tx, height); for (let coin of coins.outputs.values()) coin.spent = true; - return this.add(tx.hash('hex'), coins); + return this.add(hash, coins); }; /** * Add an entry to the collection. * @param {Outpoint} prevout * @param {CoinEntry} coin - * @returns {Coins|null} + * @returns {CoinEntry|null} */ CoinView.prototype.addEntry = function addEntry(prevout, coin) { @@ -116,17 +123,18 @@ CoinView.prototype.addEntry = function addEntry(prevout, coin) { } if (coin.output.script.isUnspendable()) - return; + return null; - if (!coins.has(index)) - coins.add(index, coin); + if (coins.has(index)) + return null; - return coins; + return coins.add(index, coin); }; /** * Add a coin to the collection. * @param {Coin} coin + * @returns {CoinEntry|null} */ CoinView.prototype.addCoin = function addCoin(coin) { @@ -139,18 +147,19 @@ CoinView.prototype.addCoin = function addCoin(coin) { } if (coin.script.isUnspendable()) - return; + return null; - if (!coins.has(index)) - coins.addCoin(coin); + if (coins.has(index)) + return null; - return coins; + return coins.addCoin(coin); }; /** * Add an output to the collection. * @param {Outpoint} prevout * @param {Output} output + * @returns {CoinEntry|null} */ CoinView.prototype.addOutput = function addOutput(prevout, output) { @@ -163,16 +172,18 @@ CoinView.prototype.addOutput = function addOutput(prevout, output) { } if (output.script.isUnspendable()) - return; + return null; - if (!coins.has(index)) - coins.addOutput(index, output); + if (coins.has(index)) + return null; + + return coins.addOutput(index, output); }; /** * Spend an output. * @param {Outpoint} prevout - * @returns {Boolean} + * @returns {CoinEntry|null} */ CoinView.prototype.spendOutput = function spendOutput(prevout) { @@ -181,22 +192,22 @@ CoinView.prototype.spendOutput = function spendOutput(prevout) { let coin; if (!coins) - return false; + return null; coin = coins.spend(index); if (!coin) - return false; + return null; this.undo.push(coin); - return true; + return coin; }; /** * Remove an output. * @param {Outpoint} prevout - * @returns {Boolean} + * @returns {CoinEntry|null} */ CoinView.prototype.removeOutput = function removeOutput(prevout) { @@ -204,7 +215,7 @@ CoinView.prototype.removeOutput = function removeOutput(prevout) { let coins = this.get(hash); if (!coins) - return false; + return null; return coins.remove(index); }; @@ -226,9 +237,9 @@ CoinView.prototype.hasEntry = function hasEntry(prevout) { }; /** - * Get a single entry by input. + * Get a single entry by prevout. * @param {Outpoint} prevout - * @returns {CoinEntry} + * @returns {CoinEntry|null} */ CoinView.prototype.getEntry = function getEntry(prevout) { @@ -236,7 +247,7 @@ CoinView.prototype.getEntry = function getEntry(prevout) { let coins = this.get(hash); if (!coins) - return; + return null; return coins.get(index); }; @@ -244,14 +255,14 @@ CoinView.prototype.getEntry = function getEntry(prevout) { /** * Get a single coin by prevout. * @param {Outpoint} prevout - * @returns {Coin} + * @returns {Coin|null} */ CoinView.prototype.getCoin = function getCoin(prevout) { let coins = this.get(prevout.hash); if (!coins) - return; + return null; return coins.getCoin(prevout); }; @@ -259,7 +270,7 @@ CoinView.prototype.getCoin = function getCoin(prevout) { /** * Get a single output by prevout. * @param {Outpoint} prevout - * @returns {Output} + * @returns {Output|null} */ CoinView.prototype.getOutput = function getOutput(prevout) { @@ -267,7 +278,7 @@ CoinView.prototype.getOutput = function getOutput(prevout) { let coins = this.get(hash); if (!coins) - return; + return null; return coins.getOutput(index); }; @@ -315,7 +326,7 @@ CoinView.prototype.hasEntryFor = function hasEntryFor(input) { /** * Get a single entry by input. * @param {Input} input - * @returns {CoinEntry} + * @returns {CoinEntry|null} */ CoinView.prototype.getEntryFor = function getEntryFor(input) { @@ -325,7 +336,7 @@ CoinView.prototype.getEntryFor = function getEntryFor(input) { /** * Get a single coin by input. * @param {Input} input - * @returns {Coin} + * @returns {Coin|null} */ CoinView.prototype.getCoinFor = function getCoinFor(input) { @@ -335,7 +346,7 @@ CoinView.prototype.getCoinFor = function getCoinFor(input) { /** * Get a single output by input. * @param {Input} input - * @returns {Output} + * @returns {Output|null} */ CoinView.prototype.getOutputFor = function getOutputFor(input) { @@ -367,7 +378,7 @@ CoinView.prototype.isCoinbaseFor = function isCoinbaseFor(input) { * @method * @param {ChainDB} db * @param {Outpoint} prevout - * @returns {Promise} - Returns {@link Coins}. + * @returns {Promise} - Returns {@link CoinEntry}. */ CoinView.prototype.readCoin = async function readCoin(db, prevout) { @@ -381,9 +392,7 @@ CoinView.prototype.readCoin = async function readCoin(db, prevout) { if (!coin) return null; - this.addEntry(prevout, coin); - - return coin; + return this.addEntry(prevout, coin); }; /** diff --git a/test/coins-test.js b/test/coins-test.js index f55d208b..9c7236bb 100644 --- a/test/coins-test.js +++ b/test/coins-test.js @@ -66,7 +66,7 @@ describe('Coins', function() { coins = view.get(hash); assert(coins); - length = coins.length(); + length = coins.outputs.size; view.spendOutput(new Outpoint(hash, 0)); @@ -78,7 +78,7 @@ describe('Coins', function() { assert(entry.spent); deepCoinsEqual(entry, reserialize(entry)); - assert.strictEqual(coins.length(), length); + assert.strictEqual(coins.outputs.size, length); assert.equal(view.undo.items.length, 1); }); @@ -102,8 +102,8 @@ describe('Coins', function() { prev = tx1.inputs[0].prevout; coins = res.get(prev.hash); - assert.strictEqual(coins.length(), 2); - assert.strictEqual(coins.get(0), undefined); + assert.strictEqual(coins.outputs.size, 1); + assert.strictEqual(coins.get(0), null); deepCoinsEqual(coins.get(1), reserialize(coins.get(1))); }); });