diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index 39bffa6b..8fd2052e 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -9,6 +9,8 @@ var AsyncObject = require('../utils/async'); var constants = require('../protocol/constants'); var util = require('../utils/util'); +var BufferReader = require('../utils/reader'); +var BufferWriter = require('../utils/writer'); var co = require('../utils/co'); var assert = require('assert'); var crypto = require('../crypto/crypto'); @@ -22,6 +24,7 @@ var Coin = require('../primitives/coin'); var Locker = require('../utils/locker'); var Outpoint = require('../primitives/outpoint'); var TX = require('../primitives/tx'); +var Coin = require('../primitives/coin'); var MempoolEntry = require('./mempoolentry'); /** @@ -1310,7 +1313,7 @@ Mempool.prototype.storeOrphan = function storeOrphan(tx) { this.waiting[prev].push(hash); } - this.orphans[hash] = tx.toExtended(true); + this.orphans[hash] = toOrphanRaw(tx); this.totalOrphans++; this.logger.debug('Added orphan %s to mempool.', tx.txid()); @@ -1389,7 +1392,7 @@ Mempool.prototype.getOrphan = function getOrphan(hash) { return; try { - orphan = TX.fromExtended(data, true); + orphan = fromOrphanRaw(data); } catch (e) { delete this.orphans[hash]; this.logger.warning('%s %s', @@ -1444,7 +1447,7 @@ Mempool.prototype.resolveOrphans = function resolveOrphans(tx) { continue; } - this.orphans[orphanHash] = orphan.toExtended(true); + this.orphans[orphanHash] = toOrphanRaw(orphan); } delete this.waiting[hash]; @@ -1981,6 +1984,53 @@ AddressIndex.prototype.removeCoin = function removeCoin(coin) { delete this.map[key]; }; +/* + * Helpers + */ + +function toOrphanRaw(tx) { + var bw = new BufferWriter(); + var i, input; + + tx.toWriter(bw); + + for (i = 0; i < tx.inputs.length; i++) { + input = tx.inputs[i]; + + if (!input.coin) { + bw.writeU8(0); + continue; + } + + bw.writeU8(1); + input.coin.toWriter(bw); + } + + return bw.render(); +}; + +function fromOrphanRaw(data) { + var br = new BufferReader(data); + var i, tx, input, coin; + + tx = TX.fromReader(br); + + for (i = 0; i < tx.inputs.length; i++) { + input = tx.inputs[i]; + + if (br.readU8() === 0) + continue; + + coin = Coin.fromReader(br); + coin.hash = input.prevout.hash; + coin.index = input.prevout.index; + + input.coin = coin; + } + + return tx; +} + /* * Expose */ diff --git a/lib/primitives/tx.js b/lib/primitives/tx.js index 03a4196c..d2dcb134 100644 --- a/lib/primitives/tx.js +++ b/lib/primitives/tx.js @@ -2435,17 +2435,20 @@ TX.isWitness = function isWitness(br) { * This is the serialization format BCoin uses internally * to store transactions in the database. The extended * serialization includes the height, block hash, index, - * timestamp, pending-since time, and optionally a vector - * for the serialized coins. - * @param {Boolean?} saveCoins - Whether to serialize the coins. + * timestamp, and pending-since time. * @returns {Buffer} */ -TX.prototype.toExtended = function toExtended(saveCoins) { +TX.prototype.toExtended = function toExtended() { var bw = new BufferWriter(); var height = this.height; var index = this.index; - var i, input, field, bit, oct; + + if (height === -1) + height = 0x7fffffff; + + if (index === -1) + index = 0x7fffffff; this.toWriter(bw); @@ -2458,49 +2461,21 @@ TX.prototype.toExtended = function toExtended(saveCoins) { bw.writeU8(0); } - if (height === -1) - height = 0x7fffffff; - - if (index === -1) - index = 0x7fffffff; - bw.writeU32(height); bw.writeU32(this.ts); bw.writeU32(index); - if (saveCoins) { - field = new Buffer(Math.ceil(this.inputs.length / 8)); - field.fill(0); - - bw.writeBytes(field); - - for (i = 0; i < this.inputs.length; i++) { - input = this.inputs[i]; - - if (!input.coin) { - bit = i % 8; - oct = (i - bit) / 8; - field[oct] |= 1 << (7 - bit); - continue; - } - - input.coin.toWriter(bw); - } - } - return bw.render(); }; /** * Inject properties from "extended" serialization format. + * @private * @param {Buffer} data - * @param {Boolean?} saveCoins - If true, the function will - * attempt to parse the coins. */ -TX.prototype.fromExtended = function fromExtended(data, saveCoins) { +TX.prototype.fromExtended = function fromExtended(data) { var br = new BufferReader(data); - var i, input, coin, field, bit, oct, spent; this.fromReader(br); @@ -2519,27 +2494,6 @@ TX.prototype.fromExtended = function fromExtended(data, saveCoins) { if (this.index === 0x7fffffff) this.index = -1; - if (saveCoins) { - field = br.readBytes(Math.ceil(this.inputs.length / 8), true); - - for (i = 0; i < this.inputs.length; i++) { - input = this.inputs[i]; - - bit = i % 8; - oct = (i - bit) / 8; - spent = (field[oct] >>> (7 - bit)) & 1; - - if (spent) - continue; - - coin = Coin.fromReader(br); - coin.hash = input.prevout.hash; - coin.index = input.prevout.index; - - input.coin = coin; - } - } - return this; }; @@ -2547,22 +2501,14 @@ TX.prototype.fromExtended = function fromExtended(data, saveCoins) { * Instantiate a transaction from a Buffer * in "extended" serialization format. * @param {Buffer} data - * @param {Boolean?} saveCoins - If true, the function will - * attempt to parse the coins. * @param {String?} enc - One of `"hex"` or `null`. * @returns {TX} */ -TX.fromExtended = function fromExtended(data, saveCoins, enc) { - if (typeof saveCoins === 'string') { - enc = saveCoins; - saveCoins = false; - } - +TX.fromExtended = function fromExtended(data, enc) { if (typeof data === 'string') data = new Buffer(data, enc); - - return new TX().fromExtended(data, saveCoins); + return new TX().fromExtended(data); }; /**