diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index 13995bfa..10eb7046 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -122,6 +122,32 @@ Block.prototype.getWitnessRoot = function getWitnessRoot() { return utils.toHex(root); }; +Block.prototype.__defineGetter__('witnessRoot', function() { + var coinbase, i, commitment, witnessRoot; + + if (!block.witness) + return; + + if (this._witnessRoot) + return this._witnessRoot; + + coinbase = block.txs[0]; + + // Find the fucking commitment for segregated shitness + for (i = 0; i < coinbase.outputs.length; i++) { + commitment = coinbase.outputs[i].script; + if (bcoin.script.isCommitment(commitment)) { + witnessRoot = bcoin.script.getWitnessRoot(commitment); + break; + } + } + + if (witnessRoot) + this._witnessRoot = utils.toHex(witnessRoot); + + return this._witnessRoot; +}); + Block.prototype._verify = function _verify() { var uniq = {}; var i, tx, hash; @@ -275,6 +301,7 @@ Block.prototype.inspect = function inspect() { version: this.version, prevBlock: utils.revHex(this.prevBlock), merkleRoot: utils.revHex(this.merkleRoot), + witnessRoot: utils.revHex(this.witnessRoot), ts: this.ts, bits: this.bits, nonce: this.nonce, @@ -291,6 +318,7 @@ Block.prototype.toJSON = function toJSON() { version: this.version, prevBlock: utils.revHex(this.prevBlock), merkleRoot: utils.revHex(this.merkleRoot), + witnessRoot: utils.revHex(this.witnessRoot), ts: this.ts, bits: this.bits, nonce: this.nonce, diff --git a/lib/bcoin/chain.js b/lib/bcoin/chain.js index f2d2cc44..894f8e9e 100644 --- a/lib/bcoin/chain.js +++ b/lib/bcoin/chain.js @@ -573,19 +573,10 @@ Chain.prototype._verify = function _verify(block, prev) { } } - // Find the fucking commitment for segregated shitness if (segwit && block.witness) { - coinbase = block.txs[0]; - for (i = 0; i < coinbase.outputs.length; i++) { - commitment = coinbase.outputs[i].script; - if (bcoin.script.isCommitment(commitment)) { - witnessRoot = bcoin.script.getWitnessRoot(commitment); - if (utils.toHex(witnessRoot) !== block.getWitnessRoot()) { - utils.debug('Block failed witnessroot test: %s', block.rhash); - return false; - } - break; - } + if (block.witnessRoot !== block.getWitnessRoot()) { + utils.debug('Block failed witnessroot test: %s', block.rhash); + return false; } } diff --git a/lib/bcoin/protocol/framer.js b/lib/bcoin/protocol/framer.js index e070f80d..71699f5d 100644 --- a/lib/bcoin/protocol/framer.js +++ b/lib/bcoin/protocol/framer.js @@ -111,13 +111,21 @@ Framer.prototype.coin = function _coin(coin) { }; Framer.prototype.tx = function tx(tx) { - return this.packet('tx', Framer.tx(block)); + return this.packet('tx', Framer.tx(tx)); +}; + +Framer.prototype.witnessTX = function witnessTX(tx) { + return this.packet('tx', Framer.witnessTX(tx)); }; Framer.prototype.block = function _block(block) { return this.packet('block', Framer.block(block)); }; +Framer.prototype.witnessBlock = function witnessBlock(block) { + return this.packet('block', Framer.witnessBlock(block)); +}; + Framer.prototype.merkleBlock = function merkleBlock(block) { return this.packet('merkleblock', Framer.merkleBlock(block)); }; @@ -543,7 +551,7 @@ Framer.witness = function _witness(witness) { if (!witness) return new Buffer([0]); - size += utils.writeIntv(witness.length); + size += utils.sizeIntv(witness.length); for (i = 0; i < witness.length; i++) { chunk = witness[i]; @@ -552,6 +560,8 @@ Framer.witness = function _witness(witness) { p = new Buffer(size); + off += utils.writeIntv(p, witness.length, off); + for (i = 0; i < witness.length; i++) { chunk = witness[i]; off += utils.writeIntv(p, chunk.length, off); @@ -576,7 +586,7 @@ Framer._block = function _block(block, witness) { var i, tx, p; for (i = 0; i < block.txs.length; i++) { - tx = witness && block.txs[i].witness + tx = witness ? Framer.witnessTX(block.txs[i]) : Framer.tx(block.txs[i]); txs.push(tx); diff --git a/lib/bcoin/protocol/parser.js b/lib/bcoin/protocol/parser.js index df99de0f..e988ebf8 100644 --- a/lib/bcoin/protocol/parser.js +++ b/lib/bcoin/protocol/parser.js @@ -521,9 +521,10 @@ Parser.parseCoin = function parseCoin(p, extended) { }; Parser.parseTX = function parseTX(p) { - var inCount, off, txIn, tx; + var off = 0; + var inCount, txIn, tx; var outCount, txOut; - var i; + var version, locktime, i; if (p.length < 10) throw new Error('Invalid tx size'); @@ -531,7 +532,10 @@ Parser.parseTX = function parseTX(p) { if (Parser.isWitnessTX(p)) return Parser.parseWitnessTX(p); - inCount = utils.readIntv(p, 4); + version = utils.readU32(p, off); + off += 4; + + inCount = utils.readIntv(p, off); off = inCount.off; inCount = inCount.r; @@ -579,14 +583,18 @@ Parser.parseTX = function parseTX(p) { throw new Error('Invalid tx_out offset'); } + locktime = utils.readU32(p, off); + off += 4; + return { - version: utils.read32(p, 0), + witness: false, + version: version, inputs: txIn, outputs: txOut, - locktime: utils.readU32(p, off), - _cost: (off + 4) * 4, - _raw: p.slice(0, off + 4), - _size: off + 4 + locktime: locktime, + _cost: off * 4, + _raw: p.length !== off ? p.slice(0, off) : p, + _size: off }; }; @@ -599,16 +607,21 @@ Parser.isWitnessTX = function isWitnessTX(p) { Parser.parseWitnessTX = function parseWitnessTX(p) { var cost = 0; - var inCount, off, txIn, tx; + var off = 0; + var inCount, txIn, tx; var outCount, txOut; var marker, flag; - var i; + var version, locktime, i; if (p.length < 12) throw new Error('Invalid witness tx size'); - marker = utils.readU8(p, 4); - flag = utils.readU8(p, 5); + version = utils.readU32(p, off); + off += 4; + marker = utils.readU8(p, off); + off += 1; + flag = utils.readU8(p, off); + off += 1; if (marker !== 0) throw new Error('Invalid witness tx (marker != 0)'); @@ -616,7 +629,7 @@ Parser.parseWitnessTX = function parseWitnessTX(p) { if (flag === 0) throw new Error('Invalid witness tx (flag == 0)'); - inCount = utils.readIntv(p, 6); + inCount = utils.readIntv(p, off); off = inCount.off; inCount = inCount.r; @@ -682,25 +695,30 @@ Parser.parseWitnessTX = function parseWitnessTX(p) { throw new Error('Invalid witness offset'); } + locktime = utils.readU32(p, off); + off += 4; + cost += 4 * 4; + return { witness: true, - version: utils.read32(p, 0), + version: version, marker: marker, flag: flag, inputs: txIn, outputs: txOut, - locktime: utils.readU32(p, off), - _raw: p.slice(0, off + 4), - _size: off + 4, + locktime: locktime, + _raw: off !== p.length ? p.slice(0, off) : p, + _size: off, _cost: cost }; }; Parser.parseWitness = function parseWitness(p) { var witness = []; - var off, chunkCount, chunkSize, item, i; + var off = 0; + var chunkCount, chunkSize, item, i; - chunkCount = utils.readIntv(p, 0); + chunkCount = utils.readIntv(p, off); off = chunkCount.off; chunkCount = chunkCount.r;