From 9affb11b22bba3c21954396724b5a7ea455953db Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 15 Jan 2017 23:42:39 -0800 Subject: [PATCH] bip152: comments. --- lib/net/bip152.js | 339 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 331 insertions(+), 8 deletions(-) diff --git a/lib/net/bip152.js b/lib/net/bip152.js index ea34c784..04d32754 100644 --- a/lib/net/bip152.js +++ b/lib/net/bip152.js @@ -26,8 +26,14 @@ var Block = require('../primitives/block'); * @exports CompactBlock * @constructor * @extends AbstractBlock - * @param {NakedBlock} options + * @param {Object} options + * @property {Buffer|null} keyNonce - Nonce for siphash key. + * @property {Number[]} ids - Short IDs. + * @property {Object[]} ptx - Prefilled transactions. * @property {TX[]} available - Available transaction vector. + * @property {Object} idMap - Map of short ids to indexes. + * @property {Number} count - Transactions resolved. + * @property {Buffer|null} sipKey - Siphash key. */ function CompactBlock(options) { @@ -51,9 +57,11 @@ function CompactBlock(options) { util.inherits(CompactBlock, AbstractBlock); -CompactBlock.prototype._verify = function _verify(ret) { - return this.verifyHeaders(ret); -}; +/** + * Inject properties from options object. + * @private + * @param {Object} options + */ CompactBlock.prototype.fromOptions = function fromOptions(options) { this.parseOptions(options); @@ -83,15 +91,39 @@ CompactBlock.prototype.fromOptions = function fromOptions(options) { return this; }; +/** + * Instantiate compact block from options. + * @param {Object} options + * @returns {CompactBlock} + */ + CompactBlock.fromOptions = function fromOptions(options) { return new CompactBlock().fromOptions(options); }; +/** + * Verify the block headers. + * @alias CompactBlock#verify + * @param {Object?} ret - Return object, may be + * set with properties `reason` and `score`. + * @returns {Boolean} + */ + +CompactBlock.prototype._verify = function _verify(ret) { + return this.verifyHeaders(ret); +}; + +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + */ + CompactBlock.prototype.fromRaw = function fromRaw(data) { var br = new BufferReader(data); var i, count, index, tx; - this.version = br.readU32(); // Technically signed + this.version = br.readU32(); this.prevBlock = br.readHash('hex'); this.merkleRoot = br.readHash('hex'); this.ts = br.readU32(); @@ -126,33 +158,75 @@ CompactBlock.prototype.fromRaw = function fromRaw(data) { return this; }; +/** + * Instantiate a block from serialized data. + * @param {Buffer} data + * @param {String?} enc + * @returns {CompactBlock} + */ + CompactBlock.fromRaw = function fromRaw(data, enc) { if (typeof data === 'string') data = new Buffer(data, enc); return new CompactBlock().fromRaw(data); }; +/** + * Serialize compact block with witness data. + * @returns {Buffer} + */ + CompactBlock.prototype.toRaw = function toRaw() { return this.frameRaw(true); }; +/** + * Serialize compact block without witness data. + * @returns {Buffer} + */ + CompactBlock.prototype.toNormal = function toNormal() { return this.frameRaw(false); }; +/** + * Write serialized block to a buffer + * writer (includes witness data). + * @param {BufferWriter} bw + */ + CompactBlock.prototype.toWriter = function toWriter(bw) { return this.writeRaw(bw, true); }; +/** + * Write serialized block to a buffer + * writer (excludes witness data). + * @param {BufferWriter} bw + */ + CompactBlock.prototype.toNormalWriter = function toNormalWriter(bw) { return this.writeRaw(bw, false); }; +/** + * Serialize compact block. + * @private + * @param {Boolean} witness + * @returns {Buffer} + */ + CompactBlock.prototype.frameRaw = function frameRaw(witness) { var size = this.getSize(); return this.writeRaw(new StaticWriter(size), witness).render(); }; +/** + * Calculate block serialization size. + * @param {Boolean} witness + * @returns {Number} + */ + CompactBlock.prototype.getSize = function getSize(witness) { var size = 0; var i, ptx; @@ -175,6 +249,13 @@ CompactBlock.prototype.getSize = function getSize(witness) { return size; }; +/** + * Serialize block to buffer writer. + * @private + * @param {BufferWriter} bw + * @param {Boolean} witness + */ + CompactBlock.prototype.writeRaw = function writeRaw(bw, witness) { var i, id, lo, hi, ptx; @@ -207,10 +288,23 @@ CompactBlock.prototype.writeRaw = function writeRaw(bw, witness) { return bw; }; +/** + * Convert block to a TXRequest + * containing missing indexes. + * @returns {TXRequest} + */ + CompactBlock.prototype.toRequest = function toRequest() { return TXRequest.fromCompact(this); }; +/** + * Attempt to fill missing transactions from mempool. + * @param {Boolean} witness + * @param {Mempool} mempool + * @returns {Boolean} + */ + CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) { var have = {}; var hashes = mempool.getSnapshot(); @@ -254,6 +348,12 @@ CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) { return false; }; +/** + * Attempt to fill missing transactions from TXResponse. + * @param {TXResponse} res + * @returns {Boolean} + */ + CompactBlock.prototype.fillMissing = function fillMissing(res) { var offset = 0; var i; @@ -271,6 +371,12 @@ CompactBlock.prototype.fillMissing = function fillMissing(res) { return offset === res.txs.length; }; +/** + * Calculate a transaction short ID. + * @param {Hash} hash + * @returns {Number} + */ + CompactBlock.prototype.sid = function sid(hash) { var lo, hi; @@ -285,16 +391,32 @@ CompactBlock.prototype.sid = function sid(hash) { return hi * 0x100000000 + lo; }; +/** + * Test whether an index is available. + * @param {Number} index + * @returns {Boolean} + */ + CompactBlock.prototype.hasIndex = function hasIndex(index) { return this.available[index] != null; }; +/** + * Initialize the siphash key. + * @private + */ + CompactBlock.prototype.initKey = function initKey() { var data = util.concat(this.abbr(), this.keyNonce); var hash = crypto.sha256(data); this.sipKey = hash.slice(0, 16); }; +/** + * Initialize compact block and short id map. + * @private + */ + CompactBlock.prototype.init = function init() { var i, last, ptx, offset, id; @@ -340,6 +462,12 @@ CompactBlock.prototype.init = function init() { } }; +/** + * Convert completely filled compact + * block to a regular block. + * @returns {Block} + */ + CompactBlock.prototype.toBlock = function toBlock() { var block = new Block(); var i, tx; @@ -364,6 +492,15 @@ CompactBlock.prototype.toBlock = function toBlock() { return block; }; +/** + * Inject properties from block. + * @private + * @param {Block} block + * @param {Boolean} witness + * @param {Buffer?} nonce + * @returns {CompactBlock} + */ + CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) { var i, tx, hash, id; @@ -400,10 +537,23 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) { return this; }; +/** + * Instantiate compact block from a block. + * @param {Block} block + * @param {Boolean} witness + * @param {Buffer?} nonce + * @returns {CompactBlock} + */ + CompactBlock.fromBlock = function fromBlock(block, witness, nonce) { return new CompactBlock().fromBlock(block, witness, nonce); }; +/** + * Convert block to headers. + * @returns {Headers} + */ + CompactBlock.prototype.toHeaders = function toHeaders() { return Headers.fromBlock(this); }; @@ -412,6 +562,9 @@ CompactBlock.prototype.toHeaders = function toHeaders() { * Represents a BlockTransactionsRequest (bip152): `getblocktxn` packet. * @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki * @constructor + * @param {Object} options + * @property {Hash} hash + * @property {Number[]} indexes */ function TXRequest(options) { @@ -425,6 +578,13 @@ function TXRequest(options) { this.fromOptions(options); } +/** + * Inject properties from options. + * @private + * @param {Object} options + * @returns {TXRequest} + */ + TXRequest.prototype.fromOptions = function fromOptions(options) { this.hash = options.hash; @@ -434,10 +594,23 @@ TXRequest.prototype.fromOptions = function fromOptions(options) { return this; }; +/** + * Instantiate request from options. + * @param {Object} options + * @returns {TXRequest} + */ + TXRequest.fromOptions = function fromOptions(options) { return new TXRequest().fromOptions(options); }; +/** + * Inject properties from compact block. + * @private + * @param {CompactBlock} block + * @returns {TXRequest} + */ + TXRequest.prototype.fromCompact = function fromCompact(block) { var i; @@ -451,10 +624,23 @@ TXRequest.prototype.fromCompact = function fromCompact(block) { return this; }; +/** + * Instantiate request from compact block. + * @param {CompactBlock} block + * @returns {TXRequest} + */ + TXRequest.fromCompact = function fromCompact(block) { return new TXRequest().fromCompact(block); }; +/** + * Inject properties from buffer reader. + * @private + * @param {BufferReader} br + * @returns {TXRequest} + */ + TXRequest.prototype.fromReader = function fromReader(br) { var i, count, index, offset; @@ -481,18 +667,42 @@ TXRequest.prototype.fromReader = function fromReader(br) { return this; }; +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + * @returns {TXRequest} + */ + TXRequest.prototype.fromRaw = function fromRaw(data) { return this.fromReader(new BufferReader(data)); }; +/** + * Instantiate request from buffer reader. + * @param {BufferReader} br + * @returns {TXRequest} + */ + TXRequest.fromReader = function fromReader(br) { return new TXRequest().fromReader(br); }; +/** + * Instantiate request from serialized data. + * @param {Buffer} data + * @returns {TXRequest} + */ + TXRequest.fromRaw = function fromRaw(data) { return new TXRequest().fromRaw(data); }; +/** + * Calculate request serialization size. + * @returns {Number} + */ + TXRequest.prototype.getSize = function getSize() { var size = 0; var i, index; @@ -508,6 +718,11 @@ TXRequest.prototype.getSize = function getSize() { return size; }; +/** + * Write serialized request to buffer writer. + * @param {BufferWriter} bw + */ + TXRequest.prototype.toWriter = function toWriter(bw) { var i, index; @@ -523,6 +738,11 @@ TXRequest.prototype.toWriter = function toWriter(bw) { return bw; }; +/** + * Serialize request. + * @returns {Buffer} + */ + TXRequest.prototype.toRaw = function toRaw() { return this.toWriter(new BufferWriter()).render(); }; @@ -531,6 +751,9 @@ TXRequest.prototype.toRaw = function toRaw() { * Represents BlockTransactions (bip152): `blocktxn` packet. * @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki * @constructor + * @param {Object} options + * @property {Hash} hash + * @property {TX[]} txs */ function TXResponse(options) { @@ -544,6 +767,13 @@ function TXResponse(options) { this.fromOptions(options); } +/** + * Inject properties from options. + * @private + * @param {Object} options + * @returns {TXResponse} + */ + TXResponse.prototype.fromOptions = function fromOptions(options) { this.hash = options.hash; @@ -553,10 +783,23 @@ TXResponse.prototype.fromOptions = function fromOptions(options) { return this; }; +/** + * Instantiate response from options. + * @param {Object} options + * @returns {TXResponse} + */ + TXResponse.fromOptions = function fromOptions(options) { return new TXResponse().fromOptions(options); }; +/** + * Inject properties from buffer reader. + * @private + * @param {BufferReader} br + * @returns {TXResponse} + */ + TXResponse.prototype.fromReader = function fromReader(br) { var i, count; @@ -570,18 +813,44 @@ TXResponse.prototype.fromReader = function fromReader(br) { return this; }; +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + * @returns {TXResponse} + */ + TXResponse.prototype.fromRaw = function fromRaw(data) { return this.fromReader(new BufferReader(data)); }; +/** + * Instantiate response from buffer reader. + * @param {BufferReader} br + * @returns {TXResponse} + */ + TXResponse.fromReader = function fromReader(br) { return new TXResponse().fromReader(br); }; +/** + * Instantiate response from serialized data. + * @param {Buffer} data + * @returns {TXResponse} + */ + TXResponse.fromRaw = function fromRaw(data) { return new TXResponse().fromRaw(data); }; +/** + * Inject properties from block. + * @private + * @param {Block} block + * @returns {TXResponse} + */ + TXResponse.prototype.fromBlock = function fromBlock(block, req) { var i, index; @@ -589,34 +858,69 @@ TXResponse.prototype.fromBlock = function fromBlock(block, req) { for (i = 0; i < req.indexes.length; i++) { index = req.indexes[i]; + if (index >= block.txs.length) - return this; + break; + this.txs.push(block.txs[index]); } return this; }; +/** + * Instantiate response from block. + * @param {Block} block + * @returns {TXResponse} + */ + TXResponse.fromBlock = function fromBlock(block, req) { return new TXResponse().fromBlock(block, req); }; +/** + * Serialize response with witness data. + * @returns {Buffer} + */ + TXResponse.prototype.toRaw = function toRaw() { return this.frameRaw(true); }; +/** + * Serialize response without witness data. + * @returns {Buffer} + */ + TXResponse.prototype.toNormal = function toNormal() { return this.frameRaw(false); }; +/** + * Write serialized response to a buffer + * writer (includes witness data). + * @param {BufferWriter} bw + */ + TXResponse.prototype.toWriter = function toWriter(bw) { return this.writeRaw(bw, true); }; +/** + * Write serialized response to a buffer + * writer (excludes witness data). + * @param {BufferWriter} bw + */ + TXResponse.prototype.toNormalWriter = function toNormalWriter(bw) { return this.writeRaw(bw, false); }; +/** + * Calculate request serialization size. + * @returns {Number} + */ + TXResponse.prototype.getSize = function getSize(witness) { var size = 0; var i, tx; @@ -635,6 +939,13 @@ TXResponse.prototype.getSize = function getSize(witness) { return size; }; +/** + * Write serialized response to buffer writer. + * @private + * @param {BufferWriter} bw + * @param {Boolean} witness + */ + TXResponse.prototype.writeRaw = function writeRaw(bw, witness) { var i, tx; @@ -653,13 +964,25 @@ TXResponse.prototype.writeRaw = function writeRaw(bw, witness) { return bw; }; +/** + * Serialize response with witness data. + * @private + * @param {Boolean} witness + * @returns {Buffer} + */ + TXResponse.prototype.frameRaw = function frameRaw(witness) { var size = this.getSize(); return this.writeRaw(new StaticWriter(size), witness).render(); }; -/* - * Helpers +/** + * Represents a prefilled TX. + * @constructor + * @param {Number} index + * @param {TX} tx + * @property {Number} index + * @property {TX} tx */ function PrefilledTX(index, tx) {