diff --git a/lib/bcoin/coins.js b/lib/bcoin/coins.js index bd897607..7849a39d 100644 --- a/lib/bcoin/coins.js +++ b/lib/bcoin/coins.js @@ -76,7 +76,14 @@ Coins.prototype.has = function has(index) { */ Coins.prototype.get = function get(index) { - return this.outputs[index]; + var coin = this.outputs[index]; + if (!coin) + return; + + if (coin instanceof DeferredCoin) + coin = coin.toCoin(this, index); + + return coin; }; /** @@ -179,6 +186,11 @@ Coins.prototype.toRaw = function toRaw(writer) { continue; } + if (output instanceof DeferredCoin) { + p.writeBytes(output.raw); + continue; + } + prefix = 0; // Saves up to 7 bytes. @@ -213,10 +225,10 @@ Coins.prototype.toRaw = function toRaw(writer) { * @returns {Object} A "naked" coins object. */ -Coins.parseRaw = function parseRaw(data, hash) { +Coins.parseRaw = function parseRaw(data, hash, index) { var p = new BufferReader(data); var i = 0; - var version, height, coins, coin, mask, prefix; + var version, height, coins, mask, prefix, raw; version = p.readVarint(); height = p.readU32(); @@ -233,43 +245,87 @@ Coins.parseRaw = function parseRaw(data, hash) { coins.height = -1; while (p.left()) { + p.start(); + mask = p.readU8(); if (mask === 0xff) { + if (index != null) { + if (i === index) + return; + i++; + continue; + } coins.outputs.push(null); i++; continue; } - coin = { - version: coins.version, - coinbase: coins.coinbase, - height: coins.height, - hash: coins.hash, - index: i++, - script: null, - value: null - }; - prefix = mask & 3; if (prefix === 0) - coin.script = new bcoin.script(bcoin.protocol.parser.parseScript(p)); - else if (prefix === 1) - coin.script = bcoin.script.createPubkeyhash(p.readBytes(20)); - else if (prefix === 2) - coin.script = bcoin.script.createScripthash(p.readBytes(20)); + p.seek(p.readVarint()); + else if (prefix <= 2) + p.seek(20); else assert(false, 'Bad prefix.'); - coin.value = p.readVarint(); + p.readVarint(); - coins.outputs.push(new bcoin.coin(coin)); + if (index != null && i !== index) { + p.end(); + i++; + continue; + } + + raw = p.endData(true); + + coins.outputs.push(new DeferredCoin(raw)); + + if (index != null) + return coins.outputs[0].toCoin(coins, i); + + i++; } return coins; }; +function DeferredCoin(raw) { + this.raw = raw; +} + +DeferredCoin.prototype.toCoin = function toCoin(coins, index) { + var p = new BufferReader(this.raw); + var prefix = p.readU8() & 3; + var script, value; + + if (prefix === 0) + script = new bcoin.script(bcoin.protocol.parser.parseScript(p)); + else if (prefix === 1) + script = bcoin.script.createPubkeyhash(p.readBytes(20)); + else if (prefix === 2) + script = bcoin.script.createScripthash(p.readBytes(20)); + else + assert(false, 'Bad prefix.'); + + value = p.readVarint(); + + return new bcoin.coin({ + version: coins.version, + coinbase: coins.coinbase, + height: coins.height, + hash: coins.hash, + index: index, + script: script, + value: value + }); +}; + +DeferredCoin.prototype.toRaw = function toRaw() { + return this.raw; +}; + /** * Parse a single serialized coin. * @param {Buffer} data @@ -279,65 +335,7 @@ Coins.parseRaw = function parseRaw(data, hash) { */ Coins.parseCoin = function parseCoin(data, hash, index) { - var p = new BufferReader(data); - var i = 0; - var mask, prefix, version, height, coinbase, script, value; - - version = p.readVarint(); - height = p.readU32(); - coinbase = (height & 1) !== 0; - height >>>= 1; - - if (height === 0x7fffffff) - height = -1; - - while (p.left()) { - mask = p.readU8(); - - if (mask === 0xff) { - if (i === index) - break; - i++; - continue; - } - - prefix = mask & 3; - - if (i !== index) { - if (prefix === 0) - p.seek(p.readVarint()); - else if (prefix <= 2) - p.seek(20); - else - assert(false, 'Bad prefix.'); - p.readVarint(); - i++; - continue; - } - - if (prefix === 0) - script = new bcoin.script(bcoin.protocol.parser.parseScript(p)); - else if (prefix === 1) - script = bcoin.script.createPubkeyhash(p.readBytes(20)); - else if (prefix === 2) - script = bcoin.script.createScripthash(p.readBytes(20)); - else - assert(false, 'Bad prefix.'); - - value = p.readVarint(); - - return new bcoin.coin({ - version: version, - coinbase: coinbase, - height: height, - hash: hash, - index: i, - script: script, - value: value - }); - } - - assert(false, 'No coin.'); + return Coins.parseCoins(data, hash, index); }; /** diff --git a/lib/bcoin/reader.js b/lib/bcoin/reader.js index 253021c8..e6ac2832 100644 --- a/lib/bcoin/reader.js +++ b/lib/bcoin/reader.js @@ -68,6 +68,7 @@ BufferReader.prototype.seek = function seek(off) { BufferReader.prototype.start = function start() { this.stack.push(this.offset); + return this.offset; }; /**