comments. asserts. refactor.
This commit is contained in:
parent
b473c0a31f
commit
cc22e97dae
@ -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
|
||||
*/
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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';
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 '<Outpoint: ' + this.hash + '/' + this.index + '>';
|
||||
};
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 '<Program:'
|
||||
+ ' version=' + this.version
|
||||
|
||||
183
lib/bcoin/tx.js
183
lib/bcoin/tx.js
@ -19,7 +19,7 @@ var BufferWriter = require('./writer');
|
||||
* A static transaction object.
|
||||
* @exports TX
|
||||
* @constructor
|
||||
* @param {NakedTX} data - Transaction fields.
|
||||
* @param {NakedTX} options - Transaction fields.
|
||||
* @property {String} type - "tx" (inv type).
|
||||
* @property {Number} version - Transaction version. Note that BCoin reads
|
||||
* versions as unsigned even though they are signed at the protocol level.
|
||||
@ -48,9 +48,9 @@ var BufferWriter = require('./writer');
|
||||
* witness is present. All zeroes if coinbase).
|
||||
*/
|
||||
|
||||
function TX(data) {
|
||||
function TX(options) {
|
||||
if (!(this instanceof TX))
|
||||
return new TX(data);
|
||||
return new TX(options);
|
||||
|
||||
this.version = 1;
|
||||
this.flag = 1;
|
||||
@ -78,44 +78,66 @@ function TX(data) {
|
||||
this._hashSequence = null;
|
||||
this._hashOutputs = null;
|
||||
|
||||
if (data)
|
||||
this.fromOptions(data);
|
||||
if (options)
|
||||
this.fromOptions(options);
|
||||
}
|
||||
|
||||
TX.prototype.fromOptions = function fromOptions(data) {
|
||||
/**
|
||||
* Inject properties from options object.
|
||||
* @private
|
||||
* @param {NakedTX} options
|
||||
*/
|
||||
|
||||
TX.prototype.fromOptions = function fromOptions(options) {
|
||||
var i;
|
||||
|
||||
assert(data, 'TX data is required.');
|
||||
assert(typeof data.version === 'number');
|
||||
assert(typeof data.flag === 'number');
|
||||
assert(Array.isArray(data.inputs));
|
||||
assert(Array.isArray(data.outputs));
|
||||
assert(typeof data.locktime === 'number');
|
||||
assert(options, 'TX data is required.');
|
||||
assert(utils.isNumber(options.version));
|
||||
assert(utils.isNumber(options.flag));
|
||||
assert(Array.isArray(options.inputs));
|
||||
assert(Array.isArray(options.outputs));
|
||||
assert(utils.isNumber(options.locktime));
|
||||
|
||||
this.version = data.version;
|
||||
this.flag = data.flag;
|
||||
this.locktime = data.locktime;
|
||||
this.ts = data.ts || 0;
|
||||
this.block = data.block || null;
|
||||
this.index = data.index != null ? data.index : -1;
|
||||
this.ps = this.ts === 0 ? (data.ps != null ? data.ps : utils.now()) : 0;
|
||||
this.height = data.height != null ? data.height : -1;
|
||||
this.version = options.version;
|
||||
this.flag = options.flag;
|
||||
this.locktime = options.locktime;
|
||||
this.ts = options.ts || 0;
|
||||
this.block = options.block || null;
|
||||
this.index = options.index != null
|
||||
? options.index
|
||||
: -1;
|
||||
this.ps = this.ts === 0
|
||||
? (options.ps != null ? options.ps : utils.now())
|
||||
: 0;
|
||||
this.height = options.height != null
|
||||
? options.height
|
||||
: -1;
|
||||
|
||||
this._raw = data._raw || null;
|
||||
this._size = data._size || null;
|
||||
this._witnessSize = data._witnessSize != null ? data._witnessSize : null;
|
||||
this._raw = options._raw || null;
|
||||
this._size = options._size != null
|
||||
? options._size
|
||||
: 0;
|
||||
this._witnessSize = options._witnessSize != null
|
||||
? options._witnessSize
|
||||
: null;
|
||||
|
||||
for (i = 0; i < data.inputs.length; i++)
|
||||
this.inputs.push(new bcoin.input(data.inputs[i]));
|
||||
for (i = 0; i < options.inputs.length; i++)
|
||||
this.inputs.push(new bcoin.input(options.inputs[i]));
|
||||
|
||||
for (i = 0; i < data.outputs.length; i++)
|
||||
this.outputs.push(new bcoin.output(data.outputs[i]));
|
||||
for (i = 0; i < options.outputs.length; i++)
|
||||
this.outputs.push(new bcoin.output(options.outputs[i]));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
TX.fromOptions = function fromOptions(data) {
|
||||
return new TX().fromOptions(data);
|
||||
/**
|
||||
* Instantiate TX from options object.
|
||||
* @param {NakedTX} options
|
||||
* @returns {TX}
|
||||
*/
|
||||
|
||||
TX.fromOptions = function fromOptions(options) {
|
||||
return new TX().fromOptions(options);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -271,21 +293,13 @@ TX.prototype.toNormal = function toNormal(writer) {
|
||||
|
||||
/**
|
||||
* Serialize the transaction with the
|
||||
* witness vector, regardless of whether it
|
||||
* is a witness transaction or not.
|
||||
* witness vector. Will use normal
|
||||
* serialization if witness vector is empty.
|
||||
* @returns {Buffer} Serialized transaction.
|
||||
*/
|
||||
|
||||
TX.prototype.toWitness = function toWitness(writer) {
|
||||
var raw = this.getRaw();
|
||||
if (TX.isWitness(raw)) {
|
||||
if (writer) {
|
||||
writer.writeBytes(raw);
|
||||
return writer;
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
return this.frameWitness(writer);
|
||||
return this.toRaw(writer);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -433,6 +447,15 @@ TX.prototype.signatureHash = function signatureHash(index, prev, type, version)
|
||||
assert(false, 'Unknown sighash version.');
|
||||
};
|
||||
|
||||
/**
|
||||
* Legacy sighashing -- O(n^2).
|
||||
* @private
|
||||
* @param {Number} index
|
||||
* @param {Script} prev
|
||||
* @param {SighashType} type
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
var p = new BufferWriter();
|
||||
var empty = new Script();
|
||||
@ -527,6 +550,15 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
|
||||
return utils.hash256(p.render());
|
||||
};
|
||||
|
||||
/**
|
||||
* Witness sighashing -- O(n).
|
||||
* @private
|
||||
* @param {Number} index
|
||||
* @param {Script} prev
|
||||
* @param {SighashType} type
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, type) {
|
||||
var p = new BufferWriter();
|
||||
var i, hashPrevouts, hashSequence, hashOutputs;
|
||||
@ -997,8 +1029,10 @@ TX.prototype.fillCoins = function fillCoins(coins) {
|
||||
var total = 0;
|
||||
var key, i, input, prevout, map, coin;
|
||||
|
||||
if ((coins instanceof bcoin.coin) || (coins instanceof TX))
|
||||
if ((coins instanceof bcoin.coin)
|
||||
|| (coins instanceof TX)) {
|
||||
coins = [coins];
|
||||
}
|
||||
|
||||
if (Array.isArray(coins)) {
|
||||
map = {};
|
||||
@ -1869,17 +1903,21 @@ TX.prototype.toJSON = function toJSON() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a deserialized JSON transaction object.
|
||||
* Inject properties from a json object.
|
||||
* @private
|
||||
* @param {Object} json
|
||||
* @returns {NakedTX} A "naked" transaction (a
|
||||
* plain javascript object which is suitable
|
||||
* for passing to the TX constructor).
|
||||
*/
|
||||
|
||||
TX.prototype.fromJSON = function fromJSON(json) {
|
||||
var i, input, output;
|
||||
|
||||
assert(json, 'TX data is required.');
|
||||
assert.equal(json.type, 'tx');
|
||||
assert(utils.isNumber(json.version));
|
||||
assert(utils.isNumber(json.flag));
|
||||
assert(Array.isArray(json.inputs));
|
||||
assert(Array.isArray(json.outputs));
|
||||
assert(utils.isNumber(json.locktime));
|
||||
|
||||
this.block = json.block ? utils.revHex(json.block) : null;
|
||||
this.height = json.height;
|
||||
@ -1932,10 +1970,9 @@ TX.fromRaw = function fromRaw(data, enc) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse tx packet (will automatically switch to witness
|
||||
* parsing if a witness transaction is detected).
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {NakedTX}
|
||||
* Inject properties from serialized data.
|
||||
* @private
|
||||
* @param {Buffer|BufferReader} data
|
||||
*/
|
||||
|
||||
TX.prototype.fromRaw = function fromRaw(data) {
|
||||
@ -1964,22 +2001,25 @@ TX.prototype.fromRaw = function fromRaw(data) {
|
||||
|
||||
this.locktime = p.readU32();
|
||||
|
||||
this._raw = p.endData();
|
||||
this._size = this._raw.length;
|
||||
this._witnessSize = 0;
|
||||
if (!this.mutable) {
|
||||
this._raw = p.endData();
|
||||
this._size = this._raw.length;
|
||||
this._witnessSize = 0;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse tx packet in witness serialization.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @returns {NakedTX}
|
||||
* Inject properties from serialized
|
||||
* data (witness serialization).
|
||||
* @private
|
||||
* @param {Buffer|BufferReader} data
|
||||
*/
|
||||
|
||||
TX.prototype.fromWitness = function fromWitness(data) {
|
||||
var p = bcoin.reader(data);
|
||||
var i, marker, inCount, outCount, witness, hasWitness;
|
||||
var i, marker, inCount, outCount, witness, hasWitness, witnessSize;
|
||||
|
||||
p.start();
|
||||
|
||||
@ -2015,39 +2055,43 @@ TX.prototype.fromWitness = function fromWitness(data) {
|
||||
if (!hasWitness)
|
||||
throw new Error('Witness tx has an empty witness.');
|
||||
|
||||
this._witnessSize = p.end() + 2;
|
||||
witnessSize = p.end() + 2;
|
||||
|
||||
this.locktime = p.readU32();
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether data is a witness transaction.
|
||||
* @param {Buffer|BufferReader} p
|
||||
* @param {Buffer|BufferReader} data
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
TX.isWitness = function isWitness(p) {
|
||||
if (Buffer.isBuffer(p)) {
|
||||
if (p.length < 12)
|
||||
TX.isWitness = function isWitness(data) {
|
||||
if (Buffer.isBuffer(data)) {
|
||||
if (data.length < 12)
|
||||
return false;
|
||||
|
||||
return p[4] === 0 && p[5] !== 0;
|
||||
return data[4] === 0 && data[5] !== 0;
|
||||
}
|
||||
|
||||
if (p.left() < 12)
|
||||
if (data.left() < 12)
|
||||
return false;
|
||||
|
||||
return p.data[p.offset + 4] === 0 && p.data[p.offset + 5] !== 0;
|
||||
return data.data[data.offset + 4] === 0
|
||||
&& data.data[data.offset + 5] !== 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize transaction without witness.
|
||||
* @param {NakedTX|TX} tx
|
||||
* @private
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
@ -2081,7 +2125,7 @@ TX.prototype.frameNormal = function frameNormal(writer) {
|
||||
/**
|
||||
* Serialize transaction with witness. Calculates the witness
|
||||
* size as it is framing (exposed on return value as `_witnessSize`).
|
||||
* @param {NakedTX|TX} tx
|
||||
* @private
|
||||
* @param {BufferWriter?} writer - A buffer writer to continue writing from.
|
||||
* @returns {Buffer} Returns a BufferWriter if `writer` was passed in.
|
||||
*/
|
||||
@ -2179,12 +2223,11 @@ TX.prototype.toExtended = function toExtended(saveCoins, writer) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a transaction in "extended" serialization format.
|
||||
* Inject properties from "extended" serialization format.
|
||||
* @param {Buffer} data
|
||||
* @param {Boolean?} saveCoins - If true, the function will
|
||||
* attempt to parse the coins.
|
||||
* @param {String?} enc - One of `"hex"` or `null`.
|
||||
* @returns {NakedTX} - A "naked" transaction object.
|
||||
*/
|
||||
|
||||
TX.prototype.fromExtended = function fromExtended(data, saveCoins) {
|
||||
|
||||
@ -151,16 +151,6 @@
|
||||
* @global
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Program
|
||||
* @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 - Usually the hash.
|
||||
* @global
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Orphan
|
||||
* @property {Hash} hash - Orphan TX hash.
|
||||
|
||||
@ -18,8 +18,30 @@ var utils = exports;
|
||||
var assert = require('assert');
|
||||
var bn = require('bn.js');
|
||||
var util = require('util');
|
||||
var Number, Math, Date;
|
||||
var crypto, supersha, hash, aes;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Whether we're in a browser or not.
|
||||
* @const {Boolean}
|
||||
@ -41,6 +63,10 @@ if (!utils.isBrowser) {
|
||||
aes = require('./aes');
|
||||
}
|
||||
|
||||
Number = utils.global.Number;
|
||||
Math = utils.global.Math;
|
||||
Date = utils.global.Date;
|
||||
|
||||
/**
|
||||
* The home directory.
|
||||
* @const {String}
|
||||
@ -611,8 +637,7 @@ utils.revHex = function revHex(data) {
|
||||
var out = '';
|
||||
var i;
|
||||
|
||||
if (!data)
|
||||
return data;
|
||||
assert(typeof data === 'string');
|
||||
|
||||
for (i = 0; i < data.length; i += 2)
|
||||
out = data.slice(i, i + 2) + out;
|
||||
@ -757,13 +782,78 @@ utils.satoshi = function satoshi(value) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether a number is both a Number and finite.
|
||||
* Test whether a number is below MAX_SAFE_INTEGER.
|
||||
* @param {Number} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
utils.isSafeInteger = function isSafeInteger(value) {
|
||||
if (Number.isSafeInteger)
|
||||
return Number.isSafeInteger(value);
|
||||
return Math.abs(value) <= utils.MAX_SAFE_INTEGER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether a number is Number,
|
||||
* finite, and below MAX_SAFE_INTEGER.
|
||||
* @param {Number?} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
utils.isNumber = function isNumber(value) {
|
||||
return typeof value === 'number' && isFinite(value);
|
||||
return typeof value === 'number'
|
||||
&& isFinite(value)
|
||||
&& utils.isSafeInteger(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether an object is an int.
|
||||
* @param {Number?} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
utils.isInt = function isInt(value) {
|
||||
return utils.isNumber(value) && value % 1 === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether an object is an int32.
|
||||
* @param {Number?} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
utils.isInt32 = function isInt32(value) {
|
||||
return utils.isInt(value) && Math.abs(value) <= 0x7fffffff;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether an object is a uint32.
|
||||
* @param {Number?} value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
utils.isUInt32 = function isUInt32(value) {
|
||||
return utils.isInt(value) && value >= 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;
|
||||
})();
|
||||
|
||||
@ -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 + ''
|
||||
|
||||
Loading…
Reference in New Issue
Block a user