From cc22e97daedfc2343541133526bcf898888d1ac9 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Mon, 20 Jun 2016 01:09:27 -0700 Subject: [PATCH] comments. asserts. refactor. --- lib/bcoin/abstractblock.js | 93 +++++++++--- lib/bcoin/address.js | 60 +++++--- lib/bcoin/block.js | 60 +++++--- lib/bcoin/bloom.js | 13 ++ lib/bcoin/chaindb.js | 25 +++- lib/bcoin/chainentry.js | 21 +++ lib/bcoin/coin.js | 66 +++++++-- lib/bcoin/coins.js | 22 ++- lib/bcoin/hd.js | 11 +- lib/bcoin/headers.js | 30 +++- lib/bcoin/input.js | 181 ++++++++++++++++++------ lib/bcoin/memblock.js | 53 +++++-- lib/bcoin/merkleblock.js | 67 +++++---- lib/bcoin/mtx.js | 20 ++- lib/bcoin/output.js | 49 ++++--- lib/bcoin/peer.js | 265 ++++++++++++++++++++++++++++++----- lib/bcoin/pool.js | 132 +++++++++++++++-- lib/bcoin/protocol/framer.js | 16 +++ lib/bcoin/script.js | 162 +++++++++++++++++---- lib/bcoin/tx.js | 183 +++++++++++++++--------- lib/bcoin/types.js | 10 -- lib/bcoin/utils.js | 135 +++++++++++++----- lib/bcoin/workers.js | 2 +- 23 files changed, 1287 insertions(+), 389 deletions(-) diff --git a/lib/bcoin/abstractblock.js b/lib/bcoin/abstractblock.js index 68b308e0..f0f78020 100644 --- a/lib/bcoin/abstractblock.js +++ b/lib/bcoin/abstractblock.js @@ -17,7 +17,7 @@ var assert = utils.assert; * @exports AbstractBlock * @constructor * @abstract - * @param {NakedBlock} data + * @param {NakedBlock} options * @property {Number} version - Block version. Note * that BCoin reads versions as unsigned despite * them being signed on the protocol level. This @@ -33,9 +33,9 @@ var assert = utils.assert; * @property {ReversedHash} rhash - Reversed block hash (uint256le). */ -function AbstractBlock(data) { +function AbstractBlock(options) { if (!(this instanceof AbstractBlock)) - return new AbstractBlock(data); + return new AbstractBlock(options); this.version = 1; this.prevBlock = null; @@ -54,35 +54,72 @@ function AbstractBlock(data) { this._size = null; this._witnessSize = null; - if (data) - this.parseOptions(data); + if (options) + this.parseOptions(options); } -AbstractBlock.prototype.parseOptions = function parseOptions(data) { - assert(data, 'Block data is required.'); - assert(typeof data.version === 'number'); - assert(typeof data.prevBlock === 'string'); - assert(typeof data.merkleRoot === 'string'); - assert(typeof data.ts === 'number'); - assert(typeof data.bits === 'number'); - assert(typeof data.nonce === 'number'); +/** + * Inject properties from options object. + * @private + * @param {NakedBlock} options + */ - this.version = data.version; - this.prevBlock = data.prevBlock; - this.merkleRoot = data.merkleRoot; - this.ts = data.ts; - this.bits = data.bits; - this.nonce = data.nonce; - this.totalTX = data.totalTX || 0; - this.height = data.height != null ? data.height : -1; +AbstractBlock.prototype.parseOptions = function parseOptions(options) { + assert(options, 'Block data is required.'); + assert(utils.isNumber(options.version)); + assert(typeof options.prevBlock === 'string'); + assert(typeof options.merkleRoot === 'string'); + assert(utils.isNumber(options.ts)); + assert(utils.isNumber(options.bits)); + assert(utils.isNumber(options.nonce)); + + this.version = options.version; + this.prevBlock = options.prevBlock; + this.merkleRoot = options.merkleRoot; + this.ts = options.ts; + this.bits = options.bits; + this.nonce = options.nonce; + this.totalTX = options.totalTX || 0; + this.height = options.height != null ? options.height : -1; this.txs = null; - this.mutable = !!data.mutable; + this.mutable = !!options.mutable; this._valid = null; this._hash = null; this._size = null; this._witnessSize = null; + + return this; +}; + +/** + * Inject properties from json object. + * @private + * @param {Object} json + */ + +AbstractBlock.prototype.parseJSON = function parseJSON(json) { + assert(json, 'Block data is required.'); + assert(utils.isNumber(json.height)); + assert(utils.isNumber(json.version)); + assert(typeof json.prevBlock === 'string'); + assert(typeof json.merkleRoot === 'string'); + assert(utils.isNumber(json.ts)); + assert(utils.isNumber(json.bits)); + assert(utils.isNumber(json.nonce)); + assert(utils.isNumber(json.totalTX)); + + this.height = json.height; + this.version = json.version; + this.prevBlock = utils.revHex(json.prevBlock); + this.merkleRoot = utils.revHex(json.merkleRoot); + this.ts = json.ts; + this.bits = json.bits; + this.nonce = json.nonce; + this.totalTX = json.totalTX; + + return this; }; /** @@ -206,6 +243,18 @@ AbstractBlock.prototype.toInv = function toInv() { }; }; +/** + * Convert the block to a headers object. + * @returns {Headers} + */ + +AbstractBlock.prototype.toHeaders = function toHeaders() { + var headers = new bcoin.headers(this); + headers._hash = this._hash; + headers._valid = true; + return headers; +}; + /* * Expose */ diff --git a/lib/bcoin/address.js b/lib/bcoin/address.js index 45a0bb3f..735e567c 100644 --- a/lib/bcoin/address.js +++ b/lib/bcoin/address.js @@ -44,6 +44,12 @@ function Address(options) { this.fromOptions(options); } +/** + * Inject properties from options object. + * @private + * @param {Object} options + */ + Address.prototype.fromOptions = function fromOptions(options) { this.hash = options.hash; this.type = options.type || 'pubkeyhash'; @@ -54,6 +60,12 @@ Address.prototype.fromOptions = function fromOptions(options) { this.hash = new Buffer(this.hash, 'hex'); }; +/** + * Insantiate address from options. + * @param {Object} options + * @returns {Address} + */ + Address.fromOptions = function fromOptions(options) { return new Address().fromOptions(options); }; @@ -132,9 +144,9 @@ Address.prototype.inspect = function inspect() { }; /** - * Parse a base58 address. + * Inject properties from base58 address. + * @private * @param {Base58Address} address - * @returns {ParsedAddress} * @throws Parse error */ @@ -196,11 +208,9 @@ Address.fromBase58 = function fromBase58(address) { }; /** - * Parse an output script and extract address - * properties. Converts pubkey and multisig - * scripts to pubkeyhash and scripthash addresses. + * Inject properties from output script. + * @private * @param {Script} script - * @returns {ParsedAddress|null} */ Address.prototype.fromScript = function fromScript(script) { @@ -262,10 +272,9 @@ Address.prototype.fromScript = function fromScript(script) { }; /** - * Attempt to extract address - * properties from a witness. + * Inject properties from witness. + * @private * @param {Witness} witness - * @returns {ParsedAddress|null} */ Address.prototype.fromWitness = function fromWitness(witness) { @@ -285,10 +294,9 @@ Address.prototype.fromWitness = function fromWitness(witness) { }; /** - * Attempt to extract address - * properties from an input script. - * @param {Witness} witness - * @returns {ParsedAddress|null} + * Inject properties from input script. + * @private + * @param {Script} script */ Address.prototype.fromInputScript = function fromInputScript(script) { @@ -309,8 +317,10 @@ Address.prototype.fromInputScript = function fromInputScript(script) { /** * Create an Address from a witness. + * Attempt to extract address + * properties from a witness. * @param {Witness} - * @returns {ParsedAddress|null} + * @returns {Address|null} */ Address.fromWitness = function fromWitness(witness) { @@ -319,8 +329,10 @@ Address.fromWitness = function fromWitness(witness) { /** * Create an Address from an input script. + * Attempt to extract address + * properties from an input script. * @param {Script} - * @returns {ParsedAddress|null} + * @returns {Address|null} */ Address.fromInputScript = function fromInputScript(script) { @@ -329,8 +341,11 @@ Address.fromInputScript = function fromInputScript(script) { /** * Create an Address from an output script. + * Parse an output script and extract address + * properties. Converts pubkey and multisig + * scripts to pubkeyhash and scripthash addresses. * @param {Script} - * @returns {ParsedAddress|null} + * @returns {Address|null} */ Address.fromScript = function fromScript(script) { @@ -338,11 +353,12 @@ Address.fromScript = function fromScript(script) { }; /** - * Create a naked address from hash/type/version. + * Inject properties from a hash. + * @private * @param {Buffer|Hash} hash * @param {AddressType} type * @param {Number} [version=-1] - * @returns {ParsedAddress} + * @throws on bad hash size */ Address.prototype.fromHash = function fromHash(hash, type, version, network) { @@ -382,11 +398,12 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) { }; /** - * Create an Address from hash/type/version. + * Create a naked address from hash/type/version. * @param {Buffer|Hash} hash * @param {AddressType} type * @param {Number} [version=-1] * @returns {Address} + * @throws on bad hash size */ Address.fromHash = function fromHash(hash, type, version, network) { @@ -394,11 +411,11 @@ Address.fromHash = function fromHash(hash, type, version, network) { }; /** - * Hash data and compile hash to an address. + * Inject properties from hash. * @param {Hash|Buffer} hash * @param {AddressType?} type * @param {Number?} version - Witness program version. - * @returns {ParsedAddress} + * @throws on bad hash size */ Address.prototype.fromData = function fromData(data, type, version, network) { @@ -416,6 +433,7 @@ Address.prototype.fromData = function fromData(data, type, version, network) { * @param {AddressType} type * @param {Number} [version=-1] * @returns {Address} + * @throws on bad hash size */ Address.fromData = function fromData(data, type, version, network) { diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index 9b50e5bb..1cdb0539 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -649,25 +649,19 @@ Block.prototype.toJSON = function toJSON() { }; /** - * Handle a deserialized JSON transaction object. - * @returns {Object} A "naked" block (a - * plain javascript object which is suitable - * for passing to the Block constructor). + * Inject properties from json object. + * @private + * @param {Object} json */ Block.prototype.fromJSON = function fromJSON(json) { var i; + assert(json, 'Block data is required.'); assert.equal(json.type, 'block'); + assert(Array.isArray(json.txs)); - this.height = json.height; - this.version = json.version; - this.prevBlock = utils.revHex(json.prevBlock); - this.merkleRoot = utils.revHex(json.merkleRoot); - this.ts = json.ts; - this.bits = json.bits; - this.nonce = json.nonce; - this.totalTX = json.totalTX; + this.parseJSON(json); for (i = 0; i < json.txs.length; i++) this.txs.push(bcoin.tx.fromJSON(json.txs[i])); @@ -686,15 +680,14 @@ Block.fromJSON = function fromJSON(json) { }; /** - * Parse a serialized block. + * Inject properties from serialized data. + * @private * @param {Buffer} data - * @param {String?} enc - Encoding, can be `'hex'` or null. - * @returns {Object} A "naked" block object. */ Block.prototype.fromRaw = function fromRaw(data) { var p = bcoin.reader(data); - var i, tx; + var i, tx, witnessSize; p.start(); @@ -706,16 +699,19 @@ Block.prototype.fromRaw = function fromRaw(data) { this.nonce = p.readU32(); this.totalTX = p.readVarint(); - this._witnessSize = 0; + witnessSize = 0; for (i = 0; i < this.totalTX; i++) { tx = bcoin.tx.fromRaw(p); - this._witnessSize += tx._witnessSize; + witnessSize += tx._witnessSize; this.addTX(tx); } - this._raw = p.endData(); - this._size = this._raw.length; + if (!this.mutable) { + this._raw = p.endData(); + this._size = this._raw.length; + this._witnessSize = witnessSize; + } return this; }; @@ -745,6 +741,14 @@ Block.prototype.toMerkle = function toMerkle(filter) { return bcoin.merkleblock.fromBlock(this, filter); }; +/** + * Serialze block with or without witness data. + * @private + * @param {Boolean} witness + * @param {BufferWriter?} writer + * @returns {Buffer} + */ + Block.prototype.frame = function frame(witness, writer) { var p = bcoin.writer(writer); var witnessSize = 0; @@ -776,10 +780,24 @@ Block.prototype.frame = function frame(witness, writer) { return p; }; +/** + * Serialze block without witness data. + * @private + * @param {BufferWriter?} writer + * @returns {Buffer} + */ + Block.prototype.frameNormal = function frameNormal(writer) { return this.frame(false, writer); }; +/** + * Serialze block with witness data. + * @private + * @param {BufferWriter?} writer + * @returns {Buffer} + */ + Block.prototype.frameWitness = function frameWitness(writer) { return this.frame(true, writer); }; @@ -793,7 +811,7 @@ Block.prototype.frameWitness = function frameWitness(writer) { Block.isBlock = function isBlock(obj) { return obj && obj.merkleRoot !== undefined - && typeof obj.getCommitmentHash === 'function'; + && typeof obj.getClaimed === 'function'; }; /* diff --git a/lib/bcoin/bloom.js b/lib/bcoin/bloom.js index 3804bc45..215b9145 100644 --- a/lib/bcoin/bloom.js +++ b/lib/bcoin/bloom.js @@ -159,6 +159,11 @@ Bloom.prototype.isWithinConstraints = function isWithinConstraints() { return true; }; +/** + * Serialize the filter in `filterload` packet format. + * @returns {Buffer} + */ + Bloom.prototype.toRaw = function toRaw(writer) { var p = BufferWriter(writer); @@ -173,6 +178,14 @@ Bloom.prototype.toRaw = function toRaw(writer) { return p; }; +/** + * Instantiate bloom filter from + * serialized data (filterload). + * @param {Buffer} + * @param {String?} enc + * @returns {Bloom} + */ + Bloom.fromRaw = function fromRaw(data, enc) { var p, filter, n, tweak, update; diff --git a/lib/bcoin/chaindb.js b/lib/bcoin/chaindb.js index a2107c1e..29835c00 100644 --- a/lib/bcoin/chaindb.js +++ b/lib/bcoin/chaindb.js @@ -796,12 +796,12 @@ ChainDB.prototype.has = function has(height, callback) { ChainDB.prototype.saveBlock = function saveBlock(block, view, batch, connect, callback) { if (this.options.spv) - return utils.nextTick(callback); + return utils.asyncify(callback)(null, block); batch.put(layout.b(block.hash()), block.toRaw()); if (!connect) - return utils.nextTick(callback); + return utils.asyncify(callback)(null, block); this.connectBlock(block, view, batch, callback); }; @@ -1325,9 +1325,9 @@ ChainDB.prototype.getFullBlock = function getFullBlock(hash, callback) { }; /** - * Fill a block with coins (unspent only). + * Get a view of the existing coins necessary to verify a block. * @param {Block} block - * @param {Function} callback - Returns [Error, {@link Block}]. + * @param {Function} callback - Returns [Error, {@link CoinView}]. */ ChainDB.prototype.getCoinView = function getCoinView(block, callback) { @@ -1355,7 +1355,7 @@ ChainDB.prototype.getCoinView = function getCoinView(block, callback) { /** * Get coins necessary to be resurrected during a reorg. * @param {Hash} hash - * @param {Function} callback - Returns [Error, Object]. + * @param {Function} callback - Returns [Error, {@link Coin}[]]. */ ChainDB.prototype.getUndoCoins = function getUndoCoins(hash, callback) { @@ -1371,9 +1371,11 @@ ChainDB.prototype.getUndoCoins = function getUndoCoins(hash, callback) { }; /** - * Fill a block with coins necessary to be resurrected during a reorg. + * Get a coin view containing unspent coins as + * well as the coins to be resurrected for a reorg. + * (Note: fills block with undo coins). * @param {Block} block - * @param {Function} callback - Returns [Error, {@link Block}]. + * @param {Function} callback - Returns [Error, {@link CoinView}]. */ ChainDB.prototype.getUndoView = function getUndoView(block, callback) { @@ -1446,6 +1448,15 @@ ChainDB.prototype.hasCoins = function hasCoins(hash, callback) { this.db.has(layout.c(hash), callback); }; +/** + * Prune a block from the chain and + * add current block to the prune queue. + * @private + * @param {Block} + * @param {Batch} batch + * @param {Function} callback + */ + ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) { var futureHeight, key; diff --git a/lib/bcoin/chainentry.js b/lib/bcoin/chainentry.js index 0bbf3ba0..6225f296 100644 --- a/lib/bcoin/chainentry.js +++ b/lib/bcoin/chainentry.js @@ -490,6 +490,27 @@ ChainEntry.fromJSON = function fromJSON(chain, json) { }); }; +/** + * Convert the entry to a headers object. + * @returns {Headers} + */ + +ChainEntry.prototype.toHeaders = function toHeaders() { + return bcoin.headers.fromEntry(this); +}; + +/** + * Convert the entry to an inv item. + * @returns {InvItem} + */ + +ChainEntry.prototype.toInv = function toInv() { + return { + type: constants.inv.BLOCK, + hash: this.hash + }; +}; + /** * Return a more user-friendly object. * @returns {Object} diff --git a/lib/bcoin/coin.js b/lib/bcoin/coin.js index 1c9bf938..43c56751 100644 --- a/lib/bcoin/coin.js +++ b/lib/bcoin/coin.js @@ -48,8 +48,20 @@ function Coin(options) { utils.inherits(Coin, bcoin.output); +/** + * Inject options into coin. + * @private + * @param {Object} options + */ + Coin.prototype.fromOptions = function fromOptions(options) { assert(options, 'Coin data is required.'); + assert(utils.isNumber(options.version)); + assert(utils.isNumber(options.height)); + assert(utils.isNumber(options.value)); + assert(typeof options.coinbase === 'boolean'); + assert(!options.hash || typeof options.hash === 'string'); + assert(!options.index || utils.isNumber(options.index)); this.version = options.version; this.height = options.height; @@ -59,17 +71,15 @@ Coin.prototype.fromOptions = function fromOptions(options) { this.hash = options.hash; this.index = options.index; - assert(utils.isNumber(this.version)); - assert(utils.isNumber(this.height)); - assert(utils.isNumber(this.value)); - assert(this.script instanceof bcoin.script); - assert(typeof this.coinbase === 'boolean'); - assert(!this.hash || typeof this.hash === 'string'); - assert(!this.index || utils.isNumber(this.index)); - return this; }; +/** + * Instantiate Coin from options object. + * @private + * @param {Object} options + */ + Coin.fromOptions = function fromOptions(options) { if (options instanceof Coin) return options; @@ -167,7 +177,21 @@ Coin.fromJSON = function fromJSON(json) { return new Coin().fromJSON(json); }; +/** + * Inject JSON properties into coin. + * @private + * @param {Object} json + */ + Coin.prototype.fromJSON = function fromJSON(json) { + assert(json, 'Coin data required.'); + assert(utils.isNumber(json.version)); + assert(utils.isNumber(json.height)); + assert(typeof json.value === 'string'); + assert(typeof json.coinbase === 'boolean'); + assert(!json.hash || typeof json.hash === 'string'); + assert(!json.index || utils.isNumber(json.index)); + this.version = json.version; this.height = json.height; this.value = utils.satoshi(json.value); @@ -175,6 +199,7 @@ Coin.prototype.fromJSON = function fromJSON(json) { this.coinbase = json.coinbase; this.hash = json.hash ? utils.revHex(json.hash) : null; this.index = json.index; + return this; }; @@ -203,6 +228,12 @@ Coin.prototype.toRaw = function toRaw(writer) { return p; }; +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + */ + Coin.prototype.fromRaw = function fromRaw(data) { var p = bcoin.reader(data); @@ -251,6 +282,12 @@ Coin.prototype.toExtended = function toExtended(writer) { return p; }; +/** + * Inject properties from extended serialized data. + * @private + * @param {Buffer} data + */ + Coin.prototype.fromExtended = function fromExtended(data) { var p = bcoin.reader(data); this.fromRaw(p); @@ -274,13 +311,13 @@ Coin.fromExtended = function fromExtended(data, enc) { }; /** - * Instantiate a coin from a TX + * Inject properties from TX. * @param {TX} tx - * @param {Number} index - Output index. - * @returns {Coin} + * @param {Number} index */ Coin.prototype.fromTX = function fromTX(tx, index) { + assert(utils.isNumber(index)); this.version = tx.version; this.height = tx.height; this.value = tx.outputs[index].value; @@ -291,6 +328,13 @@ Coin.prototype.fromTX = function fromTX(tx, index) { return this; }; +/** + * Instantiate a coin from a TX + * @param {TX} tx + * @param {Number} index - Output index. + * @returns {Coin} + */ + Coin.fromTX = function fromTX(tx, index) { return new Coin().fromTX(tx, index); }; diff --git a/lib/bcoin/coins.js b/lib/bcoin/coins.js index 0635bb7b..20ef8aab 100644 --- a/lib/bcoin/coins.js +++ b/lib/bcoin/coins.js @@ -40,6 +40,12 @@ function Coins(options) { this.fromOptions(options); } +/** + * Inject properties from options object. + * @private + * @param {Object} options + */ + Coins.prototype.fromOptions = function fromOptions(options) { this.version = options.version != null ? options.version : -1; this.hash = options.hash || null; @@ -52,6 +58,12 @@ Coins.prototype.fromOptions = function fromOptions(options) { return this; }; +/** + * Instantiate coins from options object. + * @param {Object} options + * @returns {Coins} + */ + Coins.fromOptions = function fromOptions(options) { return new Coins().fromOptions(options); }; @@ -291,9 +303,9 @@ Coins.fromRaw = function fromRaw(data, hash) { }; /** - * Instantiate a coins object from a transaction. + * Inject properties from tx. + * @private * @param {TX} tx - * @returns {Coins} */ Coins.prototype.fromTX = function fromTX(tx) { @@ -315,6 +327,12 @@ Coins.prototype.fromTX = function fromTX(tx) { return this; }; +/** + * Instantiate a coins object from a transaction. + * @param {TX} tx + * @returns {Coins} + */ + Coins.fromTX = function fromTX(tx) { return new Coins().fromTX(tx); }; diff --git a/lib/bcoin/hd.js b/lib/bcoin/hd.js index bd5c6c06..734310ad 100644 --- a/lib/bcoin/hd.js +++ b/lib/bcoin/hd.js @@ -328,7 +328,7 @@ HD.fromRaw = function fromRaw(data) { * Generate an hdkey from any number of options. * @param {Object|Mnemonic|Buffer} options - mnemonic, mnemonic * options, seed, or base58 key. - * @param {String?} network + * @param {(Network|NetworkType)?} network * @returns {HDPrivateKey|HDPublicKey} */ @@ -346,16 +346,13 @@ HD.from = function from(options, network) { else xkey = options; - if (HDPrivateKey.isExtended(xkey)) - return HDPrivateKey.fromBase58(xkey); - - if (HDPublicKey.isExtended(xkey)) - return HDPublicKey.fromBase58(xkey); + if (HD.isExtended(xkey)) + return HD.fromBase58(xkey); if (HD.hasPrefix(options)) return HD.fromRaw(options); - return HDPrivateKey.fromMnemonic(options, network); + return HD.fromMnemonic(options, network); }; /** diff --git a/lib/bcoin/headers.js b/lib/bcoin/headers.js index e1169cf0..c303c348 100644 --- a/lib/bcoin/headers.js +++ b/lib/bcoin/headers.js @@ -86,7 +86,6 @@ Headers.prototype.inspect = function inspect() { /** * Serialize the headers. - * @see {Headers#render} * @param {String?} enc - Encoding, can be `'hex'` or null. * @returns {Buffer|String} */ @@ -109,10 +108,9 @@ Headers.prototype.toRaw = function toRaw(writer) { }; /** - * Parse a serialized headers. + * Inject properties from serialized data. + * @private * @param {Buffer} data - * @param {String?} enc - Encoding, can be `'hex'` or null. - * @returns {NakedBlock} A "naked" headers object. */ Headers.prototype.fromRaw = function fromRaw(data) { @@ -130,7 +128,7 @@ Headers.prototype.fromRaw = function fromRaw(data) { }; /** - * Instantiate headers from a serialized Buffer. + * Instantiate headers from serialized data. * @param {Buffer} data * @param {String?} enc - Encoding, can be `'hex'` or null. * @returns {Headers} @@ -142,6 +140,28 @@ Headers.fromRaw = function fromRaw(data, enc) { return new Headers().fromRaw(data); }; +/** + * Instantiate headers from a chain entry. + * @param {ChainEntry} entry + * @returns {Headers} + */ + +Headers.fromEntry = function fromEntry(entry) { + var headers = new Headers(entry); + headers._hash = new Buffer(entry.hash, 'hex'); + headers._valid = true; + return headers; +}; + +/** + * Convert the block to a headers object. + * @returns {Headers} + */ + +Headers.prototype.toHeaders = function toHeaders() { + return this; +}; + /** * Test an object to see if it is a Headers object. * @param {Object} obj diff --git a/lib/bcoin/input.js b/lib/bcoin/input.js index 3fcb2405..d1f65fe1 100644 --- a/lib/bcoin/input.js +++ b/lib/bcoin/input.js @@ -30,34 +30,46 @@ function Outpoint(hash, index) { this.index = index != null ? index : null; } -Outpoint.prototype.fromOptions = function fromOptions(data) { - this.hash = data.hash; - this.index = data.index; - assert(typeof this.hash === 'string'); - assert(typeof this.index === 'number'); +/** + * Inject properties from options object. + * @private + * @param {Object} options + */ + +Outpoint.prototype.fromOptions = function fromOptions(options) { + assert(typeof options.hash === 'string'); + assert(utils.isNumber(options.index)); + this.hash = options.hash; + this.index = options.index; return this; }; -Outpoint.fromOptions = function fromOptions(data) { - if (data instanceof Outpoint) - return data; - return new Outpoint().fromOptions(data); +/** + * Instantate outpoint from options object. + * @param {Object} options + * @returns {Outpoint} + */ + +Outpoint.fromOptions = function fromOptions(options) { + if (options instanceof Outpoint) + return options; + return new Outpoint().fromOptions(options); }; +/** + * Test whether the outpoint is null (hash of zeroes + * with max-u32 index). Used to detect coinbases. + * @returns {Boolean} + */ + Outpoint.prototype.isNull = function isNull() { return this.hash === constants.NULL_HASH && this.index === 0xffffffff; }; -Outpoint.prototype.fromRaw = function fromRaw(data) { - var p = bcoin.reader(data); - this.hash = p.readHash('hex'); - this.index = p.readU32(); - return this; -}; - -Outpoint.fromRaw = function fromRaw(data) { - return new Outpoint().fromRaw(data); -}; +/** + * Serialize outpoint. + * @returns {Buffer} + */ Outpoint.prototype.toRaw = function toRaw(writer) { var p = bcoin.writer(writer); @@ -71,25 +83,50 @@ Outpoint.prototype.toRaw = function toRaw(writer) { return p; }; +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + */ + +Outpoint.prototype.fromRaw = function fromRaw(data) { + var p = bcoin.reader(data); + this.hash = p.readHash('hex'); + this.index = p.readU32(); + return this; +}; + +/** + * Instantiate outpoint from serialized data. + * @param {Buffer} data + * @returns {Outpoint} + */ + +Outpoint.fromRaw = function fromRaw(data) { + return new Outpoint().fromRaw(data); +}; + +/** + * Inject properties from json object. + * @private + * @params {Object} json + */ + Outpoint.prototype.fromJSON = function fromJSON(json) { + assert(typeof json.hash === 'string'); + assert(utils.isNumber(json.index)); this.hash = utils.revHex(json.hash); this.index = json.index; return this; }; -Outpoint.fromJSON = function fromJSON(json) { - return new Outpoint().fromJSON(json); -}; - -Outpoint.prototype.fromTX = function fromTX(tx, i) { - this.hash = tx.hash('hex'); - this.index = i; - return this; -}; - -Outpoint.fromTX = function fromTX(tx, i) { - return new Outpoint().fromTX(tx, i); -}; +/** + * Convert the outpoint to an object suitable + * for JSON serialization. Note that the hash + * will be reversed to abide by bitcoind's legacy + * of little-endian uint256s. + * @returns {Object} + */ Outpoint.prototype.toJSON = function toJSON() { return { @@ -98,6 +135,46 @@ Outpoint.prototype.toJSON = function toJSON() { }; }; +/** + * Instantiate outpoint from json object. + * @param {Object} json + * @returns {Outpoint} + */ + +Outpoint.fromJSON = function fromJSON(json) { + return new Outpoint().fromJSON(json); +}; + +/** + * Inject properties from tx. + * @private + * @param {TX} tx + * @param {Number} index + */ + +Outpoint.prototype.fromTX = function fromTX(tx, index) { + assert(utils.isNumber(index)); + this.hash = tx.hash('hex'); + this.index = index; + return this; +}; + +/** + * Instantiate outpoint from tx. + * @param {TX} tx + * @param {Number} index + * @returns {Outpoint} + */ + +Outpoint.fromTX = function fromTX(tx, index) { + return new Outpoint().fromTX(tx, index); +}; + +/** + * Convert the outpoint to a user-friendly string. + * @returns {String} + */ + Outpoint.prototype.inspect = function inspect() { return ''; }; @@ -133,8 +210,16 @@ function Input(options, mutable) { this.fromOptions(options, mutable); } +/** + * Inject properties from options object. + * @private + * @param {Object} options + * @param {Boolean} mutable + */ + Input.prototype.fromOptions = function fromOptions(options, mutable) { assert(options, 'Input data is required.'); + assert(options.sequence == null || utils.isNumber(options.sequence)); this.mutable = !!mutable; this.prevout = Outpoint.fromOptions(options.prevout); @@ -146,11 +231,15 @@ Input.prototype.fromOptions = function fromOptions(options, mutable) { if (options.coin) this.coin = bcoin.coin(options.coin); - assert(typeof this.sequence === 'number'); - return this; }; +/** + * Instantiate an Input from options object. + * @param {NakedInput} options - The jsonified input object. + * @returns {Input} + */ + Input.fromOptions = function fromOptions(options) { return new Input().fromOptions(options); }; @@ -392,7 +481,15 @@ Input.prototype.toJSON = function toJSON() { }; }; +/** + * Inject properties from a JSON object. + * @private + * @param {Object} json + */ + Input.prototype.fromJSON = function fromJSON(json) { + assert(json, 'Input data is required.'); + assert(utils.isNumber(json.sequence)); this.prevout = Outpoint.fromJSON(json.prevout); this.coin = json.coin ? bcoin.coin.fromJSON(json.coin) : null; this.script = bcoin.script.fromJSON(json.script); @@ -431,10 +528,8 @@ Input.prototype.toRaw = function toRaw(writer) { }; /** - * Instantiate an input from a serialized Buffer. + * Inject properties from serialized data. * @param {Buffer} data - * @param {String?} enc - Encoding, can be `'hex'` or null. - * @returns {Input} */ Input.prototype.fromRaw = function fromRaw(data) { @@ -447,6 +542,13 @@ Input.prototype.fromRaw = function fromRaw(data) { return this; }; +/** + * Instantiate an input from a serialized Buffer. + * @param {Buffer} data + * @param {String?} enc - Encoding, can be `'hex'` or null. + * @returns {Input} + */ + Input.fromRaw = function fromRaw(data, enc) { if (typeof data === 'string') data = new Buffer(data, enc); @@ -473,10 +575,9 @@ Input.prototype.toExtended = function toExtended(writer) { }; /** - * Parse an input in "extended" serialization format. + * Inject properties from extended serialized data. + * @private * @param {Buffer} data - * @param {String?} enc - Encoding, can be `'hex'` or null. - * @returns {NakedInput} - A "naked" input object. */ Input.prototype.fromExtended = function fromExtended(data) { diff --git a/lib/bcoin/memblock.js b/lib/bcoin/memblock.js index 1a694028..80c876bb 100644 --- a/lib/bcoin/memblock.js +++ b/lib/bcoin/memblock.js @@ -28,7 +28,9 @@ var utils = require('./utils'); * thing. * @exports MemBlock * @constructor - * @param {Object} data + * @param {NakedBlock} options + * @param {Buffer} options.raw + * @param {Number} options.coinbaseHeight * @property {Number} version - Block version. Note * that BCoin reads versions as unsigned despite * them being signed on the protocol level. This @@ -48,30 +50,42 @@ var utils = require('./utils'); * @property {ReversedHash} rhash - Reversed block hash (uint256le). */ -function MemBlock(data) { +function MemBlock(options) { if (!(this instanceof MemBlock)) - return new MemBlock(data); + return new MemBlock(options); - bcoin.abstractblock.call(this, data); + bcoin.abstractblock.call(this, options); this.memory = true; this.coinbaseHeight = null; this.raw = null; - if (data) - this.fromOptions(data); + if (options) + this.fromOptions(options); } utils.inherits(MemBlock, bcoin.abstractblock); -MemBlock.prototype.fromOptions = function fromOptions(data) { - this.coinbaseHeight = data.coinbaseHeight; - this.raw = data.raw; +/** + * Inject properties from options object. + * @private + * @param {NakedBlock} options + */ + +MemBlock.prototype.fromOptions = function fromOptions(options) { + this.coinbaseHeight = options.coinbaseHeight; + this.raw = options.raw; return this; }; -MemBlock.fromOptions = function fromOptions(data) { - return new MemBlock().fromOptions(data); +/** + * Instantiate memblock from options object. + * @param {NakedBlock} options + * @returns {MemBlock} + */ + +MemBlock.fromOptions = function fromOptions(options) { + return new MemBlock().fromOptions(options); }; /** @@ -105,6 +119,12 @@ MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() { return this.coinbaseHeight; }; +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + */ + MemBlock.prototype.fromRaw = function fromRaw(data) { var p = bcoin.reader(data); var height = -1; @@ -140,10 +160,21 @@ MemBlock.prototype.fromRaw = function fromRaw(data) { return this; }; +/** + * Insantiate a memblock from serialized data. + * @param {Buffer} data + * @returns {MemBlock} + */ + MemBlock.fromRaw = function fromRaw(data) { return new MemBlock().fromRaw(data); }; +/** + * Return serialized block data. + * @returns {Buffer} + */ + MemBlock.prototype.toRaw = function toRaw() { return this.raw; }; diff --git a/lib/bcoin/merkleblock.js b/lib/bcoin/merkleblock.js index c8a7fbcd..226dc4d4 100644 --- a/lib/bcoin/merkleblock.js +++ b/lib/bcoin/merkleblock.js @@ -17,7 +17,7 @@ var constants = bcoin.protocol.constants; * @exports MerkleBlock * @constructor * @extends AbstractBlock - * @param {NakedBlock} data + * @param {NakedBlock} options * @property {String} type - "merkleblock" (getdata type). * @property {Number} version - Block version. Note * that BCoin reads versions as unsigned despite @@ -38,11 +38,11 @@ var constants = bcoin.protocol.constants; * @property {ReversedHash} rhash - Reversed block hash (uint256le). */ -function MerkleBlock(data) { +function MerkleBlock(options) { if (!(this instanceof MerkleBlock)) - return new MerkleBlock(data); + return new MerkleBlock(options); - bcoin.abstractblock.call(this, data); + bcoin.abstractblock.call(this, options); this.hashes = null; this.flags = null; @@ -55,23 +55,35 @@ function MerkleBlock(data) { // TXs that will be pushed on this.txs = []; - if (data) - this.fromOptions(data); + if (options) + this.fromOptions(options); } utils.inherits(MerkleBlock, bcoin.abstractblock); -MerkleBlock.prototype.fromOptions = function fromOptions(data) { - assert(data); - assert(Array.isArray(data.hashes)); - assert(Buffer.isBuffer(data.flags)); +/** + * Inject properties from options object. + * @private + * @param {NakedBlock} options + */ - this.hashes = data.hashes; - this.flags = data.flags; +MerkleBlock.prototype.fromOptions = function fromOptions(options) { + assert(options, 'MerkleBlock data is required.'); + assert(Array.isArray(options.hashes)); + assert(Buffer.isBuffer(options.flags)); + + this.hashes = options.hashes; + this.flags = options.flags; return this; }; +/** + * Instantiate merkle block from options object. + * @param {NakedBlock} options + * @returns {MerkleBlock} + */ + MerkleBlock.fromOptions = function fromOptions(data) { return new MerkleBlock().fromOptions(data); }; @@ -313,7 +325,6 @@ MerkleBlock.prototype.inspect = function inspect() { /** * Serialize the merkleblock. - * @see {MerkleBlock#render} * @param {String?} enc - Encoding, can be `'hex'` or null. * @returns {Buffer|String} */ @@ -344,10 +355,9 @@ MerkleBlock.prototype.toRaw = function toRaw(writer) { }; /** - * Parse a serialized merkleblock. + * Inject properties from serialized data. + * @private * @param {Buffer} data - * @param {String?} enc - Encoding, can be `'hex'` or null. - * @returns {NakedBlock} A "naked" headers object. */ MerkleBlock.prototype.fromRaw = function fromRaw(data) { @@ -375,10 +385,10 @@ MerkleBlock.prototype.fromRaw = function fromRaw(data) { }; /** - * Instantiate a merkleblock from a serialized Buffer. + * Instantiate a merkleblock from a serialized data. * @param {Buffer} data * @param {String?} enc - Encoding, can be `'hex'` or null. - * @returns {Headers} + * @returns {MerkleBlock} */ MerkleBlock.fromRaw = function fromRaw(data, enc) { @@ -413,23 +423,19 @@ MerkleBlock.prototype.toJSON = function toJSON() { }; /** - * Handle a deserialized JSON transaction object. - * @returns {Object} A "naked" block (a - * plain javascript object which is suitable - * for passing to the Block constructor). + * Inject properties from json object. + * @private + * @param {Object} json */ MerkleBlock.prototype.fromJSON = function fromJSON(json) { + assert(json, 'MerkleBlock data is required.'); assert.equal(json.type, 'merkleblock'); + assert(Array.isArray(json.hashes)); + assert(typeof json.flags === 'string'); + + this.parseJSON(json); - this.height = json.height; - this.version = json.version; - this.prevBlock = utils.revHex(json.prevBlock); - this.merkleRoot = utils.revHex(json.merkleRoot); - this.ts = json.ts; - this.bits = json.bits; - this.nonce = json.nonce; - this.totalTX = json.totalTX; this.hashes = json.hashes; this.flags = new Buffer(json.flags, 'hex'); @@ -529,6 +535,7 @@ MerkleBlock.fromBlock = function fromBlock(block, filter) { flags[p / 8 | 0] |= bits[p] << (p % 8); merkle = new MerkleBlock(); + merkle._hash = block._hash; merkle.version = block.version; merkle.prevBlock = block.prevBlock; merkle.merkleRoot = block.merkleRoot; diff --git a/lib/bcoin/mtx.js b/lib/bcoin/mtx.js index ab3bc61c..979ef343 100644 --- a/lib/bcoin/mtx.js +++ b/lib/bcoin/mtx.js @@ -1261,7 +1261,7 @@ MTX.prototype.setLocktime = function setLocktime(locktime) { */ MTX.fromJSON = function fromJSON(json) { - return new MTX().fromJSON(JSON); + return new MTX().fromJSON(JSON)._mutable(); }; /** @@ -1271,7 +1271,21 @@ MTX.fromJSON = function fromJSON(json) { MTX.fromRaw = function fromRaw(data, enc) { if (typeof data === 'string') data = new Buffer(data, enc); - return new MTX().fromRaw(data); + return new MTX().fromRaw(data)._mutable(); +}; + +/** + * Mark inputs and outputs as mutable. + * @private + */ + +MTX._mutable = function _mutable() { + var i; + for (i = 0; i < this.inputs.length; i++) + this.inputs[i].mutable = true; + for (i = 0; i < this.outputs.length; i++) + this.outputs[i].mutable = true; + return this; }; /** @@ -1281,7 +1295,7 @@ MTX.fromRaw = function fromRaw(data, enc) { MTX.fromExtended = function fromExtended(data, enc) { if (typeof data === 'string') data = new Buffer(data, enc); - return new MTX().fromExtended(data); + return new MTX().fromExtended(data)._mutable(); }; /** diff --git a/lib/bcoin/output.js b/lib/bcoin/output.js index ab542bea..6a976ff6 100644 --- a/lib/bcoin/output.js +++ b/lib/bcoin/output.js @@ -37,28 +37,34 @@ function Output(options, mutable) { this.fromOptions(options, mutable); } +/** + * Inject properties from options object. + * @private + * @param {NakedOutput} options + * @param {Boolean} mutable + */ + Output.prototype.fromOptions = function fromOptions(options, mutable) { - var value; - assert(options, 'Output data is required.'); - - value = options.value; - - if (!value) - value = 0; + assert(!options.value || utils.isNumber(options.value)); + assert(!mutable || options.value >= 0); this.mutable = !!mutable; - this.value = value; + this.value = options.value || 0; this.script = bcoin.script(options.script); - assert(typeof this.value === 'number'); - assert(!this.mutable || this.value >= 0); - return this; }; -Output.fromOptions = function fromOptions(options) { - return new Output().fromOptions(options); +/** + * Instantiate output from options object. + * @param {NakedOutput} options + * @param {Boolean} mutable + * @returns {Output} + */ + +Output.fromOptions = function fromOptions(options, mutable) { + return new Output().fromOptions(options, mutable); }; /** @@ -185,6 +191,11 @@ Output.prototype.getDustThreshold = function getDustThreshold(rate) { return 3 * bcoin.tx.getMinFee(size, rate); }; +/** + * Calculate size of serialized output. + * @returns {Number} + */ + Output.prototype.getSize = function getSize() { return this.toRaw(bcoin.writer()).written; }; @@ -200,10 +211,9 @@ Output.prototype.isDust = function isDust(rate) { }; /** - * Handle a deserialized JSON output object. - * @returns {NakedOutput} A "naked" output (a - * plain javascript object which is suitable - * for passing to the Output constructor). + * Inject properties from a JSON object. + * @private + * @param {Object} json */ Output.prototype.fromJSON = function fromJSON(json) { @@ -241,10 +251,9 @@ Output.prototype.toRaw = function toRaw(writer) { }; /** - * Parse a serialized output. + * Inject properties from serialized data. + * @private * @param {Buffer} data - * @param {String?} enc - Encoding, can be `'hex'` or null. - * @returns {NakedOutput} A "naked" output object. */ Output.prototype.fromRaw = function fromRaw(data) { diff --git a/lib/bcoin/peer.js b/lib/bcoin/peer.js index 3b432e8f..13d8fd43 100644 --- a/lib/bcoin/peer.js +++ b/lib/bcoin/peer.js @@ -153,8 +153,19 @@ function Peer(pool, options) { utils.inherits(Peer, EventEmitter); +/** + * Globally incremented unique id. + * @private + * @type {Number} + */ + Peer.uid = 0; +/** + * Begin peer initialization. + * @private + */ + Peer.prototype._init = function init() { var self = this; @@ -192,6 +203,12 @@ Peer.prototype._init = function init() { } }; +/** + * Handle `connect` event (called immediately + * if a socket was passed into peer). + * @private + */ + Peer.prototype._onConnect = function _onConnect() { var self = this; @@ -351,13 +368,12 @@ Peer.prototype.announce = function announce(items) { if (!this.isWatched(item)) continue; - if (this.preferHeaders) { - if (item instanceof bcoin.abstractblock) { - if (this.invFilter.test(item.hash())) - continue; - headers.push(item); + if (this.preferHeaders && item.toHeaders) { + item = item.toHeaders(); + if (this.invFilter.test(item.hash())) continue; - } + headers.push(item); + continue; } if (item.toInv) @@ -642,27 +658,35 @@ Peer.prototype.response = function response(cmd, payload) { res = entry.callback(null, payload, cmd); - if (res !== this.requests.skip) { - queue.shift(); - if (queue.length === 0) - delete this.requests.map[cmd]; - clearTimeout(entry.timer); - entry.timer = null; - return true; - } + if (res === this.requests.skip) + return false; - return false; + queue.shift(); + + if (queue.length === 0) + delete this.requests.map[cmd]; + + clearTimeout(entry.timer); + entry.timer = null; + + return true; }; /** * Send `getdata` to peer. - * @param {Object[]} items - See {@link Framer.getData}. + * @param {InvItem[]} items */ Peer.prototype.getData = function getData(items) { this.write(this.framer.getData(items)); }; +/** + * Handle a packet payload. + * @private + * @param {Object} packet + */ + Peer.prototype._onPacket = function onPacket(packet) { var cmd = packet.cmd; var payload = packet.payload; @@ -751,10 +775,11 @@ Peer.prototype._onPacket = function onPacket(packet) { } }; -Peer.prototype.fire = function fire(cmd, payload) { - this.response(cmd, payload); - this.emit(cmd, payload); -}; +/** + * Flush merkle block once all matched + * txs have been received. + * @private + */ Peer.prototype._flushMerkle = function _flushMerkle() { if (this.lastBlock) @@ -763,6 +788,23 @@ Peer.prototype._flushMerkle = function _flushMerkle() { this.waiting = 0; }; +/** + * Emit an event and fulfill a response. + * @param {String} cmd + * @param {Object} payload + */ + +Peer.prototype.fire = function fire(cmd, payload) { + this.response(cmd, payload); + this.emit(cmd, payload); +}; + +/** + * Handle `filterload` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleFilterLoad = function _handleFilterLoad(payload) { if (!payload.isWithinConstraints()) { this.setMisbehavior(100); @@ -773,6 +815,12 @@ Peer.prototype._handleFilterLoad = function _handleFilterLoad(payload) { this.relay = true; }; +/** + * Handle `filteradd` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleFilterAdd = function _handleFilterAdd(payload) { if (payload.data.length > constants.script.MAX_PUSH) { this.setMisbehavior(100); @@ -785,6 +833,12 @@ Peer.prototype._handleFilterAdd = function _handleFilterAdd(payload) { this.relay = true; }; +/** + * Handle `filterclear` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleFilterClear = function _handleFilterClear(payload) { if (this.spvFilter) this.spvFilter.reset(); @@ -792,12 +846,24 @@ Peer.prototype._handleFilterClear = function _handleFilterClear(payload) { this.relay = true; }; +/** + * Handle `utxos` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleUTXOs = function _handleUTXOs(payload) { bcoin.debug('Received %d utxos (%s).', payload.coins.length, this.hostname); this.fire('utxos', payload); }; +/** + * Handle `feefilter` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleFeeFilter = function _handleFeeFilter(payload) { if (!(payload.rate >= 0 && payload.rate <= constants.MAX_MONEY)) { this.setMisbehavior(100); @@ -841,6 +907,13 @@ Peer.prototype.getUTXOs = function getUTXOs(utxos, callback) { }); }; +/** + * Send non-chunked getuxos to peer. + * @private + * @param {Array[]} utxos + * @param {Function} callback + */ + Peer.prototype._getUTXOs = function _getUTXOs(utxos, callback) { var index = 0; var i, prevout, coin; @@ -873,6 +946,11 @@ Peer.prototype._getUTXOs = function _getUTXOs(utxos, callback) { })); }; +/** + * Handle `getutxos` packet. + * @private + */ + Peer.prototype._handleGetUTXOs = function _handleGetUTXOs(payload) { var self = this; var coins = []; @@ -976,6 +1054,12 @@ Peer.prototype._handleGetUTXOs = function _handleGetUTXOs(payload) { }); }; +/** + * Handle `getheaders` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleGetHeaders = function _handleGetHeaders(payload) { var self = this; var headers = []; @@ -1026,7 +1110,7 @@ Peer.prototype._handleGetHeaders = function _handleGetHeaders(payload) { if (!entry) return done(); - headers.push(new bcoin.headers(entry)); + headers.push(entry.toHeaders()); if (headers.length === 2000) return done(); @@ -1053,6 +1137,12 @@ Peer.prototype._handleGetHeaders = function _handleGetHeaders(payload) { }); }; +/** + * Handle `getblocks` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleGetBlocks = function _handleGetBlocks(payload) { var self = this; var blocks = []; @@ -1113,6 +1203,12 @@ Peer.prototype._handleGetBlocks = function _handleGetBlocks(payload) { }); }; +/** + * Handle `version` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleVersion = function _handleVersion(payload) { var self = this; var version = payload.version; @@ -1179,6 +1275,12 @@ Peer.prototype._handleVersion = function _handleVersion(payload) { this.fire('version', payload); }; +/** + * Handle `mempool` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleMempool = function _handleMempool() { var self = this; var items = []; @@ -1219,6 +1321,12 @@ Peer.prototype._handleMempool = function _handleMempool() { }); }; +/** + * Handle `getdata` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleGetData = function _handleGetData(items) { var self = this; var check = []; @@ -1422,6 +1530,12 @@ Peer.prototype._handleGetData = function _handleGetData(items) { }); }; +/** + * Handle `addr` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleAddr = function _handleAddr(addrs) { var hosts = []; var i, addr; @@ -1442,11 +1556,23 @@ Peer.prototype._handleAddr = function _handleAddr(addrs) { this.fire('addr', hosts); }; +/** + * Handle `ping` packet. + * @private + * @param {Object} + */ + Peer.prototype._handlePing = function _handlePing(data) { this.write(this.framer.pong(data)); this.fire('ping', this.minPing); }; +/** + * Handle `pong` packet. + * @private + * @param {Object} + */ + Peer.prototype._handlePong = function _handlePong(data) { var now = utils.ms(); @@ -1479,6 +1605,12 @@ Peer.prototype._handlePong = function _handlePong(data) { this.fire('pong', this.minPing); }; +/** + * Handle `getaddr` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleGetAddr = function _handleGetAddr() { var items = []; var i, host; @@ -1512,6 +1644,12 @@ Peer.prototype._handleGetAddr = function _handleGetAddr() { this.write(this.framer.addr(items)); }; +/** + * Handle `inv` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleInv = function _handleInv(items) { var blocks = []; var txs = []; @@ -1547,6 +1685,12 @@ Peer.prototype._handleInv = function _handleInv(items) { bcoin.debug('Peer sent an unknown inv type: %d (%s).', unknown); }; +/** + * Handle `headers` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleHeaders = function _handleHeaders(headers) { if (headers.length > 2000) { this.setMisbehavior(100); @@ -1555,6 +1699,12 @@ Peer.prototype._handleHeaders = function _handleHeaders(headers) { this.fire('headers', headers); }; +/** + * Handle `reject` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleReject = function _handleReject(payload) { var hash, entry; @@ -1572,6 +1722,12 @@ Peer.prototype._handleReject = function _handleReject(payload) { entry.reject(this); }; +/** + * Handle `alert` packet. + * @private + * @param {Object} + */ + Peer.prototype._handleAlert = function _handleAlert(details) { this.invFilter.add(details.hash, 'hex'); this.fire('alert', details); @@ -1845,8 +2001,12 @@ Peer.prototype.inspect = function inspect() { * Represents a network address. * @exports NetworkAddress * @constructor - * @private * @param {NakedNetworkAddress} options + * @property {Number} id + * @property {Host} host + * @property {Number} port + * @property {Number} services + * @property {Number} ts */ function NetworkAddress(options) { @@ -1863,8 +2023,20 @@ function NetworkAddress(options) { this.fromOptions(options); } +/** + * Globally incremented unique id. + * @private + * @type {Number} + */ + NetworkAddress.uid = 0; +/** + * Inject properties from options object. + * @private + * @param {Object} options + */ + NetworkAddress.prototype.fromOptions = function fromOptions(options) { var host = options.host; @@ -1884,6 +2056,12 @@ NetworkAddress.prototype.fromOptions = function fromOptions(options) { return this; }; +/** + * Instantiate network address from options. + * @param {Object} options + * @returns {NetworkAddress} + */ + NetworkAddress.fromOptions = function fromOptions(options) { return new NetworkAddress().fromOptions(options); }; @@ -1948,11 +2126,10 @@ NetworkAddress.prototype.inspect = function inspect() { }; /** - * Instantiate a network address - * from a hostname (i.e. 127.0.0.1:8333). + * Inject properties from hostname and network. + * @private * @param {String} hostname - * @param {(Network|NetworkType)?} network - * @returns {NetworkAddress} + * @param {Network|NetworkType} network */ NetworkAddress.prototype.fromHostname = function fromHostname(hostname, network) { @@ -1962,7 +2139,6 @@ NetworkAddress.prototype.fromHostname = function fromHostname(hostname, network) this.host = address.host; this.port = address.port || network.port; - this.version = constants.VERSION; this.services = constants.services.NETWORK | constants.services.BLOOM | constants.services.WITNESS; @@ -1971,19 +2147,31 @@ NetworkAddress.prototype.fromHostname = function fromHostname(hostname, network) return this; }; +/** + * Instantiate a network address + * from a hostname (i.e. 127.0.0.1:8333). + * @param {String} hostname + * @param {(Network|NetworkType)?} network + * @returns {NetworkAddress} + */ + NetworkAddress.fromHostname = function fromHostname(hostname, network) { return new NetworkAddress().fromHostname(hostname, network); }; +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + * @param {Boolean?} full - Include timestamp. + */ + NetworkAddress.prototype.fromRaw = function fromRaw(data, full) { var p = bcoin.reader(data); var now = bcoin.now(); - if (full) // only version >= 31402 - this.ts = p.readU32(); - else - this.ts = 0; - + // only version >= 31402 + this.ts = full ? p.readU32() : 0; this.services = p.readU53(); this.host = IP.toString(p.readBytes(16)); this.port = p.readU16BE(); @@ -1994,10 +2182,23 @@ NetworkAddress.prototype.fromRaw = function fromRaw(data, full) { return this; }; +/** + * Insantiate a network address from serialized data. + * @param {Buffer} data + * @param {Boolean?} full - Include timestamp. + * @returns {NetworkAddress} + */ + NetworkAddress.fromRaw = function fromRaw(data, full) { return new NetworkAddress().fromRaw(data, full); }; +/** + * Serialize network address. + * @param {Boolean} full - Include timestamp. + * @returns {Buffer} + */ + NetworkAddress.prototype.toRaw = function toRaw(full, writer) { var p = bcoin.writer(writer); diff --git a/lib/bcoin/pool.js b/lib/bcoin/pool.js index b6332d9f..03d31dab 100644 --- a/lib/bcoin/pool.js +++ b/lib/bcoin/pool.js @@ -260,16 +260,21 @@ Pool.prototype.connect = function connect() { }); } - if (this.seeds.length > 0) { - this._addLoader(); + assert(this.seeds.length !== 0, 'No seeds available.'); - for (i = 0; i < this.size - 1; i++) - this._addPeer(); + this._addLoader(); - this.connected = true; - } + for (i = 0; i < this.size - 1; i++) + this._addPeer(); + + this.connected = true; }; +/** + * Initialize the pool. Bind to events. + * @private + */ + Pool.prototype._init = function _init() { var self = this; @@ -420,6 +425,11 @@ Pool.prototype.unlisten = function unlisten(callback) { this.server = null; }; +/** + * Start timer to detect stalling. + * @private + */ + Pool.prototype._startTimer = function _startTimer() { var self = this; @@ -442,6 +452,11 @@ Pool.prototype._startTimer = function _startTimer() { this._timer = setTimeout(destroy, this.load.timeout); }; +/** + * Stop the stall timer (done on chain sync). + * @private + */ + Pool.prototype._stopTimer = function _stopTimer() { if (this._timer == null) return; @@ -450,6 +465,14 @@ Pool.prototype._stopTimer = function _stopTimer() { this._timer = null; }; +/** + * Start the stall interval (shorter than the + * stall timer, inteded to give warnings and + * reset the stall *timer* if the chain is + * busy). Stopped on chain sync. + * @private + */ + Pool.prototype._startInterval = function _startInterval() { var self = this; @@ -472,6 +495,11 @@ Pool.prototype._startInterval = function _startInterval() { this._interval = setInterval(load, this.load.interval); }; +/** + * Stop the stall interval. + * @private + */ + Pool.prototype._stopInterval = function _stopInterval() { if (this._interval == null) return; @@ -480,6 +508,12 @@ Pool.prototype._stopInterval = function _stopInterval() { this._interval = null; }; +/** + * Add a loader peer. Necessary for + * a sync to even begin. + * @private + */ + Pool.prototype._addLoader = function _addLoader() { var self = this; var peer; @@ -529,6 +563,11 @@ Pool.prototype.startSync = function startSync() { this.sync(); }; +/** + * Send a sync to each peer. + * @private + */ + Pool.prototype.sync = function sync() { var i; @@ -564,6 +603,14 @@ Pool.prototype.stopSync = function stopSync() { this.peers.regular[i].syncSent = false; }; +/** + * Handle `headers` packet from a given peer. + * @private + * @param {Headers[]} headers + * @param {Peer} peer + * @param {Function} callback + */ + Pool.prototype._handleHeaders = function _handleHeaders(headers, peer, callback) { var self = this; var ret = {}; @@ -633,6 +680,14 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer, callback) }); }; +/** + * Handle `inv` packet from peer (containing only BLOCK types). + * @private + * @param {Hash[]} hashes + * @param {Peer} peer + * @param {Function} callback + */ + Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer, callback) { var self = this; @@ -698,6 +753,15 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer, callback) { }); }; +/** + * Handle `inv` packet from peer (containing only BLOCK types). + * Potentially request headers if headers mode is enabled. + * @private + * @param {Hash[]} hashes + * @param {Peer} peer + * @param {Function} callback + */ + Pool.prototype._handleInv = function _handleInv(hashes, peer, callback) { var self = this; var unlock = this.locker.lock(_handleInv, [hashes, peer, callback]); @@ -726,6 +790,14 @@ Pool.prototype._handleInv = function _handleInv(hashes, peer, callback) { }); }; +/** + * Handle `block` packet. Attempt to add to chain. + * @private + * @param {MemBlock|MerkleBlock} block + * @param {Peer} peer + * @param {Function} callback + */ + Pool.prototype._handleBlock = function _handleBlock(block, peer, callback) { var self = this; var requested; @@ -832,6 +904,13 @@ Pool.prototype.sendAlert = function sendAlert(details, key) { this.peers.leeches[i].sendAlert(details, key); }; +/** + * Create a base peer with no special purpose. + * @private + * @param {Object} options + * @returns {Peer} + */ + Pool.prototype._createPeer = function _createPeer(options) { var self = this; @@ -1038,6 +1117,13 @@ Pool.prototype._createPeer = function _createPeer(options) { return peer; }; +/** + * Handle an alert packet. + * @private + * @param {AlertPacket} details + * @param {Peer} peer + */ + Pool.prototype._handleAlert = function _handleAlert(details, peer) { var hash = new Buffer(details.hash, 'hex'); var signature = details.signature; @@ -1068,6 +1154,14 @@ Pool.prototype._handleAlert = function _handleAlert(details, peer) { this.emit('alert', details, peer); }; +/** + * Handle a transaction. Attempt to add to mempool. + * @private + * @param {TX} tx + * @param {Peer} peer + * @param {Function} callback + */ + Pool.prototype._handleTX = function _handleTX(tx, peer, callback) { var self = this; var requested; @@ -1115,6 +1209,12 @@ Pool.prototype._handleTX = function _handleTX(tx, peer, callback) { }); }; +/** + * Create a leech peer from an existing socket. + * @private + * @param {net.Socket} socket + */ + Pool.prototype._addLeech = function _addLeech(socket) { var self = this; var peer; @@ -1140,6 +1240,12 @@ Pool.prototype._addLeech = function _addLeech(socket) { }); }; +/** + * Create a regular non-loader peer. These primarily + * exist for transaction relaying. + * @private + */ + Pool.prototype._addPeer = function _addPeer() { var self = this; var peer, host; @@ -1405,8 +1511,14 @@ Pool.prototype.scheduleRequests = function scheduleRequests(peer) { }); }; +/** + * Send scheduled requests in the request queues. + * @private + * @param {Peer} peer + */ + Pool.prototype._sendRequests = function _sendRequests(peer) { - var size, items; + var i, size, items; if (this.chain.isBusy()) return; @@ -1437,9 +1549,8 @@ Pool.prototype._sendRequests = function _sendRequests(peer) { peer.queue.block = peer.queue.block.slice(size); } - items = items.map(function(item) { - return item.start(); - }); + for (i = 0; i < items.length; i++) + items[i] = items[i].start(); bcoin.debug( 'Requesting %d/%d blocks from peer with getdata (%s).', @@ -1453,6 +1564,7 @@ Pool.prototype._sendRequests = function _sendRequests(peer) { /** * Fulfill a requested block. * @param {Hash} + * @returns {LoadRequest|null} */ Pool.prototype.fulfill = function fulfill(hash) { diff --git a/lib/bcoin/protocol/framer.js b/lib/bcoin/protocol/framer.js index 24b69e2a..59fbcfd7 100644 --- a/lib/bcoin/protocol/framer.js +++ b/lib/bcoin/protocol/framer.js @@ -455,6 +455,13 @@ Framer.verack = function verack() { return DUMMY; }; +/** + * Create an inv, getdata, or notfound packet. + * @private + * @param {InvItem[]} items + * @returns {Buffer} + */ + Framer._inv = function _inv(items, writer) { var p = new BufferWriter(writer); var type; @@ -571,6 +578,15 @@ Framer.getBlocks = function getBlocks(data, writer) { return Framer._getBlocks(data, writer, false); }; +/** + * Create a getblocks or getheaders packet. + * @private + * @param {GetBlocksPacket} data + * @param {BufferWriter|null} writer + * @param {Boolean} headers + * @returns {Buffer} + */ + Framer._getBlocks = function _getBlocks(data, writer, headers) { var version = data.version; var locator = data.locator; diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index a2667bbb..3ee1dbf6 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -45,6 +45,12 @@ function Witness(options) { this.fromOptions(options); } +/** + * Inject properties from options object. + * @private + * @param {Object} options + */ + Witness.prototype.fromOptions = function fromOptions(options) { this.items = options.items || options; this.redeem = null; @@ -52,14 +58,31 @@ Witness.prototype.fromOptions = function fromOptions(options) { return this; }; +/** + * Instantiate witness from options. + * @param {Object} options + * @returns {Witness} + */ + Witness.fromOptions = function fromOptions(options) { return new Witness().fromOptions(options); }; +/** + * Convert witness to an array of buffers. + * @returns {Buffer[]} + */ + Witness.prototype.toArray = function toArray() { return this.items.slice(); }; +/** + * Insantiate witness from an array of buffers. + * @param {Buffer[]} items + * @returns {Witness} + */ + Witness.fromArray = function fromArray(items) { return new Witness(items); }; @@ -270,10 +293,21 @@ Witness.prototype.toRaw = function toRaw(writer) { return p; }; +/** + * Convert witness to a hex string. + * @returns {String} + */ + Witness.prototype.toJSON = function toJSON() { return this.toRaw().toString('hex'); }; +/** + * Insantiate witness from a hex string. + * @param {String} json + * @returns {Witness} + */ + Witness.fromJSON = function fromJSON(json) { return Witness.fromRaw(json, 'hex'); }; @@ -405,8 +439,8 @@ Witness.prototype.__defineGetter__('length', function() { return this.items.length; }); -Witness.prototype.__defineSetter__('length', function(len) { - return this.items.length = len; +Witness.prototype.__defineSetter__('length', function(length) { + return this.items.length = length; }); /** @@ -441,6 +475,12 @@ Witness.encodeItem = function encodeItem(data) { return data; }; +/** + * Inject properties from serialized data. + * @private + * @param {Buffer} data + */ + Witness.prototype.fromRaw = function fromRaw(data) { var p = bcoin.reader(data); var chunkCount = p.readVarint(); @@ -568,8 +608,8 @@ Stack.prototype.__defineGetter__('length', function() { return this.items.length; }); -Stack.prototype.__defineSetter__('length', function(value) { - return this.items.length = value; +Stack.prototype.__defineSetter__('length', function(length) { + return this.items.length = length; }); /** @@ -725,7 +765,6 @@ Stack.prototype._swap = function _swap(i1, i2) { * @throws {ScriptError} */ - Stack.prototype.toalt = function toalt(alt) { if (this.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', opcodes.OP_TOALTSTACK); @@ -836,6 +875,14 @@ Stack.prototype.roll = function roll(flags) { return this._pickroll(opcodes.OP_ROLL, flags); }; +/** + * Perform a pick or roll. + * @private + * @param {Number} op + * @param {VerifyFlags} flags + * @throws {ScriptError} + */ + Stack.prototype._pickroll = function pickroll(op, flags) { var val, n; @@ -1022,10 +1069,10 @@ Stack.isStack = function isStack(obj) { * @constructor * @param {Buffer|Array|Object|NakedScript} code - Array * of script code or a serialized script Buffer. - * @property {Array} code - Script code. + * @property {Array} code - Parsed script code. * @property {Buffer?} raw - Serialized script. * @property {Script?} redeem - Redeem script. - * @property {Number} length + * @property {Number} length - Number of parsed opcodes. */ function Script(options) { @@ -1043,6 +1090,12 @@ function Script(options) { this.fromOptions(options); } +/** + * Inject properties from options object. + * @private + * @param {Object} options + */ + Script.prototype.fromOptions = function fromOptions(options) { var code, raw; @@ -1075,6 +1128,12 @@ Script.prototype.fromOptions = function fromOptions(options) { return this; }; +/** + * Insantiate script from options object. + * @param {Object} options + * @returns {Script} + */ + Script.fromOptions = function fromOptions(options) { if (options instanceof Script) return options; @@ -1170,10 +1229,21 @@ Script.prototype.toRaw = function toRaw(writer) { return this.raw; }; +/** + * Convert script to a hex string. + * @returns {String} + */ + Script.prototype.toJSON = function toJSON() { return this.toRaw().toString('hex'); }; +/** + * Instantiate script from a hex string. + * @params {String} json + * @returns {Script} + */ + Script.fromJSON = function fromJSON(json) { return Script.fromRaw(json, 'hex'); }; @@ -2297,7 +2367,8 @@ Script.isMinimal = function isMinimal(data, opcode, flags) { }; /** - * Test a buffer to see if it is valid script code (no non-existent opcodes). + * Test a buffer to see if it is valid + * script code (no non-existent opcodes). * @param {Buffer} raw * @returns {Boolean} */ @@ -2359,9 +2430,9 @@ Script.fromPubkeyhash = function fromPubkeyhash(hash) { /** * Create a pay-to-multisig script. - * @param {Buffer[]} keys * @param {Number} m * @param {Number} n + * @param {Buffer[]} keys * @returns {Script} */ @@ -2698,6 +2769,9 @@ Script.prototype.isNulldata = function isNulldata(sloppy) { if (this.raw[0] !== opcodes.OP_RETURN) return false; + if (this.raw.length === 1) + return true; + if (sloppy) { for (i = 1; i < this.code.length; i++) { op = this.code[i]; @@ -2711,6 +2785,14 @@ Script.prototype.isNulldata = function isNulldata(sloppy) { return true; } + if (this.raw.length === 2) { + if (this.raw[1] === opcodes.OP_0) + return true; + if (this.raw[1] >= opcodes.OP_1 && this.raw[1] <= opcodes.OP_16) + return true; + return false; + } + if (this.raw[1] >= 0x01 && this.raw[1] <= 0x4b) { if (this.raw[1] + 2 !== this.raw.length) return false; @@ -2736,15 +2818,10 @@ Script.prototype.isNulldata = function isNulldata(sloppy) { */ Script.prototype.isCommitment = function isCommitment() { - if (this.raw.length < 38) - return false; - if (this.raw[0] !== opcodes.OP_RETURN) - return false; - if (this.raw[1] !== 0x24) - return false; - if (this.raw.readUInt32BE(2, true) !== 0xaa21a9ed) - return false; - return true; + return this.raw.length >= 38 + && this.raw[0] === opcodes.OP_RETURN + && this.raw[1] === 0x24 + && this.raw.readUInt32BE(2, true) === 0xaa21a9ed; }; /** @@ -2862,10 +2939,13 @@ Script.prototype.isUnknownInput = function isUnknownInput() { Script.prototype.isPubkeyInput = function isPubkeyInput() { if (this.raw.length < 10) return false; + if (this.raw.length > 78) return false; + if (this.raw[0] > opcodes.OP_PUSHDATA4) return false; + return this.code.length === 1 && Script.isSignature(this.code[0].data); }; @@ -2878,10 +2958,13 @@ Script.prototype.isPubkeyInput = function isPubkeyInput() { Script.prototype.isPubkeyhashInput = function isPubkeyhashInput() { if (this.raw.length < 44) return false; + if (this.raw.length > 148) return false; + if (this.raw[0] > opcodes.OP_PUSHDATA4) return false; + return this.code.length === 2 && Script.isSignature(this.code[0].data) && Script.isKey(this.code[1].data); @@ -3044,10 +3127,12 @@ Script.prototype.getCoinbaseFlags = function getCoinbaseFlags() { if (height !== -1) index++; - if (this.code[1].data && this.code[1].data.length <= 6) - extraNonce = new bn(this.code[1].data, 'le').toNumber(); + extraNonce = this.getNumber(1); + + if (extraNonce) + extraNonce = extraNonce.toNumber(); else - extraNonce = this.getSmall(1); + extraNonce = -1; flags = Script.encode(this.code.slice(index)); @@ -3228,8 +3313,8 @@ Script.prototype.__defineGetter__('length', function() { return this.code.length; }); -Script.prototype.__defineSetter__('length', function(len) { - return this.code.length = len; +Script.prototype.__defineSetter__('length', function(length) { + return this.code.length = length; }); /** @@ -4105,10 +4190,9 @@ Script.sign = function sign(msg, key, type) { }; /** - * Create a script from a serialized buffer. - * @param {Buffer|String} data - Serialized script. - * @param {String?} enc - Either `"hex"` or `null`. - * @returns {Script} + * Inject properties from serialized data. + * @private + * @param {Buffer} */ Script.prototype.fromRaw = function fromRaw(data) { @@ -4121,6 +4205,13 @@ Script.prototype.fromRaw = function fromRaw(data) { return this; }; +/** + * Create a script from a serialized buffer. + * @param {Buffer|String} data - Serialized script. + * @param {String?} enc - Either `"hex"` or `null`. + * @returns {Script} + */ + Script.fromRaw = function fromRaw(data, enc) { if (typeof data === 'string') data = new Buffer(data, enc); @@ -4449,9 +4540,13 @@ Opcode.isOpcode = function isOpcode(obj) { /** * Witness Program * @constructor - * @private * @param {Number} version * @param {Buffer} data + * @property {Number} version - Ranges from 0 to 16. + * @property {String|null} type - Null if malformed. `unknown` if unknown + * version (treated as anyone-can-spend). Otherwise one of `witnesspubkeyhash` + * or `witnessscripthash`. + * @property {Buffer} data - The hash (for now). */ function Program(version, data) { @@ -4475,10 +4570,21 @@ function Program(version, data) { } } +/** + * Test whether the program is either + * an unknown version or malformed. + * @returns {Boolean} + */ + Program.prototype.isUnknown = function isUnknown() { return !this.type || this.type === 'unknown'; }; +/** + * Inspect the program. + * @returns {String} + */ + Program.prototype.inspect = function inspect() { return '= 0 && value <= 0xffffffff; +}; + +/** + * Test whether an object is a 160 bit hash (hex string). + * @param {String?} value + * @returns {Boolean} + */ + +utils.isHex160 = function isHex160(hash) { + return utils.isHex(hash) && hash.length === 40; +}; + +/** + * Test whether an object is a 256 bit hash (hex string). + * @param {String?} value + * @returns {Boolean} + */ + +utils.isHex256 = function isHex256(hash) { + return utils.isHex(hash) && hash.length === 64; }; /** @@ -779,16 +869,6 @@ utils.isFloat = function isFloat(value) { && value !== '-'; }; -/** - * Test whether an object is a finite number and int. - * @param {Number?} value - * @returns {Boolean} - */ - -utils.isInt = function isInt(value) { - return utils.isNumber(value) && value % 1 === 0; -}; - /** * Test and validate a satoshi value (Number). * @param {Number?} value @@ -1113,7 +1193,7 @@ utils.U32 = new bn(0xffffffff); utils.U64 = new bn('ffffffffffffffff', 'hex'); /** - * Create an 8 byte nonce. + * Create a 64 bit nonce. * @returns {BN} */ @@ -2390,7 +2470,7 @@ utils.binarySearch = function binarySearch(items, key, compare, insert) { * Perform a binary insert on a sorted array. * @param {Array} items * @param {Object} item - * @param {Function?} compare + * @param {Function} compare * @returns {Number} Length. */ @@ -2404,7 +2484,7 @@ utils.binaryInsert = function binaryInsert(items, item, compare) { * Perform a binary removal on a sorted array. * @param {Array} items * @param {Object} item - * @param {Function?} compare + * @param {Function} compare * @returns {Number} Length. */ @@ -2415,24 +2495,3 @@ utils.binaryRemove = function binaryRemove(items, item, compare) { items.splice(i, 1); return true; }; - -/** - * Reference to the global object. - * @const {Object} - */ - -utils.global = (function() { - /* global self */ - - if (this) - return this; - - if (typeof window !== 'undefined') - return window; - - if (typeof self !== 'undefined') - return self; - - if (typeof global !== 'undefined') - return global; -})(); diff --git a/lib/bcoin/workers.js b/lib/bcoin/workers.js index ea72076d..cca5bde6 100644 --- a/lib/bcoin/workers.js +++ b/lib/bcoin/workers.js @@ -686,7 +686,7 @@ Master.listen = function listen(id, options) { try { result = jobs[body.name].apply(jobs, body.items); } catch (e) { - bcoin.debug(e.stack + ''); + bcoin.error(e); return master.send(job, 'response', [{ message: e.message, stack: e.stack + ''