primitives: classify primitives.

This commit is contained in:
Christopher Jeffrey 2017-11-15 18:54:47 -08:00
parent ca08d6d97e
commit daa55a05bc
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
27 changed files with 14507 additions and 14404 deletions

File diff suppressed because it is too large Load Diff

View File

@ -19,18 +19,15 @@ const InvItem = require('../primitives/invitem');
const ZERO = new BN(0); const ZERO = new BN(0);
/** /**
* Chain Entry
* Represents an entry in the chain. Unlike * Represents an entry in the chain. Unlike
* other bitcoin fullnodes, we store the * other bitcoin fullnodes, we store the
* chainwork _with_ the entry in order to * chainwork _with_ the entry in order to
* avoid reading the entire chain index on * avoid reading the entire chain index on
* boot and recalculating the chainworks. * boot and recalculating the chainworks.
* @alias module:blockchain.ChainEntry * @alias module:blockchain.ChainEntry
* @constructor
* @param {Object?} options
* @property {Hash} hash * @property {Hash} hash
* @property {Number} version - Transaction version. Note that Bcoin reads * @property {Number} version
* versions as unsigned even though they are signed at the protocol level.
* This value will never be negative.
* @property {Hash} prevBlock * @property {Hash} prevBlock
* @property {Hash} merkleRoot * @property {Hash} merkleRoot
* @property {Number} time * @property {Number} time
@ -38,13 +35,17 @@ const ZERO = new BN(0);
* @property {Number} nonce * @property {Number} nonce
* @property {Number} height * @property {Number} height
* @property {BN} chainwork * @property {BN} chainwork
* @property {ReversedHash} rhash - Reversed block hash (uint256le). * @property {ReversedHash} rhash
*/ */
function ChainEntry(options) { class ChainEntry {
if (!(this instanceof ChainEntry)) /**
return new ChainEntry(options); * Create a chain entry.
* @constructor
* @param {Object?} options
*/
constructor(options) {
this.hash = encoding.NULL_HASH; this.hash = encoding.NULL_HASH;
this.version = 1; this.version = 1;
this.prevBlock = encoding.NULL_HASH; this.prevBlock = encoding.NULL_HASH;
@ -59,20 +60,13 @@ function ChainEntry(options) {
this.fromOptions(options); this.fromOptions(options);
} }
/**
* The max chainwork (1 << 256).
* @const {BN}
*/
ChainEntry.MAX_CHAINWORK = new BN(1).ushln(256);
/** /**
* Inject properties from options. * Inject properties from options.
* @private * @private
* @param {Object} options * @param {Object} options
*/ */
ChainEntry.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
assert(options, 'Block data is required.'); assert(options, 'Block data is required.');
assert(typeof options.hash === 'string'); assert(typeof options.hash === 'string');
assert((options.version >>> 0) === options.version); assert((options.version >>> 0) === options.version);
@ -95,7 +89,7 @@ ChainEntry.prototype.fromOptions = function fromOptions(options) {
this.chainwork = options.chainwork || ZERO; this.chainwork = options.chainwork || ZERO;
return this; return this;
}; }
/** /**
* Instantiate chainentry from options. * Instantiate chainentry from options.
@ -104,23 +98,23 @@ ChainEntry.prototype.fromOptions = function fromOptions(options) {
* @returns {ChainEntry} * @returns {ChainEntry}
*/ */
ChainEntry.fromOptions = function fromOptions(options, prev) { static fromOptions(options, prev) {
return new ChainEntry().fromOptions(options, prev); return new this().fromOptions(options, prev);
}; }
/** /**
* Calculate the proof: (1 << 256) / (target + 1) * Calculate the proof: (1 << 256) / (target + 1)
* @returns {BN} proof * @returns {BN} proof
*/ */
ChainEntry.prototype.getProof = function getProof() { getProof() {
const target = consensus.fromCompact(this.bits); const target = consensus.fromCompact(this.bits);
if (target.isNeg() || target.isZero()) if (target.isNeg() || target.isZero())
return new BN(0); return new BN(0);
return ChainEntry.MAX_CHAINWORK.div(target.iaddn(1)); return ChainEntry.MAX_CHAINWORK.div(target.iaddn(1));
}; }
/** /**
* Calculate the chainwork by * Calculate the chainwork by
@ -128,23 +122,23 @@ ChainEntry.prototype.getProof = function getProof() {
* @returns {BN} chainwork * @returns {BN} chainwork
*/ */
ChainEntry.prototype.getChainwork = function getChainwork(prev) { getChainwork(prev) {
const proof = this.getProof(); const proof = this.getProof();
if (!prev) if (!prev)
return proof; return proof;
return proof.iadd(prev.chainwork); return proof.iadd(prev.chainwork);
}; }
/** /**
* Test against the genesis block. * Test against the genesis block.
* @returns {Boolean} * @returns {Boolean}
*/ */
ChainEntry.prototype.isGenesis = function isGenesis() { isGenesis() {
return this.height === 0; return this.height === 0;
}; }
/** /**
* Test whether the entry contains an unknown version bit. * Test whether the entry contains an unknown version bit.
@ -152,7 +146,7 @@ ChainEntry.prototype.isGenesis = function isGenesis() {
* @returns {Boolean} * @returns {Boolean}
*/ */
ChainEntry.prototype.hasUnknown = function hasUnknown(network) { hasUnknown(network) {
const TOP_MASK = consensus.VERSION_TOP_MASK; const TOP_MASK = consensus.VERSION_TOP_MASK;
const TOP_BITS = consensus.VERSION_TOP_BITS; const TOP_BITS = consensus.VERSION_TOP_BITS;
const bits = (this.version & TOP_MASK) >>> 0; const bits = (this.version & TOP_MASK) >>> 0;
@ -161,7 +155,7 @@ ChainEntry.prototype.hasUnknown = function hasUnknown(network) {
return false; return false;
return (this.version & network.unknownBits) !== 0; return (this.version & network.unknownBits) !== 0;
}; }
/** /**
* Test whether the entry contains a version bit. * Test whether the entry contains a version bit.
@ -169,18 +163,18 @@ ChainEntry.prototype.hasUnknown = function hasUnknown(network) {
* @returns {Boolean} * @returns {Boolean}
*/ */
ChainEntry.prototype.hasBit = function hasBit(bit) { hasBit(bit) {
return consensus.hasBit(this.version, bit); return consensus.hasBit(this.version, bit);
}; }
/** /**
* Get little-endian block hash. * Get little-endian block hash.
* @returns {Hash} * @returns {Hash}
*/ */
ChainEntry.prototype.rhash = function rhash() { rhash() {
return encoding.revHex(this.hash); return encoding.revHex(this.hash);
}; }
/** /**
* Inject properties from block. * Inject properties from block.
@ -189,7 +183,7 @@ ChainEntry.prototype.rhash = function rhash() {
* @param {ChainEntry} prev - Previous entry. * @param {ChainEntry} prev - Previous entry.
*/ */
ChainEntry.prototype.fromBlock = function fromBlock(block, prev) { fromBlock(block, prev) {
this.hash = block.hash('hex'); this.hash = block.hash('hex');
this.version = block.version; this.version = block.version;
this.prevBlock = block.prevBlock; this.prevBlock = block.prevBlock;
@ -200,7 +194,7 @@ ChainEntry.prototype.fromBlock = function fromBlock(block, prev) {
this.height = prev ? prev.height + 1: 0; this.height = prev ? prev.height + 1: 0;
this.chainwork = this.getChainwork(prev); this.chainwork = this.getChainwork(prev);
return this; return this;
}; }
/** /**
* Instantiate chainentry from block. * Instantiate chainentry from block.
@ -209,16 +203,16 @@ ChainEntry.prototype.fromBlock = function fromBlock(block, prev) {
* @returns {ChainEntry} * @returns {ChainEntry}
*/ */
ChainEntry.fromBlock = function fromBlock(block, prev) { static fromBlock(block, prev) {
return new ChainEntry().fromBlock(block, prev); return new this().fromBlock(block, prev);
}; }
/** /**
* Serialize the entry to internal database format. * Serialize the entry to internal database format.
* @returns {Buffer} * @returns {Buffer}
*/ */
ChainEntry.prototype.toRaw = function toRaw() { toRaw() {
const bw = new StaticWriter(116); const bw = new StaticWriter(116);
bw.writeU32(this.version); bw.writeU32(this.version);
@ -231,7 +225,7 @@ ChainEntry.prototype.toRaw = function toRaw() {
bw.writeBytes(this.chainwork.toArrayLike(Buffer, 'le', 32)); bw.writeBytes(this.chainwork.toArrayLike(Buffer, 'le', 32));
return bw.render(); return bw.render();
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -239,7 +233,7 @@ ChainEntry.prototype.toRaw = function toRaw() {
* @param {Buffer} data * @param {Buffer} data
*/ */
ChainEntry.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
const br = new BufferReader(data, true); const br = new BufferReader(data, true);
const hash = hash256.digest(br.readBytes(80)); const hash = hash256.digest(br.readBytes(80));
@ -256,7 +250,7 @@ ChainEntry.prototype.fromRaw = function fromRaw(data) {
this.chainwork = new BN(br.readBytes(32), 'le'); this.chainwork = new BN(br.readBytes(32), 'le');
return this; return this;
}; }
/** /**
* Deserialize the entry. * Deserialize the entry.
@ -264,9 +258,9 @@ ChainEntry.prototype.fromRaw = function fromRaw(data) {
* @returns {ChainEntry} * @returns {ChainEntry}
*/ */
ChainEntry.fromRaw = function fromRaw(data) { static fromRaw(data) {
return new ChainEntry().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Serialize the entry to an object more * Serialize the entry to an object more
@ -274,7 +268,7 @@ ChainEntry.fromRaw = function fromRaw(data) {
* @returns {Object} * @returns {Object}
*/ */
ChainEntry.prototype.toJSON = function toJSON() { toJSON() {
return { return {
hash: encoding.revHex(this.hash), hash: encoding.revHex(this.hash),
version: this.version, version: this.version,
@ -286,7 +280,7 @@ ChainEntry.prototype.toJSON = function toJSON() {
height: this.height, height: this.height,
chainwork: this.chainwork.toString('hex', 64) chainwork: this.chainwork.toString('hex', 64)
}; };
}; }
/** /**
* Inject properties from json object. * Inject properties from json object.
@ -294,7 +288,7 @@ ChainEntry.prototype.toJSON = function toJSON() {
* @param {Object} json * @param {Object} json
*/ */
ChainEntry.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
assert(json, 'Block data is required.'); assert(json, 'Block data is required.');
assert(typeof json.hash === 'string'); assert(typeof json.hash === 'string');
assert((json.version >>> 0) === json.version); assert((json.version >>> 0) === json.version);
@ -316,7 +310,7 @@ ChainEntry.prototype.fromJSON = function fromJSON(json) {
this.chainwork = new BN(json.chainwork, 'hex'); this.chainwork = new BN(json.chainwork, 'hex');
return this; return this;
}; }
/** /**
* Instantiate block from jsonified object. * Instantiate block from jsonified object.
@ -324,38 +318,38 @@ ChainEntry.prototype.fromJSON = function fromJSON(json) {
* @returns {ChainEntry} * @returns {ChainEntry}
*/ */
ChainEntry.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new ChainEntry().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Convert the entry to a headers object. * Convert the entry to a headers object.
* @returns {Headers} * @returns {Headers}
*/ */
ChainEntry.prototype.toHeaders = function toHeaders() { toHeaders() {
return Headers.fromEntry(this); return Headers.fromEntry(this);
}; }
/** /**
* Convert the entry to an inv item. * Convert the entry to an inv item.
* @returns {InvItem} * @returns {InvItem}
*/ */
ChainEntry.prototype.toInv = function toInv() { toInv() {
return new InvItem(InvItem.types.BLOCK, this.hash); return new InvItem(InvItem.types.BLOCK, this.hash);
}; }
/** /**
* Return a more user-friendly object. * Return a more user-friendly object.
* @returns {Object} * @returns {Object}
*/ */
ChainEntry.prototype.inspect = function inspect() { inspect() {
const json = this.toJSON(); const json = this.toJSON();
json.version = json.version.toString(16); json.version = json.version.toString(16);
return json; return json;
}; }
/** /**
* Test whether an object is a {@link ChainEntry}. * Test whether an object is a {@link ChainEntry}.
@ -363,9 +357,17 @@ ChainEntry.prototype.inspect = function inspect() {
* @returns {Boolean} * @returns {Boolean}
*/ */
ChainEntry.isChainEntry = function isChainEntry(obj) { static isChainEntry(obj) {
return obj instanceof ChainEntry; return obj instanceof ChainEntry;
}; }
}
/**
* The max chainwork (1 << 256).
* @const {BN}
*/
ChainEntry.MAX_CHAINWORK = new BN(1).ushln(256);
/* /*
* Expose * Expose

View File

@ -22,9 +22,9 @@ const NUM_FLAGS = 1;
const MAX_HEIGHT = ((1 << (32 - NUM_FLAGS)) >>> 0) - 1; const MAX_HEIGHT = ((1 << (32 - NUM_FLAGS)) >>> 0) - 1;
/** /**
* Coin Entry
* Represents an unspent output. * Represents an unspent output.
* @alias module:coins.CoinEntry * @alias module:coins.CoinEntry
* @constructor
* @property {Number} version - Transaction version. * @property {Number} version - Transaction version.
* @property {Number} height - Transaction height (-1 if unconfirmed). * @property {Number} height - Transaction height (-1 if unconfirmed).
* @property {Boolean} coinbase - Whether the containing * @property {Boolean} coinbase - Whether the containing
@ -34,10 +34,13 @@ const MAX_HEIGHT = ((1 << (32 - NUM_FLAGS)) >>> 0) - 1;
* @property {Buffer} raw * @property {Buffer} raw
*/ */
function CoinEntry() { class CoinEntry {
if (!(this instanceof CoinEntry)) /**
return new CoinEntry(); * Create a coin entry.
* @constructor
*/
constructor() {
this.version = 1; this.version = 1;
this.height = -1; this.height = -1;
this.coinbase = false; this.coinbase = false;
@ -51,9 +54,9 @@ function CoinEntry() {
* @returns {Output} * @returns {Output}
*/ */
CoinEntry.prototype.toOutput = function toOutput() { toOutput() {
return this.output; return this.output;
}; }
/** /**
* Convert coin entry to a coin. * Convert coin entry to a coin.
@ -61,7 +64,7 @@ CoinEntry.prototype.toOutput = function toOutput() {
* @returns {Coin} * @returns {Coin}
*/ */
CoinEntry.prototype.toCoin = function toCoin(prevout) { toCoin(prevout) {
const coin = new Coin(); const coin = new Coin();
coin.version = this.version; coin.version = this.version;
coin.height = this.height; coin.height = this.height;
@ -71,7 +74,7 @@ CoinEntry.prototype.toCoin = function toCoin(prevout) {
coin.hash = prevout.hash; coin.hash = prevout.hash;
coin.index = prevout.index; coin.index = prevout.index;
return coin; return coin;
}; }
/** /**
* Inject properties from TX. * Inject properties from TX.
@ -79,10 +82,10 @@ CoinEntry.prototype.toCoin = function toCoin(prevout) {
* @param {Number} index * @param {Number} index
*/ */
CoinEntry.prototype.fromOutput = function fromOutput(output) { fromOutput(output) {
this.output = output; this.output = output;
return this; return this;
}; }
/** /**
* Instantiate a coin from a TX * Instantiate a coin from a TX
@ -91,9 +94,9 @@ CoinEntry.prototype.fromOutput = function fromOutput(output) {
* @returns {CoinEntry} * @returns {CoinEntry}
*/ */
CoinEntry.fromOutput = function fromOutput(output) { static fromOutput(output) {
return new CoinEntry().fromOutput(output); return new this().fromOutput(output);
}; }
/** /**
* Inject properties from TX. * Inject properties from TX.
@ -101,14 +104,14 @@ CoinEntry.fromOutput = function fromOutput(output) {
* @param {Number} index * @param {Number} index
*/ */
CoinEntry.prototype.fromCoin = function fromCoin(coin) { fromCoin(coin) {
this.version = coin.version; this.version = coin.version;
this.height = coin.height; this.height = coin.height;
this.coinbase = coin.coinbase; this.coinbase = coin.coinbase;
this.output.script = coin.script; this.output.script = coin.script;
this.output.value = coin.value; this.output.value = coin.value;
return this; return this;
}; }
/** /**
* Instantiate a coin from a TX * Instantiate a coin from a TX
@ -117,9 +120,9 @@ CoinEntry.prototype.fromCoin = function fromCoin(coin) {
* @returns {CoinEntry} * @returns {CoinEntry}
*/ */
CoinEntry.fromCoin = function fromCoin(coin) { static fromCoin(coin) {
return new CoinEntry().fromCoin(coin); return new this().fromCoin(coin);
}; }
/** /**
* Inject properties from TX. * Inject properties from TX.
@ -127,7 +130,7 @@ CoinEntry.fromCoin = function fromCoin(coin) {
* @param {Number} index * @param {Number} index
*/ */
CoinEntry.prototype.fromTX = function fromTX(tx, index, height) { fromTX(tx, index, height) {
assert(typeof index === 'number'); assert(typeof index === 'number');
assert(typeof height === 'number'); assert(typeof height === 'number');
assert(index >= 0 && index < tx.outputs.length); assert(index >= 0 && index < tx.outputs.length);
@ -136,7 +139,7 @@ CoinEntry.prototype.fromTX = function fromTX(tx, index, height) {
this.coinbase = tx.isCoinbase(); this.coinbase = tx.isCoinbase();
this.output = tx.outputs[index]; this.output = tx.outputs[index];
return this; return this;
}; }
/** /**
* Instantiate a coin from a TX * Instantiate a coin from a TX
@ -145,16 +148,16 @@ CoinEntry.prototype.fromTX = function fromTX(tx, index, height) {
* @returns {CoinEntry} * @returns {CoinEntry}
*/ */
CoinEntry.fromTX = function fromTX(tx, index, height) { static fromTX(tx, index, height) {
return new CoinEntry().fromTX(tx, index, height); return new this().fromTX(tx, index, height);
}; }
/** /**
* Calculate size of coin. * Calculate size of coin.
* @returns {Number} * @returns {Number}
*/ */
CoinEntry.prototype.getSize = function getSize() { getSize() {
if (this.raw) if (this.raw)
return this.raw.length; return this.raw.length;
@ -164,14 +167,14 @@ CoinEntry.prototype.getSize = function getSize() {
size += compress.size(this.output); size += compress.size(this.output);
return size; return size;
}; }
/** /**
* Write the coin to a buffer writer. * Write the coin to a buffer writer.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
CoinEntry.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
if (this.raw) { if (this.raw) {
bw.writeBytes(this.raw); bw.writeBytes(this.raw);
return bw; return bw;
@ -193,14 +196,14 @@ CoinEntry.prototype.toWriter = function toWriter(bw) {
compress.pack(this.output, bw); compress.pack(this.output, bw);
return bw; return bw;
}; }
/** /**
* Serialize the coin. * Serialize the coin.
* @returns {Buffer} * @returns {Buffer}
*/ */
CoinEntry.prototype.toRaw = function toRaw() { toRaw() {
if (this.raw) if (this.raw)
return this.raw; return this.raw;
@ -212,7 +215,7 @@ CoinEntry.prototype.toRaw = function toRaw() {
this.raw = bw.render(); this.raw = bw.render();
return this.raw; return this.raw;
}; }
/** /**
* Inject properties from serialized buffer writer. * Inject properties from serialized buffer writer.
@ -220,7 +223,7 @@ CoinEntry.prototype.toRaw = function toRaw() {
* @param {BufferReader} br * @param {BufferReader} br
*/ */
CoinEntry.prototype.fromReader = function fromReader(br) { fromReader(br) {
const version = br.readVarint(); const version = br.readVarint();
const field = br.readU32(); const field = br.readU32();
@ -236,7 +239,7 @@ CoinEntry.prototype.fromReader = function fromReader(br) {
compress.unpack(this.output, br); compress.unpack(this.output, br);
return this; return this;
}; }
/** /**
* Instantiate a coin from a serialized Buffer. * Instantiate a coin from a serialized Buffer.
@ -244,9 +247,9 @@ CoinEntry.prototype.fromReader = function fromReader(br) {
* @returns {CoinEntry} * @returns {CoinEntry}
*/ */
CoinEntry.fromReader = function fromReader(data) { static fromReader(data) {
return new CoinEntry().fromReader(data); return new this().fromReader(data);
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -254,11 +257,11 @@ CoinEntry.fromReader = function fromReader(data) {
* @param {Buffer} data * @param {Buffer} data
*/ */
CoinEntry.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
this.fromReader(new BufferReader(data)); this.fromReader(new BufferReader(data));
this.raw = data; this.raw = data;
return this; return this;
}; }
/** /**
* Instantiate a coin from a serialized Buffer. * Instantiate a coin from a serialized Buffer.
@ -266,9 +269,10 @@ CoinEntry.prototype.fromRaw = function fromRaw(data) {
* @returns {CoinEntry} * @returns {CoinEntry}
*/ */
CoinEntry.fromRaw = function fromRaw(data) { static fromRaw(data) {
return new CoinEntry().fromRaw(data); return new this().fromRaw(data);
}; }
}
/* /*
* Expose * Expose

View File

@ -10,16 +10,19 @@ const assert = require('assert');
const CoinEntry = require('./coinentry'); const CoinEntry = require('./coinentry');
/** /**
* Coins
* Represents the outputs for a single transaction. * Represents the outputs for a single transaction.
* @alias module:coins.Coins * @alias module:coins.Coins
* @constructor
* @property {Map[]} outputs - Coins. * @property {Map[]} outputs - Coins.
*/ */
function Coins() { class Coins {
if (!(this instanceof Coins)) /**
return new Coins(); * Create coins.
* @constructor
*/
constructor() {
this.outputs = new Map(); this.outputs = new Map();
} }
@ -30,12 +33,12 @@ function Coins() {
* @returns {CoinEntry} * @returns {CoinEntry}
*/ */
Coins.prototype.add = function add(index, coin) { add(index, coin) {
assert((index >>> 0) === index); assert((index >>> 0) === index);
assert(coin); assert(coin);
this.outputs.set(index, coin); this.outputs.set(index, coin);
return coin; return coin;
}; }
/** /**
* Add a single output to the collection. * Add a single output to the collection.
@ -44,9 +47,9 @@ Coins.prototype.add = function add(index, coin) {
* @returns {CoinEntry} * @returns {CoinEntry}
*/ */
Coins.prototype.addOutput = function addOutput(index, output) { addOutput(index, output) {
return this.add(index, CoinEntry.fromOutput(output)); return this.add(index, CoinEntry.fromOutput(output));
}; }
/** /**
* Add an output to the collection by output index. * Add an output to the collection by output index.
@ -56,9 +59,9 @@ Coins.prototype.addOutput = function addOutput(index, output) {
* @returns {CoinEntry} * @returns {CoinEntry}
*/ */
Coins.prototype.addIndex = function addIndex(tx, index, height) { addIndex(tx, index, height) {
return this.add(index, CoinEntry.fromTX(tx, index, height)); return this.add(index, CoinEntry.fromTX(tx, index, height));
}; }
/** /**
* Add a single coin to the collection. * Add a single coin to the collection.
@ -66,9 +69,9 @@ Coins.prototype.addIndex = function addIndex(tx, index, height) {
* @returns {CoinEntry} * @returns {CoinEntry}
*/ */
Coins.prototype.addCoin = function addCoin(coin) { addCoin(coin) {
return this.add(coin.index, CoinEntry.fromCoin(coin)); return this.add(coin.index, CoinEntry.fromCoin(coin));
}; }
/** /**
* Test whether the collection has a coin. * Test whether the collection has a coin.
@ -76,9 +79,9 @@ Coins.prototype.addCoin = function addCoin(coin) {
* @returns {Boolean} * @returns {Boolean}
*/ */
Coins.prototype.has = function has(index) { has(index) {
return this.outputs.has(index); return this.outputs.has(index);
}; }
/** /**
* Test whether the collection has an unspent coin. * Test whether the collection has an unspent coin.
@ -86,14 +89,14 @@ Coins.prototype.has = function has(index) {
* @returns {Boolean} * @returns {Boolean}
*/ */
Coins.prototype.isUnspent = function isUnspent(index) { isUnspent(index) {
const coin = this.outputs.get(index); const coin = this.outputs.get(index);
if (!coin || coin.spent) if (!coin || coin.spent)
return false; return false;
return true; return true;
}; }
/** /**
* Get a coin entry. * Get a coin entry.
@ -101,9 +104,9 @@ Coins.prototype.isUnspent = function isUnspent(index) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
Coins.prototype.get = function get(index) { get(index) {
return this.outputs.get(index) || null; return this.outputs.get(index) || null;
}; }
/** /**
* Get an output. * Get an output.
@ -111,14 +114,14 @@ Coins.prototype.get = function get(index) {
* @returns {Output|null} * @returns {Output|null}
*/ */
Coins.prototype.getOutput = function getOutput(index) { getOutput(index) {
const coin = this.outputs.get(index); const coin = this.outputs.get(index);
if (!coin) if (!coin)
return null; return null;
return coin.output; return coin.output;
}; }
/** /**
* Get a coin. * Get a coin.
@ -126,14 +129,14 @@ Coins.prototype.getOutput = function getOutput(index) {
* @returns {Coin|null} * @returns {Coin|null}
*/ */
Coins.prototype.getCoin = function getCoin(prevout) { getCoin(prevout) {
const coin = this.outputs.get(prevout.index); const coin = this.outputs.get(prevout.index);
if (!coin) if (!coin)
return null; return null;
return coin.toCoin(prevout); return coin.toCoin(prevout);
}; }
/** /**
* Spend a coin entry and return it. * Spend a coin entry and return it.
@ -141,7 +144,7 @@ Coins.prototype.getCoin = function getCoin(prevout) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
Coins.prototype.spend = function spend(index) { spend(index) {
const coin = this.get(index); const coin = this.get(index);
if (!coin || coin.spent) if (!coin || coin.spent)
@ -150,7 +153,7 @@ Coins.prototype.spend = function spend(index) {
coin.spent = true; coin.spent = true;
return coin; return coin;
}; }
/** /**
* Remove a coin entry and return it. * Remove a coin entry and return it.
@ -158,7 +161,7 @@ Coins.prototype.spend = function spend(index) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
Coins.prototype.remove = function remove(index) { remove(index) {
const coin = this.get(index); const coin = this.get(index);
if (!coin) if (!coin)
@ -167,16 +170,16 @@ Coins.prototype.remove = function remove(index) {
this.outputs.delete(index); this.outputs.delete(index);
return coin; return coin;
}; }
/** /**
* Test whether the coins are fully spent. * Test whether the coins are fully spent.
* @returns {Boolean} * @returns {Boolean}
*/ */
Coins.prototype.isEmpty = function isEmpty() { isEmpty() {
return this.outputs.size === 0; return this.outputs.size === 0;
}; }
/** /**
* Inject properties from tx. * Inject properties from tx.
@ -186,7 +189,7 @@ Coins.prototype.isEmpty = function isEmpty() {
* @returns {Coins} * @returns {Coins}
*/ */
Coins.prototype.fromTX = function fromTX(tx, height) { fromTX(tx, height) {
assert(typeof height === 'number'); assert(typeof height === 'number');
for (let i = 0; i < tx.outputs.length; i++) { for (let i = 0; i < tx.outputs.length; i++) {
@ -201,7 +204,7 @@ Coins.prototype.fromTX = function fromTX(tx, height) {
} }
return this; return this;
}; }
/** /**
* Instantiate a coins object from a transaction. * Instantiate a coins object from a transaction.
@ -210,9 +213,10 @@ Coins.prototype.fromTX = function fromTX(tx, height) {
* @returns {Coins} * @returns {Coins}
*/ */
Coins.fromTX = function fromTX(tx, height) { static fromTX(tx, height) {
return new Coins().fromTX(tx, height); return new this().fromTX(tx, height);
}; }
}
/* /*
* Expose * Expose

View File

@ -11,18 +11,21 @@ const UndoCoins = require('./undocoins');
const CoinEntry = require('./coinentry'); const CoinEntry = require('./coinentry');
/** /**
* Coin View
* Represents a coin viewpoint: * Represents a coin viewpoint:
* a snapshot of {@link Coins} objects. * a snapshot of {@link Coins} objects.
* @alias module:coins.CoinView * @alias module:coins.CoinView
* @constructor
* @property {Object} map * @property {Object} map
* @property {UndoCoins} undo * @property {UndoCoins} undo
*/ */
function CoinView() { class CoinView {
if (!(this instanceof CoinView)) /**
return new CoinView(); * Create a coin view.
* @constructor
*/
constructor() {
this.map = new Map(); this.map = new Map();
this.undo = new UndoCoins(); this.undo = new UndoCoins();
} }
@ -33,9 +36,9 @@ function CoinView() {
* @returns {Coins} coins * @returns {Coins} coins
*/ */
CoinView.prototype.get = function get(hash) { get(hash) {
return this.map.get(hash); return this.map.get(hash);
}; }
/** /**
* Test whether the view has an entry. * Test whether the view has an entry.
@ -43,9 +46,9 @@ CoinView.prototype.get = function get(hash) {
* @returns {Boolean} * @returns {Boolean}
*/ */
CoinView.prototype.has = function has(hash) { has(hash) {
return this.map.has(hash); return this.map.has(hash);
}; }
/** /**
* Add coins to the collection. * Add coins to the collection.
@ -54,10 +57,10 @@ CoinView.prototype.has = function has(hash) {
* @returns {Coins} * @returns {Coins}
*/ */
CoinView.prototype.add = function add(hash, coins) { add(hash, coins) {
this.map.set(hash, coins); this.map.set(hash, coins);
return coins; return coins;
}; }
/** /**
* Ensure existence of coins object in the collection. * Ensure existence of coins object in the collection.
@ -65,14 +68,14 @@ CoinView.prototype.add = function add(hash, coins) {
* @returns {Coins} * @returns {Coins}
*/ */
CoinView.prototype.ensure = function ensure(hash) { ensure(hash) {
const coins = this.map.get(hash); const coins = this.map.get(hash);
if (coins) if (coins)
return coins; return coins;
return this.add(hash, new Coins()); return this.add(hash, new Coins());
}; }
/** /**
* Remove coins from the collection. * Remove coins from the collection.
@ -80,7 +83,7 @@ CoinView.prototype.ensure = function ensure(hash) {
* @returns {Coins|null} * @returns {Coins|null}
*/ */
CoinView.prototype.remove = function remove(hash) { remove(hash) {
const coins = this.map.get(hash); const coins = this.map.get(hash);
if (!coins) if (!coins)
@ -89,7 +92,7 @@ CoinView.prototype.remove = function remove(hash) {
this.map.delete(hash); this.map.delete(hash);
return coins; return coins;
}; }
/** /**
* Add a tx to the collection. * Add a tx to the collection.
@ -98,11 +101,11 @@ CoinView.prototype.remove = function remove(hash) {
* @returns {Coins} * @returns {Coins}
*/ */
CoinView.prototype.addTX = function addTX(tx, height) { addTX(tx, height) {
const hash = tx.hash('hex'); const hash = tx.hash('hex');
const coins = Coins.fromTX(tx, height); const coins = Coins.fromTX(tx, height);
return this.add(hash, coins); return this.add(hash, coins);
}; }
/** /**
* Remove a tx from the collection. * Remove a tx from the collection.
@ -111,7 +114,7 @@ CoinView.prototype.addTX = function addTX(tx, height) {
* @returns {Coins} * @returns {Coins}
*/ */
CoinView.prototype.removeTX = function removeTX(tx, height) { removeTX(tx, height) {
const hash = tx.hash('hex'); const hash = tx.hash('hex');
const coins = Coins.fromTX(tx, height); const coins = Coins.fromTX(tx, height);
@ -119,7 +122,7 @@ CoinView.prototype.removeTX = function removeTX(tx, height) {
coin.spent = true; coin.spent = true;
return this.add(hash, coins); return this.add(hash, coins);
}; }
/** /**
* Add an entry to the collection. * Add an entry to the collection.
@ -128,11 +131,11 @@ CoinView.prototype.removeTX = function removeTX(tx, height) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
CoinView.prototype.addEntry = function addEntry(prevout, coin) { addEntry(prevout, coin) {
const {hash, index} = prevout; const {hash, index} = prevout;
const coins = this.ensure(hash); const coins = this.ensure(hash);
return coins.add(index, coin); return coins.add(index, coin);
}; }
/** /**
* Add a coin to the collection. * Add a coin to the collection.
@ -140,10 +143,10 @@ CoinView.prototype.addEntry = function addEntry(prevout, coin) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
CoinView.prototype.addCoin = function addCoin(coin) { addCoin(coin) {
const coins = this.ensure(coin.hash); const coins = this.ensure(coin.hash);
return coins.addCoin(coin); return coins.addCoin(coin);
}; }
/** /**
* Add an output to the collection. * Add an output to the collection.
@ -152,11 +155,11 @@ CoinView.prototype.addCoin = function addCoin(coin) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
CoinView.prototype.addOutput = function addOutput(prevout, output) { addOutput(prevout, output) {
const {hash, index} = prevout; const {hash, index} = prevout;
const coins = this.ensure(hash); const coins = this.ensure(hash);
return coins.addOutput(index, output); return coins.addOutput(index, output);
}; }
/** /**
* Add an output to the collection by output index. * Add an output to the collection by output index.
@ -166,11 +169,11 @@ CoinView.prototype.addOutput = function addOutput(prevout, output) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
CoinView.prototype.addIndex = function addIndex(tx, index, height) { addIndex(tx, index, height) {
const hash = tx.hash('hex'); const hash = tx.hash('hex');
const coins = this.ensure(hash); const coins = this.ensure(hash);
return coins.addIndex(tx, index, height); return coins.addIndex(tx, index, height);
}; }
/** /**
* Spend an output. * Spend an output.
@ -178,7 +181,7 @@ CoinView.prototype.addIndex = function addIndex(tx, index, height) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
CoinView.prototype.spendEntry = function spendEntry(prevout) { spendEntry(prevout) {
const {hash, index} = prevout; const {hash, index} = prevout;
const coins = this.get(hash); const coins = this.get(hash);
@ -193,7 +196,7 @@ CoinView.prototype.spendEntry = function spendEntry(prevout) {
this.undo.push(coin); this.undo.push(coin);
return coin; return coin;
}; }
/** /**
* Remove an output. * Remove an output.
@ -201,7 +204,7 @@ CoinView.prototype.spendEntry = function spendEntry(prevout) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
CoinView.prototype.removeEntry = function removeEntry(prevout) { removeEntry(prevout) {
const {hash, index} = prevout; const {hash, index} = prevout;
const coins = this.get(hash); const coins = this.get(hash);
@ -209,7 +212,7 @@ CoinView.prototype.removeEntry = function removeEntry(prevout) {
return null; return null;
return coins.remove(index); return coins.remove(index);
}; }
/** /**
* Test whether the view has an entry by prevout. * Test whether the view has an entry by prevout.
@ -217,7 +220,7 @@ CoinView.prototype.removeEntry = function removeEntry(prevout) {
* @returns {Boolean} * @returns {Boolean}
*/ */
CoinView.prototype.hasEntry = function hasEntry(prevout) { hasEntry(prevout) {
const {hash, index} = prevout; const {hash, index} = prevout;
const coins = this.get(hash); const coins = this.get(hash);
@ -225,7 +228,7 @@ CoinView.prototype.hasEntry = function hasEntry(prevout) {
return false; return false;
return coins.has(index); return coins.has(index);
}; }
/** /**
* Get a single entry by prevout. * Get a single entry by prevout.
@ -233,7 +236,7 @@ CoinView.prototype.hasEntry = function hasEntry(prevout) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
CoinView.prototype.getEntry = function getEntry(prevout) { getEntry(prevout) {
const {hash, index} = prevout; const {hash, index} = prevout;
const coins = this.get(hash); const coins = this.get(hash);
@ -241,7 +244,7 @@ CoinView.prototype.getEntry = function getEntry(prevout) {
return null; return null;
return coins.get(index); return coins.get(index);
}; }
/** /**
* Test whether an entry has been spent by prevout. * Test whether an entry has been spent by prevout.
@ -249,7 +252,7 @@ CoinView.prototype.getEntry = function getEntry(prevout) {
* @returns {Boolean} * @returns {Boolean}
*/ */
CoinView.prototype.isUnspent = function isUnspent(prevout) { isUnspent(prevout) {
const {hash, index} = prevout; const {hash, index} = prevout;
const coins = this.get(hash); const coins = this.get(hash);
@ -257,7 +260,7 @@ CoinView.prototype.isUnspent = function isUnspent(prevout) {
return false; return false;
return coins.isUnspent(index); return coins.isUnspent(index);
}; }
/** /**
* Get a single coin by prevout. * Get a single coin by prevout.
@ -265,14 +268,14 @@ CoinView.prototype.isUnspent = function isUnspent(prevout) {
* @returns {Coin|null} * @returns {Coin|null}
*/ */
CoinView.prototype.getCoin = function getCoin(prevout) { getCoin(prevout) {
const coins = this.get(prevout.hash); const coins = this.get(prevout.hash);
if (!coins) if (!coins)
return null; return null;
return coins.getCoin(prevout); return coins.getCoin(prevout);
}; }
/** /**
* Get a single output by prevout. * Get a single output by prevout.
@ -280,7 +283,7 @@ CoinView.prototype.getCoin = function getCoin(prevout) {
* @returns {Output|null} * @returns {Output|null}
*/ */
CoinView.prototype.getOutput = function getOutput(prevout) { getOutput(prevout) {
const {hash, index} = prevout; const {hash, index} = prevout;
const coins = this.get(hash); const coins = this.get(hash);
@ -288,7 +291,7 @@ CoinView.prototype.getOutput = function getOutput(prevout) {
return null; return null;
return coins.getOutput(index); return coins.getOutput(index);
}; }
/** /**
* Get coins height by prevout. * Get coins height by prevout.
@ -296,14 +299,14 @@ CoinView.prototype.getOutput = function getOutput(prevout) {
* @returns {Number} * @returns {Number}
*/ */
CoinView.prototype.getHeight = function getHeight(prevout) { getHeight(prevout) {
const coin = this.getEntry(prevout); const coin = this.getEntry(prevout);
if (!coin) if (!coin)
return -1; return -1;
return coin.height; return coin.height;
}; }
/** /**
* Get coins coinbase flag by prevout. * Get coins coinbase flag by prevout.
@ -311,14 +314,14 @@ CoinView.prototype.getHeight = function getHeight(prevout) {
* @returns {Boolean} * @returns {Boolean}
*/ */
CoinView.prototype.isCoinbase = function isCoinbase(prevout) { isCoinbase(prevout) {
const coin = this.getEntry(prevout); const coin = this.getEntry(prevout);
if (!coin) if (!coin)
return false; return false;
return coin.coinbase; return coin.coinbase;
}; }
/** /**
* Test whether the view has an entry by input. * Test whether the view has an entry by input.
@ -326,9 +329,9 @@ CoinView.prototype.isCoinbase = function isCoinbase(prevout) {
* @returns {Boolean} * @returns {Boolean}
*/ */
CoinView.prototype.hasEntryFor = function hasEntryFor(input) { hasEntryFor(input) {
return this.hasEntry(input.prevout); return this.hasEntry(input.prevout);
}; }
/** /**
* Get a single entry by input. * Get a single entry by input.
@ -336,9 +339,9 @@ CoinView.prototype.hasEntryFor = function hasEntryFor(input) {
* @returns {CoinEntry|null} * @returns {CoinEntry|null}
*/ */
CoinView.prototype.getEntryFor = function getEntryFor(input) { getEntryFor(input) {
return this.getEntry(input.prevout); return this.getEntry(input.prevout);
}; }
/** /**
* Test whether an entry has been spent by input. * Test whether an entry has been spent by input.
@ -346,9 +349,9 @@ CoinView.prototype.getEntryFor = function getEntryFor(input) {
* @returns {Boolean} * @returns {Boolean}
*/ */
CoinView.prototype.isUnspentFor = function isUnspentFor(input) { isUnspentFor(input) {
return this.isUnspent(input.prevout); return this.isUnspent(input.prevout);
}; }
/** /**
* Get a single coin by input. * Get a single coin by input.
@ -356,9 +359,9 @@ CoinView.prototype.isUnspentFor = function isUnspentFor(input) {
* @returns {Coin|null} * @returns {Coin|null}
*/ */
CoinView.prototype.getCoinFor = function getCoinFor(input) { getCoinFor(input) {
return this.getCoin(input.prevout); return this.getCoin(input.prevout);
}; }
/** /**
* Get a single output by input. * Get a single output by input.
@ -366,9 +369,9 @@ CoinView.prototype.getCoinFor = function getCoinFor(input) {
* @returns {Output|null} * @returns {Output|null}
*/ */
CoinView.prototype.getOutputFor = function getOutputFor(input) { getOutputFor(input) {
return this.getOutput(input.prevout); return this.getOutput(input.prevout);
}; }
/** /**
* Get coins height by input. * Get coins height by input.
@ -376,9 +379,9 @@ CoinView.prototype.getOutputFor = function getOutputFor(input) {
* @returns {Number} * @returns {Number}
*/ */
CoinView.prototype.getHeightFor = function getHeightFor(input) { getHeightFor(input) {
return this.getHeight(input.prevout); return this.getHeight(input.prevout);
}; }
/** /**
* Get coins coinbase flag by input. * Get coins coinbase flag by input.
@ -386,9 +389,9 @@ CoinView.prototype.getHeightFor = function getHeightFor(input) {
* @returns {Boolean} * @returns {Boolean}
*/ */
CoinView.prototype.isCoinbaseFor = function isCoinbaseFor(input) { isCoinbaseFor(input) {
return this.isCoinbase(input.prevout); return this.isCoinbase(input.prevout);
}; }
/** /**
* Retrieve coins from database. * Retrieve coins from database.
@ -398,7 +401,7 @@ CoinView.prototype.isCoinbaseFor = function isCoinbaseFor(input) {
* @returns {Promise} - Returns {@link CoinEntry}. * @returns {Promise} - Returns {@link CoinEntry}.
*/ */
CoinView.prototype.readCoin = async function readCoin(db, prevout) { async readCoin(db, prevout) {
const cache = this.getEntry(prevout); const cache = this.getEntry(prevout);
if (cache) if (cache)
@ -410,7 +413,7 @@ CoinView.prototype.readCoin = async function readCoin(db, prevout) {
return null; return null;
return this.addEntry(prevout, coin); return this.addEntry(prevout, coin);
}; }
/** /**
* Read all input coins into unspent map. * Read all input coins into unspent map.
@ -420,7 +423,7 @@ CoinView.prototype.readCoin = async function readCoin(db, prevout) {
* @returns {Promise} - Returns {Boolean}. * @returns {Promise} - Returns {Boolean}.
*/ */
CoinView.prototype.readInputs = async function readInputs(db, tx) { async readInputs(db, tx) {
let found = true; let found = true;
for (const {prevout} of tx.inputs) { for (const {prevout} of tx.inputs) {
@ -429,7 +432,7 @@ CoinView.prototype.readInputs = async function readInputs(db, tx) {
} }
return found; return found;
}; }
/** /**
* Spend coins for transaction. * Spend coins for transaction.
@ -439,7 +442,7 @@ CoinView.prototype.readInputs = async function readInputs(db, tx) {
* @returns {Promise} - Returns {Boolean}. * @returns {Promise} - Returns {Boolean}.
*/ */
CoinView.prototype.spendInputs = async function spendInputs(db, tx) { async spendInputs(db, tx) {
let i = 0; let i = 0;
while (i < tx.inputs.length) { while (i < tx.inputs.length) {
@ -463,14 +466,14 @@ CoinView.prototype.spendInputs = async function spendInputs(db, tx) {
} }
return true; return true;
}; }
/** /**
* Calculate serialization size. * Calculate serialization size.
* @returns {Number} * @returns {Number}
*/ */
CoinView.prototype.getSize = function getSize(tx) { getSize(tx) {
let size = 0; let size = 0;
size += tx.inputs.length; size += tx.inputs.length;
@ -485,7 +488,7 @@ CoinView.prototype.getSize = function getSize(tx) {
} }
return size; return size;
}; }
/** /**
* Write coin data to buffer writer * Write coin data to buffer writer
@ -494,7 +497,7 @@ CoinView.prototype.getSize = function getSize(tx) {
* @param {TX} tx * @param {TX} tx
*/ */
CoinView.prototype.toWriter = function toWriter(bw, tx) { toWriter(bw, tx) {
for (const {prevout} of tx.inputs) { for (const {prevout} of tx.inputs) {
const coin = this.getEntry(prevout); const coin = this.getEntry(prevout);
@ -508,7 +511,7 @@ CoinView.prototype.toWriter = function toWriter(bw, tx) {
} }
return bw; return bw;
}; }
/** /**
* Read serialized view data from a buffer * Read serialized view data from a buffer
@ -518,7 +521,7 @@ CoinView.prototype.toWriter = function toWriter(bw, tx) {
* @param {TX} tx * @param {TX} tx
*/ */
CoinView.prototype.fromReader = function fromReader(br, tx) { fromReader(br, tx) {
for (const {prevout} of tx.inputs) { for (const {prevout} of tx.inputs) {
if (br.readU8() === 0) if (br.readU8() === 0)
continue; continue;
@ -529,7 +532,7 @@ CoinView.prototype.fromReader = function fromReader(br, tx) {
} }
return this; return this;
}; }
/** /**
* Read serialized view data from a buffer * Read serialized view data from a buffer
@ -539,9 +542,10 @@ CoinView.prototype.fromReader = function fromReader(br, tx) {
* @returns {CoinView} * @returns {CoinView}
*/ */
CoinView.fromReader = function fromReader(br, tx) { static fromReader(br, tx) {
return new CoinView().fromReader(br, tx); return new this().fromReader(br, tx);
}; }
}
/* /*
* Expose * Expose

View File

@ -18,14 +18,16 @@ const CoinEntry = require('../coins/coinentry');
* spent coins in a single record per block * spent coins in a single record per block
* (in a compressed format). * (in a compressed format).
* @alias module:coins.UndoCoins * @alias module:coins.UndoCoins
* @constructor
* @property {UndoCoin[]} items * @property {UndoCoin[]} items
*/ */
function UndoCoins() { class UndoCoins {
if (!(this instanceof UndoCoins)) /**
return new UndoCoins(); * Create undo coins.
* @constructor
*/
constructor() {
this.items = []; this.items = [];
} }
@ -35,16 +37,16 @@ function UndoCoins() {
* @returns {Number} * @returns {Number}
*/ */
UndoCoins.prototype.push = function push(coin) { push(coin) {
return this.items.push(coin); return this.items.push(coin);
}; }
/** /**
* Calculate undo coins size. * Calculate undo coins size.
* @returns {Number} * @returns {Number}
*/ */
UndoCoins.prototype.getSize = function getSize() { getSize() {
let size = 0; let size = 0;
size += 4; size += 4;
@ -53,14 +55,14 @@ UndoCoins.prototype.getSize = function getSize() {
size += coin.getSize(); size += coin.getSize();
return size; return size;
}; }
/** /**
* Serialize all undo coins. * Serialize all undo coins.
* @returns {Buffer} * @returns {Buffer}
*/ */
UndoCoins.prototype.toRaw = function toRaw() { toRaw() {
const size = this.getSize(); const size = this.getSize();
const bw = new StaticWriter(size); const bw = new StaticWriter(size);
@ -70,7 +72,7 @@ UndoCoins.prototype.toRaw = function toRaw() {
coin.toWriter(bw); coin.toWriter(bw);
return bw.render(); return bw.render();
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -79,7 +81,7 @@ UndoCoins.prototype.toRaw = function toRaw() {
* @returns {UndoCoins} * @returns {UndoCoins}
*/ */
UndoCoins.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
const br = new BufferReader(data); const br = new BufferReader(data);
const count = br.readU32(); const count = br.readU32();
@ -87,7 +89,7 @@ UndoCoins.prototype.fromRaw = function fromRaw(data) {
this.items.push(CoinEntry.fromReader(br)); this.items.push(CoinEntry.fromReader(br));
return this; return this;
}; }
/** /**
* Instantiate undo coins from serialized data. * Instantiate undo coins from serialized data.
@ -95,29 +97,29 @@ UndoCoins.prototype.fromRaw = function fromRaw(data) {
* @returns {UndoCoins} * @returns {UndoCoins}
*/ */
UndoCoins.fromRaw = function fromRaw(data) { static fromRaw(data) {
return new UndoCoins().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Test whether the undo coins have any members. * Test whether the undo coins have any members.
* @returns {Boolean} * @returns {Boolean}
*/ */
UndoCoins.prototype.isEmpty = function isEmpty() { isEmpty() {
return this.items.length === 0; return this.items.length === 0;
}; }
/** /**
* Render the undo coins. * Render the undo coins.
* @returns {Buffer} * @returns {Buffer}
*/ */
UndoCoins.prototype.commit = function commit() { commit() {
const raw = this.toRaw(); const raw = this.toRaw();
this.items.length = 0; this.items.length = 0;
return raw; return raw;
}; }
/** /**
* Re-apply undo coins to a view, effectively unspending them. * Re-apply undo coins to a view, effectively unspending them.
@ -125,13 +127,14 @@ UndoCoins.prototype.commit = function commit() {
* @param {Outpoint} prevout * @param {Outpoint} prevout
*/ */
UndoCoins.prototype.apply = function apply(view, prevout) { apply(view, prevout) {
const undo = this.items.pop(); const undo = this.items.pop();
assert(undo); assert(undo);
view.addEntry(prevout, undo); view.addEntry(prevout, undo);
}; }
}
/* /*
* Expose * Expose

View File

@ -221,7 +221,7 @@ Miner.prototype.mineBlock = function mineBlock(tip, address) {
*/ */
Miner.prototype.addAddress = function addAddress(address) { Miner.prototype.addAddress = function addAddress(address) {
this.addresses.push(Address(address)); this.addresses.push(new Address(address));
}; };
/** /**

View File

@ -512,7 +512,7 @@ BlockTemplate.prototype.getDifficulty = function getDifficulty() {
*/ */
BlockTemplate.prototype.setAddress = function setAddress(address) { BlockTemplate.prototype.setAddress = function setAddress(address) {
this.address = Address(address); this.address = new Address(address);
this.refresh(); this.refresh();
}; };

View File

@ -24,11 +24,10 @@ const Block = require('../primitives/block');
const common = require('./common'); const common = require('./common');
/** /**
* Compact Block
* Represents a compact block (bip152): `cmpctblock` packet. * Represents a compact block (bip152): `cmpctblock` packet.
* @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki * @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
* @constructor
* @extends AbstractBlock * @extends AbstractBlock
* @param {Object} options
* @property {Buffer|null} keyNonce - Nonce for siphash key. * @property {Buffer|null} keyNonce - Nonce for siphash key.
* @property {Number[]} ids - Short IDs. * @property {Number[]} ids - Short IDs.
* @property {Object[]} ptx - Prefilled transactions. * @property {Object[]} ptx - Prefilled transactions.
@ -38,11 +37,15 @@ const common = require('./common');
* @property {Buffer|null} sipKey - Siphash key. * @property {Buffer|null} sipKey - Siphash key.
*/ */
function CompactBlock(options) { class CompactBlock extends AbstractBlock {
if (!(this instanceof CompactBlock)) /**
return new CompactBlock(options); * Create a compact block.
* @constructor
* @param {Object?} options
*/
AbstractBlock.call(this); constructor(options) {
super();
this.keyNonce = null; this.keyNonce = null;
this.ids = []; this.ids = [];
@ -59,15 +62,13 @@ function CompactBlock(options) {
this.fromOptions(options); this.fromOptions(options);
} }
Object.setPrototypeOf(CompactBlock.prototype, AbstractBlock.prototype);
/** /**
* Inject properties from options object. * Inject properties from options object.
* @private * @private
* @param {Object} options * @param {Object} options
*/ */
CompactBlock.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
this.parseOptions(options); this.parseOptions(options);
assert(Buffer.isBuffer(options.keyNonce)); assert(Buffer.isBuffer(options.keyNonce));
@ -93,7 +94,7 @@ CompactBlock.prototype.fromOptions = function fromOptions(options) {
this.sipKey = this.getKey(); this.sipKey = this.getKey();
return this; return this;
}; }
/** /**
* Instantiate compact block from options. * Instantiate compact block from options.
@ -101,18 +102,18 @@ CompactBlock.prototype.fromOptions = function fromOptions(options) {
* @returns {CompactBlock} * @returns {CompactBlock}
*/ */
CompactBlock.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new CompactBlock().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Verify the block. * Verify the block.
* @returns {Boolean} * @returns {Boolean}
*/ */
CompactBlock.prototype.verifyBody = function verifyBody() { verifyBody() {
return true; return true;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -120,7 +121,7 @@ CompactBlock.prototype.verifyBody = function verifyBody() {
* @param {Buffer} data * @param {Buffer} data
*/ */
CompactBlock.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
const br = new BufferReader(data); const br = new BufferReader(data);
this.readHead(br); this.readHead(br);
@ -154,7 +155,7 @@ CompactBlock.prototype.fromRaw = function fromRaw(data) {
} }
return this; return this;
}; }
/** /**
* Instantiate a block from serialized data. * Instantiate a block from serialized data.
@ -163,29 +164,29 @@ CompactBlock.prototype.fromRaw = function fromRaw(data) {
* @returns {CompactBlock} * @returns {CompactBlock}
*/ */
CompactBlock.fromRaw = function fromRaw(data, enc) { static fromRaw(data, enc) {
if (typeof data === 'string') if (typeof data === 'string')
data = Buffer.from(data, enc); data = Buffer.from(data, enc);
return new CompactBlock().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Serialize compact block with witness data. * Serialize compact block with witness data.
* @returns {Buffer} * @returns {Buffer}
*/ */
CompactBlock.prototype.toRaw = function toRaw() { toRaw() {
return this.frameRaw(true); return this.frameRaw(true);
}; }
/** /**
* Serialize compact block without witness data. * Serialize compact block without witness data.
* @returns {Buffer} * @returns {Buffer}
*/ */
CompactBlock.prototype.toNormal = function toNormal() { toNormal() {
return this.frameRaw(false); return this.frameRaw(false);
}; }
/** /**
* Write serialized block to a buffer * Write serialized block to a buffer
@ -193,9 +194,9 @@ CompactBlock.prototype.toNormal = function toNormal() {
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
CompactBlock.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
return this.writeRaw(bw, true); return this.writeRaw(bw, true);
}; }
/** /**
* Write serialized block to a buffer * Write serialized block to a buffer
@ -203,9 +204,9 @@ CompactBlock.prototype.toWriter = function toWriter(bw) {
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
CompactBlock.prototype.toNormalWriter = function toNormalWriter(bw) { toNormalWriter(bw) {
return this.writeRaw(bw, false); return this.writeRaw(bw, false);
}; }
/** /**
* Serialize compact block. * Serialize compact block.
@ -214,10 +215,10 @@ CompactBlock.prototype.toNormalWriter = function toNormalWriter(bw) {
* @returns {Buffer} * @returns {Buffer}
*/ */
CompactBlock.prototype.frameRaw = function frameRaw(witness) { frameRaw(witness) {
const size = this.getSize(witness); const size = this.getSize(witness);
return this.writeRaw(new StaticWriter(size), witness).render(); return this.writeRaw(new StaticWriter(size), witness).render();
}; }
/** /**
* Calculate block serialization size. * Calculate block serialization size.
@ -225,7 +226,7 @@ CompactBlock.prototype.frameRaw = function frameRaw(witness) {
* @returns {Number} * @returns {Number}
*/ */
CompactBlock.prototype.getSize = function getSize(witness) { getSize(witness) {
let size = 0; let size = 0;
size += 80; size += 80;
@ -244,7 +245,7 @@ CompactBlock.prototype.getSize = function getSize(witness) {
} }
return size; return size;
}; }
/** /**
* Serialize block to buffer writer. * Serialize block to buffer writer.
@ -253,7 +254,7 @@ CompactBlock.prototype.getSize = function getSize(witness) {
* @param {Boolean} witness * @param {Boolean} witness
*/ */
CompactBlock.prototype.writeRaw = function writeRaw(bw, witness) { writeRaw(bw, witness) {
this.writeHead(bw); this.writeHead(bw);
bw.writeBytes(this.keyNonce); bw.writeBytes(this.keyNonce);
@ -280,7 +281,7 @@ CompactBlock.prototype.writeRaw = function writeRaw(bw, witness) {
} }
return bw; return bw;
}; }
/** /**
* Convert block to a TXRequest * Convert block to a TXRequest
@ -288,9 +289,9 @@ CompactBlock.prototype.writeRaw = function writeRaw(bw, witness) {
* @returns {TXRequest} * @returns {TXRequest}
*/ */
CompactBlock.prototype.toRequest = function toRequest() { toRequest() {
return TXRequest.fromCompact(this); return TXRequest.fromCompact(this);
}; }
/** /**
* Attempt to fill missing transactions from mempool. * Attempt to fill missing transactions from mempool.
@ -299,7 +300,7 @@ CompactBlock.prototype.toRequest = function toRequest() {
* @returns {Boolean} * @returns {Boolean}
*/ */
CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) { fillMempool(witness, mempool) {
if (this.count === this.totalTX) if (this.count === this.totalTX)
return true; return true;
@ -320,13 +321,13 @@ CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) {
if (set.has(index)) { if (set.has(index)) {
// Siphash collision, just request it. // Siphash collision, just request it.
this.available[index] = null; this.available[index] = null;
this.count--; this.count -= 1;
continue; continue;
} }
this.available[index] = tx; this.available[index] = tx;
set.add(index); set.add(index);
this.count++; this.count += 1;
// We actually may have a siphash collision // We actually may have a siphash collision
// here, but exit early anyway for perf. // here, but exit early anyway for perf.
@ -335,7 +336,7 @@ CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) {
} }
return false; return false;
}; }
/** /**
* Attempt to fill missing transactions from TXResponse. * Attempt to fill missing transactions from TXResponse.
@ -343,7 +344,7 @@ CompactBlock.prototype.fillMempool = function fillMempool(witness, mempool) {
* @returns {Boolean} * @returns {Boolean}
*/ */
CompactBlock.prototype.fillMissing = function fillMissing(res) { fillMissing(res) {
let offset = 0; let offset = 0;
for (let i = 0; i < this.available.length; i++) { for (let i = 0; i < this.available.length; i++) {
@ -357,7 +358,7 @@ CompactBlock.prototype.fillMissing = function fillMissing(res) {
} }
return offset === res.txs.length; return offset === res.txs.length;
}; }
/** /**
* Calculate a transaction short ID. * Calculate a transaction short ID.
@ -365,14 +366,14 @@ CompactBlock.prototype.fillMissing = function fillMissing(res) {
* @returns {Number} * @returns {Number}
*/ */
CompactBlock.prototype.sid = function sid(hash) { sid(hash) {
if (typeof hash === 'string') if (typeof hash === 'string')
hash = Buffer.from(hash, 'hex'); hash = Buffer.from(hash, 'hex');
const [hi, lo] = siphash256(hash, this.sipKey); const [hi, lo] = siphash256(hash, this.sipKey);
return (hi & 0xffff) * 0x100000000 + (lo >>> 0); return (hi & 0xffff) * 0x100000000 + (lo >>> 0);
}; }
/** /**
* Test whether an index is available. * Test whether an index is available.
@ -380,9 +381,9 @@ CompactBlock.prototype.sid = function sid(hash) {
* @returns {Boolean} * @returns {Boolean}
*/ */
CompactBlock.prototype.hasIndex = function hasIndex(index) { hasIndex(index) {
return this.available[index] != null; return this.available[index] != null;
}; }
/** /**
* Initialize the siphash key. * Initialize the siphash key.
@ -390,18 +391,18 @@ CompactBlock.prototype.hasIndex = function hasIndex(index) {
* @returns {Buffer} * @returns {Buffer}
*/ */
CompactBlock.prototype.getKey = function getKey() { getKey() {
const data = Buffer.concat([this.toHead(), this.keyNonce]); const data = Buffer.concat([this.toHead(), this.keyNonce]);
const hash = sha256.digest(data); const hash = sha256.digest(data);
return hash.slice(0, 16); return hash.slice(0, 16);
}; }
/** /**
* Initialize compact block and short id map. * Initialize compact block and short id map.
* @private * @private
*/ */
CompactBlock.prototype.init = function init() { init() {
if (this.totalTX === 0) if (this.totalTX === 0)
throw new Error('Empty vectors.'); throw new Error('Empty vectors.');
@ -428,14 +429,14 @@ CompactBlock.prototype.init = function init() {
assert(last <= 0xffff); assert(last <= 0xffff);
assert(last <= this.ids.length + i); assert(last <= this.ids.length + i);
this.available[last] = tx; this.available[last] = tx;
this.count++; this.count += 1;
} }
for (let i = 0; i < this.ids.length; i++) { for (let i = 0; i < this.ids.length; i++) {
const id = this.ids[i]; const id = this.ids[i];
while (this.available[i + offset]) while (this.available[i + offset])
offset++; offset += 1;
// Fails on siphash collision. // Fails on siphash collision.
if (this.idMap.has(id)) if (this.idMap.has(id))
@ -445,7 +446,7 @@ CompactBlock.prototype.init = function init() {
} }
return true; return true;
}; }
/** /**
* Convert completely filled compact * Convert completely filled compact
@ -453,7 +454,7 @@ CompactBlock.prototype.init = function init() {
* @returns {Block} * @returns {Block}
*/ */
CompactBlock.prototype.toBlock = function toBlock() { toBlock() {
const block = new Block(); const block = new Block();
block.version = this.version; block.version = this.version;
@ -471,7 +472,7 @@ CompactBlock.prototype.toBlock = function toBlock() {
} }
return block; return block;
}; }
/** /**
* Inject properties from block. * Inject properties from block.
@ -482,7 +483,7 @@ CompactBlock.prototype.toBlock = function toBlock() {
* @returns {CompactBlock} * @returns {CompactBlock}
*/ */
CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) { fromBlock(block, witness, nonce) {
this.version = block.version; this.version = block.version;
this.prevBlock = block.prevBlock; this.prevBlock = block.prevBlock;
this.merkleRoot = block.merkleRoot; this.merkleRoot = block.merkleRoot;
@ -514,7 +515,7 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) {
this.ptx.push([0, block.txs[0]]); this.ptx.push([0, block.txs[0]]);
return this; return this;
}; }
/** /**
* Instantiate compact block from a block. * Instantiate compact block from a block.
@ -524,32 +525,36 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) {
* @returns {CompactBlock} * @returns {CompactBlock}
*/ */
CompactBlock.fromBlock = function fromBlock(block, witness, nonce) { static fromBlock(block, witness, nonce) {
return new CompactBlock().fromBlock(block, witness, nonce); return new this().fromBlock(block, witness, nonce);
}; }
/** /**
* Convert block to headers. * Convert block to headers.
* @returns {Headers} * @returns {Headers}
*/ */
CompactBlock.prototype.toHeaders = function toHeaders() { toHeaders() {
return Headers.fromBlock(this); return Headers.fromBlock(this);
}; }
}
/** /**
* TX Request
* Represents a BlockTransactionsRequest (bip152): `getblocktxn` packet. * Represents a BlockTransactionsRequest (bip152): `getblocktxn` packet.
* @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki * @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
* @constructor
* @param {Object} options
* @property {Hash} hash * @property {Hash} hash
* @property {Number[]} indexes * @property {Number[]} indexes
*/ */
function TXRequest(options) { class TXRequest {
if (!(this instanceof TXRequest)) /**
return new TXRequest(options); * TX Request
* @constructor
* @param {Object?} options
*/
constructor(options) {
this.hash = encoding.NULL_HASH; this.hash = encoding.NULL_HASH;
this.indexes = []; this.indexes = [];
@ -564,14 +569,14 @@ function TXRequest(options) {
* @returns {TXRequest} * @returns {TXRequest}
*/ */
TXRequest.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
this.hash = options.hash; this.hash = options.hash;
if (options.indexes) if (options.indexes)
this.indexes = options.indexes; this.indexes = options.indexes;
return this; return this;
}; }
/** /**
* Instantiate request from options. * Instantiate request from options.
@ -579,9 +584,9 @@ TXRequest.prototype.fromOptions = function fromOptions(options) {
* @returns {TXRequest} * @returns {TXRequest}
*/ */
TXRequest.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new TXRequest().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Inject properties from compact block. * Inject properties from compact block.
@ -590,7 +595,7 @@ TXRequest.fromOptions = function fromOptions(options) {
* @returns {TXRequest} * @returns {TXRequest}
*/ */
TXRequest.prototype.fromCompact = function fromCompact(block) { fromCompact(block) {
this.hash = block.hash('hex'); this.hash = block.hash('hex');
for (let i = 0; i < block.available.length; i++) { for (let i = 0; i < block.available.length; i++) {
@ -599,7 +604,7 @@ TXRequest.prototype.fromCompact = function fromCompact(block) {
} }
return this; return this;
}; }
/** /**
* Instantiate request from compact block. * Instantiate request from compact block.
@ -607,9 +612,9 @@ TXRequest.prototype.fromCompact = function fromCompact(block) {
* @returns {TXRequest} * @returns {TXRequest}
*/ */
TXRequest.fromCompact = function fromCompact(block) { static fromCompact(block) {
return new TXRequest().fromCompact(block); return new this().fromCompact(block);
}; }
/** /**
* Inject properties from buffer reader. * Inject properties from buffer reader.
@ -618,7 +623,7 @@ TXRequest.fromCompact = function fromCompact(block) {
* @returns {TXRequest} * @returns {TXRequest}
*/ */
TXRequest.prototype.fromReader = function fromReader(br) { fromReader(br) {
this.hash = br.readHash('hex'); this.hash = br.readHash('hex');
const count = br.readVarint(); const count = br.readVarint();
@ -640,7 +645,7 @@ TXRequest.prototype.fromReader = function fromReader(br) {
} }
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -649,9 +654,9 @@ TXRequest.prototype.fromReader = function fromReader(br) {
* @returns {TXRequest} * @returns {TXRequest}
*/ */
TXRequest.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
return this.fromReader(new BufferReader(data)); return this.fromReader(new BufferReader(data));
}; }
/** /**
* Instantiate request from buffer reader. * Instantiate request from buffer reader.
@ -659,9 +664,9 @@ TXRequest.prototype.fromRaw = function fromRaw(data) {
* @returns {TXRequest} * @returns {TXRequest}
*/ */
TXRequest.fromReader = function fromReader(br) { static fromReader(br) {
return new TXRequest().fromReader(br); return new this().fromReader(br);
}; }
/** /**
* Instantiate request from serialized data. * Instantiate request from serialized data.
@ -669,16 +674,16 @@ TXRequest.fromReader = function fromReader(br) {
* @returns {TXRequest} * @returns {TXRequest}
*/ */
TXRequest.fromRaw = function fromRaw(data) { static fromRaw(data) {
return new TXRequest().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Calculate request serialization size. * Calculate request serialization size.
* @returns {Number} * @returns {Number}
*/ */
TXRequest.prototype.getSize = function getSize() { getSize() {
let size = 0; let size = 0;
size += 32; size += 32;
@ -694,14 +699,14 @@ TXRequest.prototype.getSize = function getSize() {
} }
return size; return size;
}; }
/** /**
* Write serialized request to buffer writer. * Write serialized request to buffer writer.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
TXRequest.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
bw.writeHash(this.hash); bw.writeHash(this.hash);
bw.writeVarint(this.indexes.length); bw.writeVarint(this.indexes.length);
@ -716,31 +721,35 @@ TXRequest.prototype.toWriter = function toWriter(bw) {
} }
return bw; return bw;
}; }
/** /**
* Serialize request. * Serialize request.
* @returns {Buffer} * @returns {Buffer}
*/ */
TXRequest.prototype.toRaw = function toRaw() { toRaw() {
const size = this.getSize(); const size = this.getSize();
return this.toWriter(new StaticWriter(size)).render(); return this.toWriter(new StaticWriter(size)).render();
}; }
}
/** /**
* TX Response
* Represents BlockTransactions (bip152): `blocktxn` packet. * Represents BlockTransactions (bip152): `blocktxn` packet.
* @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki * @see https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki
* @constructor
* @param {Object} options
* @property {Hash} hash * @property {Hash} hash
* @property {TX[]} txs * @property {TX[]} txs
*/ */
function TXResponse(options) { class TXResponse {
if (!(this instanceof TXResponse)) /**
return new TXResponse(options); * Create a tx response.
* @constructor
* @param {Object?} options
*/
constructor(options) {
this.hash = encoding.NULL_HASH; this.hash = encoding.NULL_HASH;
this.txs = []; this.txs = [];
@ -755,14 +764,14 @@ function TXResponse(options) {
* @returns {TXResponse} * @returns {TXResponse}
*/ */
TXResponse.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
this.hash = options.hash; this.hash = options.hash;
if (options.txs) if (options.txs)
this.txs = options.txs; this.txs = options.txs;
return this; return this;
}; }
/** /**
* Instantiate response from options. * Instantiate response from options.
@ -770,9 +779,9 @@ TXResponse.prototype.fromOptions = function fromOptions(options) {
* @returns {TXResponse} * @returns {TXResponse}
*/ */
TXResponse.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new TXResponse().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Inject properties from buffer reader. * Inject properties from buffer reader.
@ -781,7 +790,7 @@ TXResponse.fromOptions = function fromOptions(options) {
* @returns {TXResponse} * @returns {TXResponse}
*/ */
TXResponse.prototype.fromReader = function fromReader(br) { fromReader(br) {
this.hash = br.readHash('hex'); this.hash = br.readHash('hex');
const count = br.readVarint(); const count = br.readVarint();
@ -790,7 +799,7 @@ TXResponse.prototype.fromReader = function fromReader(br) {
this.txs.push(TX.fromReader(br)); this.txs.push(TX.fromReader(br));
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -799,9 +808,9 @@ TXResponse.prototype.fromReader = function fromReader(br) {
* @returns {TXResponse} * @returns {TXResponse}
*/ */
TXResponse.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
return this.fromReader(new BufferReader(data)); return this.fromReader(new BufferReader(data));
}; }
/** /**
* Instantiate response from buffer reader. * Instantiate response from buffer reader.
@ -809,9 +818,9 @@ TXResponse.prototype.fromRaw = function fromRaw(data) {
* @returns {TXResponse} * @returns {TXResponse}
*/ */
TXResponse.fromReader = function fromReader(br) { static fromReader(br) {
return new TXResponse().fromReader(br); return new this().fromReader(br);
}; }
/** /**
* Instantiate response from serialized data. * Instantiate response from serialized data.
@ -819,9 +828,9 @@ TXResponse.fromReader = function fromReader(br) {
* @returns {TXResponse} * @returns {TXResponse}
*/ */
TXResponse.fromRaw = function fromRaw(data) { static fromRaw(data) {
return new TXResponse().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Inject properties from block. * Inject properties from block.
@ -830,7 +839,7 @@ TXResponse.fromRaw = function fromRaw(data) {
* @returns {TXResponse} * @returns {TXResponse}
*/ */
TXResponse.prototype.fromBlock = function fromBlock(block, req) { fromBlock(block, req) {
this.hash = req.hash; this.hash = req.hash;
for (const index of req.indexes) { for (const index of req.indexes) {
@ -841,7 +850,7 @@ TXResponse.prototype.fromBlock = function fromBlock(block, req) {
} }
return this; return this;
}; }
/** /**
* Instantiate response from block. * Instantiate response from block.
@ -849,27 +858,27 @@ TXResponse.prototype.fromBlock = function fromBlock(block, req) {
* @returns {TXResponse} * @returns {TXResponse}
*/ */
TXResponse.fromBlock = function fromBlock(block, req) { static fromBlock(block, req) {
return new TXResponse().fromBlock(block, req); return new this().fromBlock(block, req);
}; }
/** /**
* Serialize response with witness data. * Serialize response with witness data.
* @returns {Buffer} * @returns {Buffer}
*/ */
TXResponse.prototype.toRaw = function toRaw() { toRaw() {
return this.frameRaw(true); return this.frameRaw(true);
}; }
/** /**
* Serialize response without witness data. * Serialize response without witness data.
* @returns {Buffer} * @returns {Buffer}
*/ */
TXResponse.prototype.toNormal = function toNormal() { toNormal() {
return this.frameRaw(false); return this.frameRaw(false);
}; }
/** /**
* Write serialized response to a buffer * Write serialized response to a buffer
@ -877,9 +886,9 @@ TXResponse.prototype.toNormal = function toNormal() {
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
TXResponse.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
return this.writeRaw(bw, true); return this.writeRaw(bw, true);
}; }
/** /**
* Write serialized response to a buffer * Write serialized response to a buffer
@ -887,16 +896,16 @@ TXResponse.prototype.toWriter = function toWriter(bw) {
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
TXResponse.prototype.toNormalWriter = function toNormalWriter(bw) { toNormalWriter(bw) {
return this.writeRaw(bw, false); return this.writeRaw(bw, false);
}; }
/** /**
* Calculate request serialization size. * Calculate request serialization size.
* @returns {Number} * @returns {Number}
*/ */
TXResponse.prototype.getSize = function getSize(witness) { getSize(witness) {
let size = 0; let size = 0;
size += 32; size += 32;
@ -910,7 +919,7 @@ TXResponse.prototype.getSize = function getSize(witness) {
} }
return size; return size;
}; }
/** /**
* Write serialized response to buffer writer. * Write serialized response to buffer writer.
@ -919,7 +928,7 @@ TXResponse.prototype.getSize = function getSize(witness) {
* @param {Boolean} witness * @param {Boolean} witness
*/ */
TXResponse.prototype.writeRaw = function writeRaw(bw, witness) { writeRaw(bw, witness) {
bw.writeHash(this.hash); bw.writeHash(this.hash);
bw.writeVarint(this.txs.length); bw.writeVarint(this.txs.length);
@ -932,7 +941,7 @@ TXResponse.prototype.writeRaw = function writeRaw(bw, witness) {
} }
return bw; return bw;
}; }
/** /**
* Serialize response with witness data. * Serialize response with witness data.
@ -941,10 +950,11 @@ TXResponse.prototype.writeRaw = function writeRaw(bw, witness) {
* @returns {Buffer} * @returns {Buffer}
*/ */
TXResponse.prototype.frameRaw = function frameRaw(witness) { frameRaw(witness) {
const size = this.getSize(witness); const size = this.getSize(witness);
return this.writeRaw(new StaticWriter(size), witness).render(); return this.writeRaw(new StaticWriter(size), witness).render();
}; }
}
/* /*
* Expose * Expose

View File

@ -11,30 +11,30 @@ const assert = require('assert');
const hash256 = require('bcrypto/lib/hash256'); const hash256 = require('bcrypto/lib/hash256');
const BufferReader = require('bufio/lib/reader'); const BufferReader = require('bufio/lib/reader');
const StaticWriter = require('bufio/lib/staticwriter'); const StaticWriter = require('bufio/lib/staticwriter');
const InvItem = require('./invitem');
const encoding = require('bufio/lib/encoding'); const encoding = require('bufio/lib/encoding');
const InvItem = require('./invitem');
const consensus = require('../protocol/consensus'); const consensus = require('../protocol/consensus');
/** /**
* Abstract Block
* The class which all block-like objects inherit from. * The class which all block-like objects inherit from.
* @alias module:primitives.AbstractBlock * @alias module:primitives.AbstractBlock
* @constructor
* @abstract * @abstract
* @property {Number} version - Block version. Note * @property {Number} version
* that Bcoin reads versions as unsigned despite * @property {Hash} prevBlock
* them being signed on the protocol level. This * @property {Hash} merkleRoot
* number will never be negative. * @property {Number} time
* @property {Hash} prevBlock - Previous block hash.
* @property {Hash} merkleRoot - Merkle root hash.
* @property {Number} time - Timestamp.
* @property {Number} bits * @property {Number} bits
* @property {Number} nonce * @property {Number} nonce
*/ */
function AbstractBlock() { class AbstractBlock {
if (!(this instanceof AbstractBlock)) /**
return new AbstractBlock(); * Create an abstract block.
* @constructor
*/
constructor() {
this.version = 1; this.version = 1;
this.prevBlock = encoding.NULL_HASH; this.prevBlock = encoding.NULL_HASH;
this.merkleRoot = encoding.NULL_HASH; this.merkleRoot = encoding.NULL_HASH;
@ -54,7 +54,7 @@ function AbstractBlock() {
* @param {NakedBlock} options * @param {NakedBlock} options
*/ */
AbstractBlock.prototype.parseOptions = function parseOptions(options) { parseOptions(options) {
assert(options, 'Block data is required.'); assert(options, 'Block data is required.');
assert((options.version >>> 0) === options.version); assert((options.version >>> 0) === options.version);
assert(typeof options.prevBlock === 'string'); assert(typeof options.prevBlock === 'string');
@ -70,11 +70,13 @@ AbstractBlock.prototype.parseOptions = function parseOptions(options) {
this.bits = options.bits; this.bits = options.bits;
this.nonce = options.nonce; this.nonce = options.nonce;
if (options.mutable != null) if (options.mutable != null) {
this.mutable = Boolean(options.mutable); assert(typeof options.mutable === 'boolean');
this.mutable = options.mutable;
}
return this; return this;
}; }
/** /**
* Inject properties from json object. * Inject properties from json object.
@ -82,7 +84,7 @@ AbstractBlock.prototype.parseOptions = function parseOptions(options) {
* @param {Object} json * @param {Object} json
*/ */
AbstractBlock.prototype.parseJSON = function parseJSON(json) { parseJSON(json) {
assert(json, 'Block data is required.'); assert(json, 'Block data is required.');
assert((json.version >>> 0) === json.version); assert((json.version >>> 0) === json.version);
assert(typeof json.prevBlock === 'string'); assert(typeof json.prevBlock === 'string');
@ -99,33 +101,33 @@ AbstractBlock.prototype.parseJSON = function parseJSON(json) {
this.nonce = json.nonce; this.nonce = json.nonce;
return this; return this;
}; }
/** /**
* Test whether the block is a memblock. * Test whether the block is a memblock.
* @returns {Boolean} * @returns {Boolean}
*/ */
AbstractBlock.prototype.isMemory = function isMemory() { isMemory() {
return false; return false;
}; }
/** /**
* Clear any cached values (abstract). * Clear any cached values (abstract).
*/ */
AbstractBlock.prototype._refresh = function _refresh() { _refresh() {
this._hash = null; this._hash = null;
this._hhash = null; this._hhash = null;
}; }
/** /**
* Clear any cached values. * Clear any cached values.
*/ */
AbstractBlock.prototype.refresh = function refresh() { refresh() {
return this._refresh(); return this._refresh();
}; }
/** /**
* Hash the block headers. * Hash the block headers.
@ -133,7 +135,7 @@ AbstractBlock.prototype.refresh = function refresh() {
* @returns {Hash|Buffer} hash * @returns {Hash|Buffer} hash
*/ */
AbstractBlock.prototype.hash = function hash(enc) { hash(enc) {
let h = this._hash; let h = this._hash;
if (!h) { if (!h) {
@ -153,16 +155,16 @@ AbstractBlock.prototype.hash = function hash(enc) {
} }
return h; return h;
}; }
/** /**
* Serialize the block headers. * Serialize the block headers.
* @returns {Buffer} * @returns {Buffer}
*/ */
AbstractBlock.prototype.toHead = function toHead() { toHead() {
return this.writeHead(new StaticWriter(80)).render(); return this.writeHead(new StaticWriter(80)).render();
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -170,16 +172,16 @@ AbstractBlock.prototype.toHead = function toHead() {
* @param {Buffer} data * @param {Buffer} data
*/ */
AbstractBlock.prototype.fromHead = function fromHead(data) { fromHead(data) {
return this.readHead(new BufferReader(data)); return this.readHead(new BufferReader(data));
}; }
/** /**
* Serialize the block headers. * Serialize the block headers.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
AbstractBlock.prototype.writeHead = function writeHead(bw) { writeHead(bw) {
bw.writeU32(this.version); bw.writeU32(this.version);
bw.writeHash(this.prevBlock); bw.writeHash(this.prevBlock);
bw.writeHash(this.merkleRoot); bw.writeHash(this.merkleRoot);
@ -187,14 +189,14 @@ AbstractBlock.prototype.writeHead = function writeHead(bw) {
bw.writeU32(this.bits); bw.writeU32(this.bits);
bw.writeU32(this.nonce); bw.writeU32(this.nonce);
return bw; return bw;
}; }
/** /**
* Parse the block headers. * Parse the block headers.
* @param {BufferReader} br * @param {BufferReader} br
*/ */
AbstractBlock.prototype.readHead = function readHead(br) { readHead(br) {
this.version = br.readU32(); this.version = br.readU32();
this.prevBlock = br.readHash('hex'); this.prevBlock = br.readHash('hex');
this.merkleRoot = br.readHash('hex'); this.merkleRoot = br.readHash('hex');
@ -202,14 +204,14 @@ AbstractBlock.prototype.readHead = function readHead(br) {
this.bits = br.readU32(); this.bits = br.readU32();
this.nonce = br.readU32(); this.nonce = br.readU32();
return this; return this;
}; }
/** /**
* Verify the block. * Verify the block.
* @returns {Boolean} * @returns {Boolean}
*/ */
AbstractBlock.prototype.verify = function verify() { verify() {
if (!this.verifyPOW()) if (!this.verifyPOW())
return false; return false;
@ -217,43 +219,44 @@ AbstractBlock.prototype.verify = function verify() {
return false; return false;
return true; return true;
}; }
/** /**
* Verify proof-of-work. * Verify proof-of-work.
* @returns {Boolean} * @returns {Boolean}
*/ */
AbstractBlock.prototype.verifyPOW = function verifyPOW() { verifyPOW() {
return consensus.verifyPOW(this.hash(), this.bits); return consensus.verifyPOW(this.hash(), this.bits);
}; }
/** /**
* Verify the block. * Verify the block.
* @returns {Boolean} * @returns {Boolean}
*/ */
AbstractBlock.prototype.verifyBody = function verifyBody() { verifyBody() {
throw new Error('Abstract method.'); throw new Error('Abstract method.');
}; }
/** /**
* Get little-endian block hash. * Get little-endian block hash.
* @returns {Hash} * @returns {Hash}
*/ */
AbstractBlock.prototype.rhash = function rhash() { rhash() {
return encoding.revHex(this.hash('hex')); return encoding.revHex(this.hash('hex'));
}; }
/** /**
* Convert the block to an inv item. * Convert the block to an inv item.
* @returns {InvItem} * @returns {InvItem}
*/ */
AbstractBlock.prototype.toInv = function toInv() { toInv() {
return new InvItem(InvItem.types.BLOCK, this.hash('hex')); return new InvItem(InvItem.types.BLOCK, this.hash('hex'));
}; }
}
/* /*
* Expose * Expose

View File

@ -8,30 +8,32 @@
'use strict'; 'use strict';
const assert = require('assert'); const assert = require('assert');
const Network = require('../protocol/network'); const {base58, bech32} = require('bstring');
const encoding = require('bufio/lib/encoding'); const encoding = require('bufio/lib/encoding');
const sha256 = require('bcrypto/lib/sha256'); const sha256 = require('bcrypto/lib/sha256');
const hash160 = require('bcrypto/lib/hash160'); const hash160 = require('bcrypto/lib/hash160');
const hash256 = require('bcrypto/lib/hash256'); const hash256 = require('bcrypto/lib/hash256');
const BufferReader = require('bufio/lib/reader'); const BufferReader = require('bufio/lib/reader');
const StaticWriter = require('bufio/lib/staticwriter'); const StaticWriter = require('bufio/lib/staticwriter');
const base58 = require('bstring/lib/base58'); const Network = require('../protocol/network');
const bech32 = require('bstring/lib/bech32');
/** /**
* Address
* Represents an address. * Represents an address.
* @alias module:primitives.Address * @alias module:primitives.Address
* @constructor
* @param {Object?} options
* @property {Buffer} hash * @property {Buffer} hash
* @property {AddressPrefix} type * @property {AddressPrefix} type
* @property {Number} version * @property {Number} version
*/ */
function Address(options, network) { class Address {
if (!(this instanceof Address)) /**
return new Address(options, network); * Create an address.
* @constructor
* @param {Object?} options
*/
constructor(options, network) {
this.type = Address.types.PUBKEYHASH; this.type = Address.types.PUBKEYHASH;
this.version = -1; this.version = -1;
this.hash = encoding.ZERO_HASH160; this.hash = encoding.ZERO_HASH160;
@ -40,42 +42,22 @@ function Address(options, network) {
this.fromOptions(options, network); this.fromOptions(options, network);
} }
/**
* Address types.
* @enum {Number}
*/
Address.types = {
PUBKEYHASH: 2,
SCRIPTHASH: 3,
WITNESS: 4
};
/**
* Address types by value.
* @const {RevMap}
*/
Address.typesByVal = [
null,
null,
'PUBKEYHASH',
'SCRIPTHASH',
'WITNESS'
];
/** /**
* Inject properties from options object. * Inject properties from options object.
* @private * @private
* @param {Object} options * @param {Object} options
*/ */
Address.prototype.fromOptions = function fromOptions(options, network) { fromOptions(options, network) {
if (typeof options === 'string') if (typeof options === 'string')
return this.fromString(options, network); return this.fromString(options, network);
return this.fromHash(options.hash, options.type, options.version); assert(options);
};
const {hash, type, version} = options;
return this.fromHash(hash, type, version);
}
/** /**
* Insantiate address from options. * Insantiate address from options.
@ -83,9 +65,9 @@ Address.prototype.fromOptions = function fromOptions(options, network) {
* @returns {Address} * @returns {Address}
*/ */
Address.fromOptions = function fromOptions(options, network) { static fromOptions(options, network) {
return new Address().fromOptions(options, network); return new this().fromOptions(options, network);
}; }
/** /**
* Get the address hash. * Get the address hash.
@ -93,18 +75,18 @@ Address.fromOptions = function fromOptions(options, network) {
* @returns {Hash|Buffer} * @returns {Hash|Buffer}
*/ */
Address.prototype.getHash = function getHash(enc) { getHash(enc) {
if (enc === 'hex') if (enc === 'hex')
return this.hash.toString(enc); return this.hash.toString(enc);
return this.hash; return this.hash;
}; }
/** /**
* Test whether the address is null. * Test whether the address is null.
* @returns {Boolean} * @returns {Boolean}
*/ */
Address.prototype.isNull = function isNull() { isNull() {
if (this.hash.length === 20) if (this.hash.length === 20)
return this.hash.equals(encoding.ZERO_HASH160); return this.hash.equals(encoding.ZERO_HASH160);
@ -117,7 +99,7 @@ Address.prototype.isNull = function isNull() {
} }
return true; return true;
}; }
/** /**
* Test equality against another address. * Test equality against another address.
@ -125,22 +107,22 @@ Address.prototype.isNull = function isNull() {
* @returns {Boolean} * @returns {Boolean}
*/ */
Address.prototype.equals = function equals(addr) { equals(addr) {
assert(addr instanceof Address); assert(addr instanceof Address);
return this.type === addr.type return this.type === addr.type
&& this.version === addr.version && this.version === addr.version
&& this.hash.equals(addr.hash); && this.hash.equals(addr.hash);
}; }
/** /**
* Get the address type as a string. * Get the address type as a string.
* @returns {String} * @returns {String}
*/ */
Address.prototype.getType = function getType() { getType() {
return Address.typesByVal[this.type].toLowerCase(); return Address.typesByVal[this.type].toLowerCase();
}; }
/** /**
* Get a network address prefix for the address. * Get a network address prefix for the address.
@ -148,7 +130,7 @@ Address.prototype.getType = function getType() {
* @returns {Number} * @returns {Number}
*/ */
Address.prototype.getPrefix = function getPrefix(network) { getPrefix(network) {
network = Network.get(network); network = Network.get(network);
const prefixes = network.addressPrefix; const prefixes = network.addressPrefix;
@ -169,21 +151,21 @@ Address.prototype.getPrefix = function getPrefix(network) {
} }
return -1; return -1;
}; }
/** /**
* Calculate size of serialized address. * Calculate size of serialized address.
* @returns {Number} * @returns {Number}
*/ */
Address.prototype.getSize = function getSize() { getSize() {
let size = 5 + this.hash.length; let size = 5 + this.hash.length;
if (this.version !== -1) if (this.version !== -1)
size += 2; size += 2;
return size; return size;
}; }
/** /**
* Compile the address object to its raw serialization. * Compile the address object to its raw serialization.
@ -192,7 +174,7 @@ Address.prototype.getSize = function getSize() {
* @throws Error on bad hash/prefix. * @throws Error on bad hash/prefix.
*/ */
Address.prototype.toRaw = function toRaw(network) { toRaw(network) {
const size = this.getSize(); const size = this.getSize();
const bw = new StaticWriter(size); const bw = new StaticWriter(size);
const prefix = this.getPrefix(network); const prefix = this.getPrefix(network);
@ -210,7 +192,7 @@ Address.prototype.toRaw = function toRaw(network) {
bw.writeChecksum(hash256.digest); bw.writeChecksum(hash256.digest);
return bw.render(); return bw.render();
}; }
/** /**
* Compile the address object to a base58 address. * Compile the address object to a base58 address.
@ -219,9 +201,9 @@ Address.prototype.toRaw = function toRaw(network) {
* @throws Error on bad hash/prefix. * @throws Error on bad hash/prefix.
*/ */
Address.prototype.toBase58 = function toBase58(network) { toBase58(network) {
return base58.encode(this.toRaw(network)); return base58.encode(this.toRaw(network));
}; }
/** /**
* Compile the address object to a bech32 address. * Compile the address object to a bech32 address.
@ -230,7 +212,7 @@ Address.prototype.toBase58 = function toBase58(network) {
* @throws Error on bad hash/prefix. * @throws Error on bad hash/prefix.
*/ */
Address.prototype.toBech32 = function toBech32(network) { toBech32(network) {
const version = this.version; const version = this.version;
const hash = this.hash; const hash = this.hash;
@ -242,7 +224,7 @@ Address.prototype.toBech32 = function toBech32(network) {
const hrp = network.addressPrefix.bech32; const hrp = network.addressPrefix.bech32;
return bech32.encode(hrp, version, hash); return bech32.encode(hrp, version, hash);
}; }
/** /**
* Inject properties from string. * Inject properties from string.
@ -252,7 +234,7 @@ Address.prototype.toBech32 = function toBech32(network) {
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromString = function fromString(addr, network) { fromString(addr, network) {
assert(typeof addr === 'string'); assert(typeof addr === 'string');
assert(addr.length > 0); assert(addr.length > 0);
assert(addr.length <= 100); assert(addr.length <= 100);
@ -268,7 +250,7 @@ Address.prototype.fromString = function fromString(addr, network) {
} catch (e) { } catch (e) {
return this.fromBase58(addr, network); return this.fromBase58(addr, network);
} }
}; }
/** /**
* Instantiate address from string. * Instantiate address from string.
@ -277,9 +259,9 @@ Address.prototype.fromString = function fromString(addr, network) {
* @returns {Address} * @returns {Address}
*/ */
Address.fromString = function fromString(addr, network) { static fromString(addr, network) {
return new Address().fromString(addr, network); return new this().fromString(addr, network);
}; }
/** /**
* Convert the Address to a string. * Convert the Address to a string.
@ -287,24 +269,24 @@ Address.fromString = function fromString(addr, network) {
* @returns {Base58Address} * @returns {Base58Address}
*/ */
Address.prototype.toString = function toString(network) { toString(network) {
if (this.version !== -1) if (this.version !== -1)
return this.toBech32(network); return this.toBech32(network);
return this.toBase58(network); return this.toBase58(network);
}; }
/** /**
* Inspect the Address. * Inspect the Address.
* @returns {Object} * @returns {Object}
*/ */
Address.prototype.inspect = function inspect() { inspect() {
return '<Address:' return '<Address:'
+ ` type=${this.getType()}` + ` type=${this.getType()}`
+ ` version=${this.version}` + ` version=${this.version}`
+ ` str=${this.toString()}` + ` str=${this.toString()}`
+ '>'; + '>';
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -313,7 +295,7 @@ Address.prototype.inspect = function inspect() {
* @throws Parse error * @throws Parse error
*/ */
Address.prototype.fromRaw = function fromRaw(data, network) { fromRaw(data, network) {
const br = new BufferReader(data, true); const br = new BufferReader(data, true);
const prefix = br.readU8(); const prefix = br.readU8();
@ -340,7 +322,7 @@ Address.prototype.fromRaw = function fromRaw(data, network) {
br.verifyChecksum(hash256.digest); br.verifyChecksum(hash256.digest);
return this.fromHash(hash, type, version); return this.fromHash(hash, type, version);
}; }
/** /**
* Create an address object from a serialized address. * Create an address object from a serialized address.
@ -349,9 +331,9 @@ Address.prototype.fromRaw = function fromRaw(data, network) {
* @throws Parse error. * @throws Parse error.
*/ */
Address.fromRaw = function fromRaw(data, network) { static fromRaw(data, network) {
return new Address().fromRaw(data, network); return new this().fromRaw(data, network);
}; }
/** /**
* Inject properties from base58 address. * Inject properties from base58 address.
@ -361,14 +343,14 @@ Address.fromRaw = function fromRaw(data, network) {
* @throws Parse error * @throws Parse error
*/ */
Address.prototype.fromBase58 = function fromBase58(data, network) { fromBase58(data, network) {
assert(typeof data === 'string'); assert(typeof data === 'string');
if (data.length > 55) if (data.length > 55)
throw new Error('Address is too long.'); throw new Error('Address is too long.');
return this.fromRaw(base58.decode(data), network); return this.fromRaw(base58.decode(data), network);
}; }
/** /**
* Create an address object from a base58 address. * Create an address object from a base58 address.
@ -378,9 +360,9 @@ Address.prototype.fromBase58 = function fromBase58(data, network) {
* @throws Parse error. * @throws Parse error.
*/ */
Address.fromBase58 = function fromBase58(data, network) { static fromBase58(data, network) {
return new Address().fromBase58(data, network); return new this().fromBase58(data, network);
}; }
/** /**
* Inject properties from bech32 address. * Inject properties from bech32 address.
@ -390,7 +372,7 @@ Address.fromBase58 = function fromBase58(data, network) {
* @throws Parse error * @throws Parse error
*/ */
Address.prototype.fromBech32 = function fromBech32(data, network) { fromBech32(data, network) {
const type = Address.types.WITNESS; const type = Address.types.WITNESS;
assert(typeof data === 'string'); assert(typeof data === 'string');
@ -400,7 +382,7 @@ Address.prototype.fromBech32 = function fromBech32(data, network) {
Network.fromBech32(addr.hrp, network); Network.fromBech32(addr.hrp, network);
return this.fromHash(addr.hash, type, addr.version); return this.fromHash(addr.hash, type, addr.version);
}; }
/** /**
* Create an address object from a bech32 address. * Create an address object from a bech32 address.
@ -410,9 +392,9 @@ Address.prototype.fromBech32 = function fromBech32(data, network) {
* @throws Parse error. * @throws Parse error.
*/ */
Address.fromBech32 = function fromBech32(data, network) { static fromBech32(data, network) {
return new Address().fromBech32(data, network); return new this().fromBech32(data, network);
}; }
/** /**
* Inject properties from output script. * Inject properties from output script.
@ -420,7 +402,7 @@ Address.fromBech32 = function fromBech32(data, network) {
* @param {Script} script * @param {Script} script
*/ */
Address.prototype.fromScript = function fromScript(script) { fromScript(script) {
const pk = script.getPubkey(); const pk = script.getPubkey();
if (pk) { if (pk) {
@ -466,7 +448,7 @@ Address.prototype.fromScript = function fromScript(script) {
} }
return null; return null;
}; }
/** /**
* Inject properties from witness. * Inject properties from witness.
@ -474,7 +456,7 @@ Address.prototype.fromScript = function fromScript(script) {
* @param {Witness} witness * @param {Witness} witness
*/ */
Address.prototype.fromWitness = function fromWitness(witness) { fromWitness(witness) {
const [, pk] = witness.getPubkeyhashInput(); const [, pk] = witness.getPubkeyhashInput();
// We're pretty much screwed here // We're pretty much screwed here
@ -496,7 +478,7 @@ Address.prototype.fromWitness = function fromWitness(witness) {
} }
return null; return null;
}; }
/** /**
* Inject properties from input script. * Inject properties from input script.
@ -504,7 +486,7 @@ Address.prototype.fromWitness = function fromWitness(witness) {
* @param {Script} script * @param {Script} script
*/ */
Address.prototype.fromInputScript = function fromInputScript(script) { fromInputScript(script) {
const [, pk] = script.getPubkeyhashInput(); const [, pk] = script.getPubkeyhashInput();
if (pk) { if (pk) {
@ -524,7 +506,7 @@ Address.prototype.fromInputScript = function fromInputScript(script) {
} }
return null; return null;
}; }
/** /**
* Create an Address from a witness. * Create an Address from a witness.
@ -534,9 +516,9 @@ Address.prototype.fromInputScript = function fromInputScript(script) {
* @returns {Address|null} * @returns {Address|null}
*/ */
Address.fromWitness = function fromWitness(witness) { static fromWitness(witness) {
return new Address().fromWitness(witness); return new this().fromWitness(witness);
}; }
/** /**
* Create an Address from an input script. * Create an Address from an input script.
@ -546,9 +528,9 @@ Address.fromWitness = function fromWitness(witness) {
* @returns {Address|null} * @returns {Address|null}
*/ */
Address.fromInputScript = function fromInputScript(script) { static fromInputScript(script) {
return new Address().fromInputScript(script); return new this().fromInputScript(script);
}; }
/** /**
* Create an Address from an output script. * Create an Address from an output script.
@ -559,9 +541,9 @@ Address.fromInputScript = function fromInputScript(script) {
* @returns {Address|null} * @returns {Address|null}
*/ */
Address.fromScript = function fromScript(script) { static fromScript(script) {
return new Address().fromScript(script); return new this().fromScript(script);
}; }
/** /**
* Inject properties from a hash. * Inject properties from a hash.
@ -572,7 +554,7 @@ Address.fromScript = function fromScript(script) {
* @throws on bad hash size * @throws on bad hash size
*/ */
Address.prototype.fromHash = function fromHash(hash, type, version) { fromHash(hash, type, version) {
if (typeof hash === 'string') if (typeof hash === 'string')
hash = Buffer.from(hash, 'hex'); hash = Buffer.from(hash, 'hex');
@ -612,7 +594,7 @@ Address.prototype.fromHash = function fromHash(hash, type, version) {
this.version = version; this.version = version;
return this; return this;
}; }
/** /**
* Create a naked address from hash/type/version. * Create a naked address from hash/type/version.
@ -623,9 +605,9 @@ Address.prototype.fromHash = function fromHash(hash, type, version) {
* @throws on bad hash size * @throws on bad hash size
*/ */
Address.fromHash = function fromHash(hash, type, version) { static fromHash(hash, type, version) {
return new Address().fromHash(hash, type, version); return new this().fromHash(hash, type, version);
}; }
/** /**
* Inject properties from pubkeyhash. * Inject properties from pubkeyhash.
@ -634,11 +616,11 @@ Address.fromHash = function fromHash(hash, type, version) {
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromPubkeyhash = function fromPubkeyhash(hash) { fromPubkeyhash(hash) {
const type = Address.types.PUBKEYHASH; const type = Address.types.PUBKEYHASH;
assert(hash.length === 20, 'P2PKH must be 20 bytes.'); assert(hash.length === 20, 'P2PKH must be 20 bytes.');
return this.fromHash(hash, type, -1); return this.fromHash(hash, type, -1);
}; }
/** /**
* Instantiate address from pubkeyhash. * Instantiate address from pubkeyhash.
@ -646,9 +628,9 @@ Address.prototype.fromPubkeyhash = function fromPubkeyhash(hash) {
* @returns {Address} * @returns {Address}
*/ */
Address.fromPubkeyhash = function fromPubkeyhash(hash) { static fromPubkeyhash(hash) {
return new Address().fromPubkeyhash(hash); return new this().fromPubkeyhash(hash);
}; }
/** /**
* Inject properties from scripthash. * Inject properties from scripthash.
@ -657,11 +639,11 @@ Address.fromPubkeyhash = function fromPubkeyhash(hash) {
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromScripthash = function fromScripthash(hash) { fromScripthash(hash) {
const type = Address.types.SCRIPTHASH; const type = Address.types.SCRIPTHASH;
assert(hash && hash.length === 20, 'P2SH must be 20 bytes.'); assert(hash && hash.length === 20, 'P2SH must be 20 bytes.');
return this.fromHash(hash, type, -1); return this.fromHash(hash, type, -1);
}; }
/** /**
* Instantiate address from scripthash. * Instantiate address from scripthash.
@ -669,9 +651,9 @@ Address.prototype.fromScripthash = function fromScripthash(hash) {
* @returns {Address} * @returns {Address}
*/ */
Address.fromScripthash = function fromScripthash(hash) { static fromScripthash(hash) {
return new Address().fromScripthash(hash); return new this().fromScripthash(hash);
}; }
/** /**
* Inject properties from witness pubkeyhash. * Inject properties from witness pubkeyhash.
@ -680,11 +662,11 @@ Address.fromScripthash = function fromScripthash(hash) {
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash) { fromWitnessPubkeyhash(hash) {
const type = Address.types.WITNESS; const type = Address.types.WITNESS;
assert(hash && hash.length === 20, 'P2WPKH must be 20 bytes.'); assert(hash && hash.length === 20, 'P2WPKH must be 20 bytes.');
return this.fromHash(hash, type, 0); return this.fromHash(hash, type, 0);
}; }
/** /**
* Instantiate address from witness pubkeyhash. * Instantiate address from witness pubkeyhash.
@ -692,9 +674,9 @@ Address.prototype.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash) {
* @returns {Address} * @returns {Address}
*/ */
Address.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash) { static fromWitnessPubkeyhash(hash) {
return new Address().fromWitnessPubkeyhash(hash); return new this().fromWitnessPubkeyhash(hash);
}; }
/** /**
* Inject properties from witness scripthash. * Inject properties from witness scripthash.
@ -703,11 +685,11 @@ Address.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash) {
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromWitnessScripthash = function fromWitnessScripthash(hash) { fromWitnessScripthash(hash) {
const type = Address.types.WITNESS; const type = Address.types.WITNESS;
assert(hash && hash.length === 32, 'P2WPKH must be 32 bytes.'); assert(hash && hash.length === 32, 'P2WPKH must be 32 bytes.');
return this.fromHash(hash, type, 0); return this.fromHash(hash, type, 0);
}; }
/** /**
* Instantiate address from witness scripthash. * Instantiate address from witness scripthash.
@ -715,9 +697,9 @@ Address.prototype.fromWitnessScripthash = function fromWitnessScripthash(hash) {
* @returns {Address} * @returns {Address}
*/ */
Address.fromWitnessScripthash = function fromWitnessScripthash(hash) { static fromWitnessScripthash(hash) {
return new Address().fromWitnessScripthash(hash); return new this().fromWitnessScripthash(hash);
}; }
/** /**
* Inject properties from witness program. * Inject properties from witness program.
@ -727,7 +709,7 @@ Address.fromWitnessScripthash = function fromWitnessScripthash(hash) {
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromProgram = function fromProgram(version, hash) { fromProgram(version, hash) {
const type = Address.types.WITNESS; const type = Address.types.WITNESS;
assert(version >= 0, 'Bad version for witness program.'); assert(version >= 0, 'Bad version for witness program.');
@ -736,7 +718,7 @@ Address.prototype.fromProgram = function fromProgram(version, hash) {
hash = Buffer.from(hash, 'hex'); hash = Buffer.from(hash, 'hex');
return this.fromHash(hash, type, version); return this.fromHash(hash, type, version);
}; }
/** /**
* Instantiate address from witness program. * Instantiate address from witness program.
@ -745,70 +727,70 @@ Address.prototype.fromProgram = function fromProgram(version, hash) {
* @returns {Address} * @returns {Address}
*/ */
Address.fromProgram = function fromProgram(version, hash) { static fromProgram(version, hash) {
return new Address().fromProgram(version, hash); return new this().fromProgram(version, hash);
}; }
/** /**
* Test whether the address is pubkeyhash. * Test whether the address is pubkeyhash.
* @returns {Boolean} * @returns {Boolean}
*/ */
Address.prototype.isPubkeyhash = function isPubkeyhash() { isPubkeyhash() {
return this.type === Address.types.PUBKEYHASH; return this.type === Address.types.PUBKEYHASH;
}; }
/** /**
* Test whether the address is scripthash. * Test whether the address is scripthash.
* @returns {Boolean} * @returns {Boolean}
*/ */
Address.prototype.isScripthash = function isScripthash() { isScripthash() {
return this.type === Address.types.SCRIPTHASH; return this.type === Address.types.SCRIPTHASH;
}; }
/** /**
* Test whether the address is witness pubkeyhash. * Test whether the address is witness pubkeyhash.
* @returns {Boolean} * @returns {Boolean}
*/ */
Address.prototype.isWitnessPubkeyhash = function isWitnessPubkeyhash() { isWitnessPubkeyhash() {
return this.version === 0 && this.hash.length === 20; return this.version === 0 && this.hash.length === 20;
}; }
/** /**
* Test whether the address is witness scripthash. * Test whether the address is witness scripthash.
* @returns {Boolean} * @returns {Boolean}
*/ */
Address.prototype.isWitnessScripthash = function isWitnessScripthash() { isWitnessScripthash() {
return this.version === 0 && this.hash.length === 32; return this.version === 0 && this.hash.length === 32;
}; }
/** /**
* Test whether the address is witness masthash. * Test whether the address is witness masthash.
* @returns {Boolean} * @returns {Boolean}
*/ */
Address.prototype.isWitnessMasthash = function isWitnessMasthash() { isWitnessMasthash() {
return this.version === 1 && this.hash.length === 32; return this.version === 1 && this.hash.length === 32;
}; }
/** /**
* Test whether the address is a witness program. * Test whether the address is a witness program.
* @returns {Boolean} * @returns {Boolean}
*/ */
Address.prototype.isProgram = function isProgram() { isProgram() {
return this.version !== -1; return this.version !== -1;
}; }
/** /**
* Test whether the address is an unknown witness program. * Test whether the address is an unknown witness program.
* @returns {Boolean} * @returns {Boolean}
*/ */
Address.prototype.isUnknown = function isUnknown() { isUnknown() {
if (this.version === -1) if (this.version === -1)
return false; return false;
@ -816,7 +798,7 @@ Address.prototype.isUnknown = function isUnknown() {
return true; return true;
return this.hash.length !== 20 && this.hash.length !== 32; return this.hash.length !== 20 && this.hash.length !== 32;
}; }
/** /**
* Get the hash of a base58 address or address-related object. * Get the hash of a base58 address or address-related object.
@ -826,7 +808,7 @@ Address.prototype.isUnknown = function isUnknown() {
* @returns {Hash} * @returns {Hash}
*/ */
Address.getHash = function getHash(data, enc, network) { static getHash(data, enc, network) {
if (!data) if (!data)
throw new Error('Object is not an address.'); throw new Error('Object is not an address.');
@ -850,7 +832,7 @@ Address.getHash = function getHash(data, enc, network) {
return enc === 'hex' return enc === 'hex'
? hash.toString('hex') ? hash.toString('hex')
: hash; : hash;
}; }
/** /**
* Get an address type for a specified network address prefix. * Get an address type for a specified network address prefix.
@ -859,8 +841,9 @@ Address.getHash = function getHash(data, enc, network) {
* @returns {AddressType} * @returns {AddressType}
*/ */
Address.getType = function getType(prefix, network) { static getType(prefix, network) {
const prefixes = network.addressPrefix; const prefixes = network.addressPrefix;
switch (prefix) { switch (prefix) {
case prefixes.pubkeyhash: case prefixes.pubkeyhash:
return Address.types.PUBKEYHASH; return Address.types.PUBKEYHASH;
@ -872,8 +855,33 @@ Address.getType = function getType(prefix, network) {
default: default:
throw new Error('Unknown address prefix.'); throw new Error('Unknown address prefix.');
} }
}
}
/**
* Address types.
* @enum {Number}
*/
Address.types = {
PUBKEYHASH: 2,
SCRIPTHASH: 3,
WITNESS: 4
}; };
/**
* Address types by value.
* @const {RevMap}
*/
Address.typesByVal = [
null,
null,
'PUBKEYHASH',
'SCRIPTHASH',
'WITNESS'
];
/* /*
* Helpers * Helpers
*/ */

View File

@ -22,18 +22,21 @@ const Headers = require('./headers');
const Network = require('../protocol/network'); const Network = require('../protocol/network');
/** /**
* Block
* Represents a full block. * Represents a full block.
* @alias module:primitives.Block * @alias module:primitives.Block
* @constructor
* @extends AbstractBlock * @extends AbstractBlock
* @param {NakedBlock} options
*/ */
function Block(options) { class Block extends AbstractBlock {
if (!(this instanceof Block)) /**
return new Block(options); * Create a block.
* @constructor
* @param {Object} options
*/
AbstractBlock.call(this); constructor(options) {
super();
this.txs = []; this.txs = [];
@ -45,15 +48,13 @@ function Block(options) {
this.fromOptions(options); this.fromOptions(options);
} }
Object.setPrototypeOf(Block.prototype, AbstractBlock.prototype);
/** /**
* Inject properties from options object. * Inject properties from options object.
* @private * @private
* @param {Object} options * @param {Object} options
*/ */
Block.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
this.parseOptions(options); this.parseOptions(options);
if (options.txs) { if (options.txs) {
@ -63,7 +64,7 @@ Block.prototype.fromOptions = function fromOptions(options) {
this.txs.push(tx); this.txs.push(tx);
} }
} }
}; }
/** /**
* Instantiate block from options. * Instantiate block from options.
@ -71,16 +72,16 @@ Block.prototype.fromOptions = function fromOptions(options) {
* @returns {Block} * @returns {Block}
*/ */
Block.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new Block().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Clear any cached values. * Clear any cached values.
* @param {Boolean?} all - Clear transactions. * @param {Boolean?} all - Clear transactions.
*/ */
Block.prototype.refresh = function refresh(all) { refresh(all) {
this._refresh(); this._refresh();
this._raw = null; this._raw = null;
@ -92,34 +93,34 @@ Block.prototype.refresh = function refresh(all) {
for (const tx of this.txs) for (const tx of this.txs)
tx.refresh(); tx.refresh();
}; }
/** /**
* Serialize the block. Include witnesses if present. * Serialize the block. Include witnesses if present.
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.toRaw = function toRaw() { toRaw() {
return this.frame().data; return this.frame().data;
}; }
/** /**
* Serialize the block, do not include witnesses. * Serialize the block, do not include witnesses.
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.toNormal = function toNormal() { toNormal() {
if (this.hasWitness()) if (this.hasWitness())
return this.frameNormal().data; return this.frameNormal().data;
return this.toRaw(); return this.toRaw();
}; }
/** /**
* Serialize the block. Include witnesses if present. * Serialize the block. Include witnesses if present.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
Block.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
if (this.mutable) if (this.mutable)
return this.writeWitness(bw); return this.writeWitness(bw);
@ -127,20 +128,20 @@ Block.prototype.toWriter = function toWriter(bw) {
bw.writeBytes(raw.data); bw.writeBytes(raw.data);
return bw; return bw;
}; }
/** /**
* Serialize the block, do not include witnesses. * Serialize the block, do not include witnesses.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
Block.prototype.toNormalWriter = function toNormalWriter(bw) { toNormalWriter(bw) {
if (this.hasWitness()) { if (this.hasWitness()) {
this.writeNormal(bw); this.writeNormal(bw);
return bw; return bw;
} }
return this.toWriter(bw); return this.toWriter(bw);
}; }
/** /**
* Get the raw block serialization. * Get the raw block serialization.
@ -149,7 +150,7 @@ Block.prototype.toNormalWriter = function toNormalWriter(bw) {
* @returns {RawBlock} * @returns {RawBlock}
*/ */
Block.prototype.frame = function frame() { frame() {
if (this.mutable) { if (this.mutable) {
assert(!this._raw); assert(!this._raw);
return this.frameWitness(); return this.frameWitness();
@ -170,58 +171,58 @@ Block.prototype.frame = function frame() {
this._witness = raw.witness; this._witness = raw.witness;
return raw; return raw;
}; }
/** /**
* Calculate real size and size of the witness bytes. * Calculate real size and size of the witness bytes.
* @returns {Object} Contains `size` and `witness`. * @returns {Object} Contains `size` and `witness`.
*/ */
Block.prototype.getSizes = function getSizes() { getSizes() {
if (this.mutable) if (this.mutable)
return this.getWitnessSizes(); return this.getWitnessSizes();
return this.frame(); return this.frame();
}; }
/** /**
* Calculate virtual block size. * Calculate virtual block size.
* @returns {Number} Virtual size. * @returns {Number} Virtual size.
*/ */
Block.prototype.getVirtualSize = function getVirtualSize() { getVirtualSize() {
const scale = consensus.WITNESS_SCALE_FACTOR; const scale = consensus.WITNESS_SCALE_FACTOR;
return (this.getWeight() + scale - 1) / scale | 0; return (this.getWeight() + scale - 1) / scale | 0;
}; }
/** /**
* Calculate block weight. * Calculate block weight.
* @returns {Number} weight * @returns {Number} weight
*/ */
Block.prototype.getWeight = function getWeight() { getWeight() {
const raw = this.getSizes(); const raw = this.getSizes();
const base = raw.size - raw.witness; const base = raw.size - raw.witness;
return base * (consensus.WITNESS_SCALE_FACTOR - 1) + raw.size; return base * (consensus.WITNESS_SCALE_FACTOR - 1) + raw.size;
}; }
/** /**
* Get real block size. * Get real block size.
* @returns {Number} size * @returns {Number} size
*/ */
Block.prototype.getSize = function getSize() { getSize() {
return this.getSizes().size; return this.getSizes().size;
}; }
/** /**
* Get base block size (without witness). * Get base block size (without witness).
* @returns {Number} size * @returns {Number} size
*/ */
Block.prototype.getBaseSize = function getBaseSize() { getBaseSize() {
const raw = this.getSizes(); const raw = this.getSizes();
return raw.size - raw.witness; return raw.size - raw.witness;
}; }
/** /**
* Test whether the block contains a * Test whether the block contains a
@ -229,7 +230,7 @@ Block.prototype.getBaseSize = function getBaseSize() {
* @returns {Boolean} * @returns {Boolean}
*/ */
Block.prototype.hasWitness = function hasWitness() { hasWitness() {
if (this._witness !== -1) if (this._witness !== -1)
return this._witness !== 0; return this._witness !== 0;
@ -239,7 +240,7 @@ Block.prototype.hasWitness = function hasWitness() {
} }
return false; return false;
}; }
/** /**
* Test the block's transaction vector against a hash. * Test the block's transaction vector against a hash.
@ -247,9 +248,9 @@ Block.prototype.hasWitness = function hasWitness() {
* @returns {Boolean} * @returns {Boolean}
*/ */
Block.prototype.hasTX = function hasTX(hash) { hasTX(hash) {
return this.indexOf(hash) !== -1; return this.indexOf(hash) !== -1;
}; }
/** /**
* Find the index of a transaction in the block. * Find the index of a transaction in the block.
@ -257,7 +258,7 @@ Block.prototype.hasTX = function hasTX(hash) {
* @returns {Number} index (-1 if not present). * @returns {Number} index (-1 if not present).
*/ */
Block.prototype.indexOf = function indexOf(hash) { indexOf(hash) {
for (let i = 0; i < this.txs.length; i++) { for (let i = 0; i < this.txs.length; i++) {
const tx = this.txs[i]; const tx = this.txs[i];
if (tx.hash('hex') === hash) if (tx.hash('hex') === hash)
@ -265,7 +266,7 @@ Block.prototype.indexOf = function indexOf(hash) {
} }
return -1; return -1;
}; }
/** /**
* Calculate merkle root. Returns null * Calculate merkle root. Returns null
@ -274,7 +275,7 @@ Block.prototype.indexOf = function indexOf(hash) {
* @returns {Hash|null} * @returns {Hash|null}
*/ */
Block.prototype.createMerkleRoot = function createMerkleRoot(enc) { createMerkleRoot(enc) {
const leaves = []; const leaves = [];
for (const tx of this.txs) for (const tx of this.txs)
@ -286,16 +287,16 @@ Block.prototype.createMerkleRoot = function createMerkleRoot(enc) {
return null; return null;
return enc === 'hex' ? root.toString('hex') : root; return enc === 'hex' ? root.toString('hex') : root;
}; }
/** /**
* Create a witness nonce (for mining). * Create a witness nonce (for mining).
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.createWitnessNonce = function createWitnessNonce() { createWitnessNonce() {
return Buffer.from(encoding.ZERO_HASH); return Buffer.from(encoding.ZERO_HASH);
}; }
/** /**
* Calculate commitment hash (the root of the * Calculate commitment hash (the root of the
@ -304,7 +305,7 @@ Block.prototype.createWitnessNonce = function createWitnessNonce() {
* @returns {Hash} * @returns {Hash}
*/ */
Block.prototype.createCommitmentHash = function createCommitmentHash(enc) { createCommitmentHash(enc) {
const nonce = this.getWitnessNonce(); const nonce = this.getWitnessNonce();
const leaves = []; const leaves = [];
@ -327,7 +328,7 @@ Block.prototype.createCommitmentHash = function createCommitmentHash(enc) {
return enc === 'hex' return enc === 'hex'
? hash.toString('hex') ? hash.toString('hex')
: hash; : hash;
}; }
/** /**
* Retrieve the merkle root from the block header. * Retrieve the merkle root from the block header.
@ -335,11 +336,11 @@ Block.prototype.createCommitmentHash = function createCommitmentHash(enc) {
* @returns {Hash} * @returns {Hash}
*/ */
Block.prototype.getMerkleRoot = function getMerkleRoot(enc) { getMerkleRoot(enc) {
if (enc === 'hex') if (enc === 'hex')
return this.merkleRoot; return this.merkleRoot;
return Buffer.from(this.merkleRoot, 'hex'); return Buffer.from(this.merkleRoot, 'hex');
}; }
/** /**
* Retrieve the witness nonce from the * Retrieve the witness nonce from the
@ -347,7 +348,7 @@ Block.prototype.getMerkleRoot = function getMerkleRoot(enc) {
* @returns {Buffer|null} * @returns {Buffer|null}
*/ */
Block.prototype.getWitnessNonce = function getWitnessNonce() { getWitnessNonce() {
if (this.txs.length === 0) if (this.txs.length === 0)
return null; return null;
@ -365,7 +366,7 @@ Block.prototype.getWitnessNonce = function getWitnessNonce() {
return null; return null;
return input.witness.items[0]; return input.witness.items[0];
}; }
/** /**
* Retrieve the commitment hash * Retrieve the commitment hash
@ -374,7 +375,7 @@ Block.prototype.getWitnessNonce = function getWitnessNonce() {
* @returns {Hash|null} * @returns {Hash|null}
*/ */
Block.prototype.getCommitmentHash = function getCommitmentHash(enc) { getCommitmentHash(enc) {
if (this.txs.length === 0) if (this.txs.length === 0)
return null; return null;
@ -395,7 +396,7 @@ Block.prototype.getCommitmentHash = function getCommitmentHash(enc) {
return enc === 'hex' return enc === 'hex'
? hash.toString('hex') ? hash.toString('hex')
: hash; : hash;
}; }
/** /**
* Do non-contextual verification on the block. Including checking the block * Do non-contextual verification on the block. Including checking the block
@ -403,10 +404,10 @@ Block.prototype.getCommitmentHash = function getCommitmentHash(enc) {
* @returns {Boolean} * @returns {Boolean}
*/ */
Block.prototype.verifyBody = function verifyBody() { verifyBody() {
const [valid] = this.checkBody(); const [valid] = this.checkBody();
return valid; return valid;
}; }
/** /**
* Do non-contextual verification on the block. Including checking the block * Do non-contextual verification on the block. Including checking the block
@ -414,7 +415,7 @@ Block.prototype.verifyBody = function verifyBody() {
* @returns {Array} [valid, reason, score] * @returns {Array} [valid, reason, score]
*/ */
Block.prototype.checkBody = function checkBody() { checkBody() {
// Check merkle root. // Check merkle root.
const root = this.createMerkleRoot('hex'); const root = this.createMerkleRoot('hex');
@ -461,14 +462,14 @@ Block.prototype.checkBody = function checkBody() {
} }
return [true, 'valid', 0]; return [true, 'valid', 0];
}; }
/** /**
* Retrieve the coinbase height from the coinbase input script. * Retrieve the coinbase height from the coinbase input script.
* @returns {Number} height (-1 if not present). * @returns {Number} height (-1 if not present).
*/ */
Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() { getCoinbaseHeight() {
if (this.version < 2) if (this.version < 2)
return -1; return -1;
@ -481,18 +482,18 @@ Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
return -1; return -1;
return coinbase.inputs[0].script.getCoinbaseHeight(); return coinbase.inputs[0].script.getCoinbaseHeight();
}; }
/** /**
* Get the "claimed" reward by the coinbase. * Get the "claimed" reward by the coinbase.
* @returns {Amount} claimed * @returns {Amount} claimed
*/ */
Block.prototype.getClaimed = function getClaimed() { getClaimed() {
assert(this.txs.length > 0); assert(this.txs.length > 0);
assert(this.txs[0].isCoinbase()); assert(this.txs[0].isCoinbase());
return this.txs[0].getOutputValue(); return this.txs[0].getOutputValue();
}; }
/** /**
* Get all unique outpoint hashes in the * Get all unique outpoint hashes in the
@ -500,7 +501,7 @@ Block.prototype.getClaimed = function getClaimed() {
* @returns {Hash[]} Outpoint hashes. * @returns {Hash[]} Outpoint hashes.
*/ */
Block.prototype.getPrevout = function getPrevout() { getPrevout() {
const prevout = Object.create(null); const prevout = Object.create(null);
for (let i = 1; i < this.txs.length; i++) { for (let i = 1; i < this.txs.length; i++) {
@ -511,7 +512,7 @@ Block.prototype.getPrevout = function getPrevout() {
} }
return Object.keys(prevout); return Object.keys(prevout);
}; }
/** /**
* Inspect the block and return a more * Inspect the block and return a more
@ -519,9 +520,9 @@ Block.prototype.getPrevout = function getPrevout() {
* @returns {Object} * @returns {Object}
*/ */
Block.prototype.inspect = function inspect() { inspect() {
return this.format(); return this.format();
}; }
/** /**
* Inspect the block and return a more * Inspect the block and return a more
@ -531,7 +532,7 @@ Block.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
Block.prototype.format = function format(view, height) { format(view, height) {
const commitmentHash = this.getCommitmentHash('hex'); const commitmentHash = this.getCommitmentHash('hex');
return { return {
hash: this.rhash(), hash: this.rhash(),
@ -552,7 +553,7 @@ Block.prototype.format = function format(view, height) {
return tx.format(view, null, i); return tx.format(view, null, i);
}) })
}; };
}; }
/** /**
* Convert the block to an object suitable * Convert the block to an object suitable
@ -560,9 +561,9 @@ Block.prototype.format = function format(view, height) {
* @returns {Object} * @returns {Object}
*/ */
Block.prototype.toJSON = function toJSON() { toJSON() {
return this.getJSON(); return this.getJSON();
}; }
/** /**
* Convert the block to an object suitable * Convert the block to an object suitable
@ -576,7 +577,7 @@ Block.prototype.toJSON = function toJSON() {
* @returns {Object} * @returns {Object}
*/ */
Block.prototype.getJSON = function getJSON(network, view, height, depth) { getJSON(network, view, height, depth) {
network = Network.get(network); network = Network.get(network);
return { return {
hash: this.rhash(), hash: this.rhash(),
@ -592,7 +593,7 @@ Block.prototype.getJSON = function getJSON(network, view, height, depth) {
return tx.getJSON(network, view, null, i); return tx.getJSON(network, view, null, i);
}) })
}; };
}; }
/** /**
* Inject properties from json object. * Inject properties from json object.
@ -600,7 +601,7 @@ Block.prototype.getJSON = function getJSON(network, view, height, depth) {
* @param {Object} json * @param {Object} json
*/ */
Block.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
assert(json, 'Block data is required.'); assert(json, 'Block data is required.');
assert(Array.isArray(json.txs)); assert(Array.isArray(json.txs));
@ -610,7 +611,7 @@ Block.prototype.fromJSON = function fromJSON(json) {
this.txs.push(TX.fromJSON(tx)); this.txs.push(TX.fromJSON(tx));
return this; return this;
}; }
/** /**
* Instantiate a block from a jsonified block object. * Instantiate a block from a jsonified block object.
@ -618,9 +619,9 @@ Block.prototype.fromJSON = function fromJSON(json) {
* @returns {Block} * @returns {Block}
*/ */
Block.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new Block().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -628,7 +629,7 @@ Block.fromJSON = function fromJSON(json) {
* @param {Buffer} data * @param {Buffer} data
*/ */
Block.prototype.fromReader = function fromReader(br) { fromReader(br) {
br.start(); br.start();
this.readHead(br); this.readHead(br);
@ -649,7 +650,7 @@ Block.prototype.fromReader = function fromReader(br) {
} }
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -657,9 +658,9 @@ Block.prototype.fromReader = function fromReader(br) {
* @param {Buffer} data * @param {Buffer} data
*/ */
Block.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
return this.fromReader(new BufferReader(data)); return this.fromReader(new BufferReader(data));
}; }
/** /**
* Instantiate a block from a serialized Buffer. * Instantiate a block from a serialized Buffer.
@ -668,9 +669,9 @@ Block.prototype.fromRaw = function fromRaw(data) {
* @returns {Block} * @returns {Block}
*/ */
Block.fromReader = function fromReader(data) { static fromReader(data) {
return new Block().fromReader(data); return new this().fromReader(data);
}; }
/** /**
* Instantiate a block from a serialized Buffer. * Instantiate a block from a serialized Buffer.
@ -679,11 +680,11 @@ Block.fromReader = function fromReader(data) {
* @returns {Block} * @returns {Block}
*/ */
Block.fromRaw = function fromRaw(data, enc) { static fromRaw(data, enc) {
if (typeof data === 'string') if (typeof data === 'string')
data = Buffer.from(data, enc); data = Buffer.from(data, enc);
return new Block().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Convert the Block to a MerkleBlock. * Convert the Block to a MerkleBlock.
@ -693,9 +694,9 @@ Block.fromRaw = function fromRaw(data, enc) {
* @returns {MerkleBlock} * @returns {MerkleBlock}
*/ */
Block.prototype.toMerkle = function toMerkle(filter) { toMerkle(filter) {
return MerkleBlock.fromBlock(this, filter); return MerkleBlock.fromBlock(this, filter);
}; }
/** /**
* Serialze block with or without witness data. * Serialze block with or without witness data.
@ -705,7 +706,7 @@ Block.prototype.toMerkle = function toMerkle(filter) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.writeNormal = function writeNormal(bw) { writeNormal(bw) {
this.writeHead(bw); this.writeHead(bw);
bw.writeVarint(this.txs.length); bw.writeVarint(this.txs.length);
@ -714,7 +715,7 @@ Block.prototype.writeNormal = function writeNormal(bw) {
tx.toNormalWriter(bw); tx.toNormalWriter(bw);
return bw; return bw;
}; }
/** /**
* Serialze block with or without witness data. * Serialze block with or without witness data.
@ -724,7 +725,7 @@ Block.prototype.writeNormal = function writeNormal(bw) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.writeWitness = function writeWitness(bw) { writeWitness(bw) {
this.writeHead(bw); this.writeHead(bw);
bw.writeVarint(this.txs.length); bw.writeVarint(this.txs.length);
@ -733,7 +734,7 @@ Block.prototype.writeWitness = function writeWitness(bw) {
tx.toWriter(bw); tx.toWriter(bw);
return bw; return bw;
}; }
/** /**
* Serialze block with or without witness data. * Serialze block with or without witness data.
@ -743,13 +744,13 @@ Block.prototype.writeWitness = function writeWitness(bw) {
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.frameNormal = function frameNormal() { frameNormal() {
const raw = this.getNormalSizes(); const raw = this.getNormalSizes();
const bw = new StaticWriter(raw.size); const bw = new StaticWriter(raw.size);
this.writeNormal(bw); this.writeNormal(bw);
raw.data = bw.render(); raw.data = bw.render();
return raw; return raw;
}; }
/** /**
* Serialze block without witness data. * Serialze block without witness data.
@ -758,29 +759,29 @@ Block.prototype.frameNormal = function frameNormal() {
* @returns {Buffer} * @returns {Buffer}
*/ */
Block.prototype.frameWitness = function frameWitness() { frameWitness() {
const raw = this.getWitnessSizes(); const raw = this.getWitnessSizes();
const bw = new StaticWriter(raw.size); const bw = new StaticWriter(raw.size);
this.writeWitness(bw); this.writeWitness(bw);
raw.data = bw.render(); raw.data = bw.render();
return raw; return raw;
}; }
/** /**
* Convert the block to a headers object. * Convert the block to a headers object.
* @returns {Headers} * @returns {Headers}
*/ */
Block.prototype.toHeaders = function toHeaders() { toHeaders() {
return Headers.fromBlock(this); return Headers.fromBlock(this);
}; }
/** /**
* Get real block size without witness. * Get real block size without witness.
* @returns {RawBlock} * @returns {RawBlock}
*/ */
Block.prototype.getNormalSizes = function getNormalSizes() { getNormalSizes() {
let size = 0; let size = 0;
size += 80; size += 80;
@ -790,14 +791,14 @@ Block.prototype.getNormalSizes = function getNormalSizes() {
size += tx.getBaseSize(); size += tx.getBaseSize();
return new RawBlock(size, 0); return new RawBlock(size, 0);
}; }
/** /**
* Get real block size with witness. * Get real block size with witness.
* @returns {RawBlock} * @returns {RawBlock}
*/ */
Block.prototype.getWitnessSizes = function getWitnessSizes() { getWitnessSizes() {
let size = 0; let size = 0;
let witness = 0; let witness = 0;
@ -811,7 +812,7 @@ Block.prototype.getWitnessSizes = function getWitnessSizes() {
} }
return new RawBlock(size, witness); return new RawBlock(size, witness);
}; }
/** /**
* Test whether an object is a Block. * Test whether an object is a Block.
@ -819,19 +820,22 @@ Block.prototype.getWitnessSizes = function getWitnessSizes() {
* @returns {Boolean} * @returns {Boolean}
*/ */
Block.isBlock = function isBlock(obj) { static isBlock(obj) {
return obj instanceof Block; return obj instanceof Block;
}; }
}
/* /*
* Helpers * Helpers
*/ */
function RawBlock(size, witness) { class RawBlock {
constructor(size, witness) {
this.data = null; this.data = null;
this.size = size; this.size = size;
this.witness = witness; this.witness = witness;
} }
}
/* /*
* Expose * Expose

View File

@ -8,38 +8,40 @@
'use strict'; 'use strict';
const assert = require('assert'); const assert = require('assert');
const BufferReader = require('bufio/lib/reader');
const StaticWriter = require('bufio/lib/staticwriter');
const encoding = require('bufio/lib/encoding');
const Amount = require('../btc/amount'); const Amount = require('../btc/amount');
const Output = require('./output'); const Output = require('./output');
const Script = require('../script/script'); const Script = require('../script/script');
const Network = require('../protocol/network'); const Network = require('../protocol/network');
const BufferReader = require('bufio/lib/reader');
const StaticWriter = require('bufio/lib/staticwriter');
const encoding = require('bufio/lib/encoding');
/** /**
* Coin
* Represents an unspent output. * Represents an unspent output.
* @alias module:primitives.Coin * @alias module:primitives.Coin
* @constructor
* @extends Output * @extends Output
* @param {NakedCoin|Coin} options * @property {Number} version
* @property {Number} version - Transaction version. * @property {Number} height
* @property {Number} height - Transaction height (-1 if unconfirmed). * @property {Amount} value
* @property {Amount} value - Output value in satoshis. * @property {Script} script
* @property {Script} script - Output script. * @property {Boolean} coinbase
* @property {Boolean} coinbase - Whether the containing * @property {Hash} hash
* transaction is a coinbase. * @property {Number} index
* @property {Hash} hash - Transaction hash.
* @property {Number} index - Output index.
*/ */
function Coin(options) { class Coin extends Output {
if (!(this instanceof Coin)) /**
return new Coin(options); * Create a coin.
* @constructor
* @param {Object} options
*/
constructor(options) {
super();
this.version = 1; this.version = 1;
this.height = -1; this.height = -1;
this.value = 0;
this.script = new Script();
this.coinbase = false; this.coinbase = false;
this.hash = encoding.NULL_HASH; this.hash = encoding.NULL_HASH;
this.index = 0; this.index = 0;
@ -48,15 +50,13 @@ function Coin(options) {
this.fromOptions(options); this.fromOptions(options);
} }
Object.setPrototypeOf(Coin.prototype, Output.prototype);
/** /**
* Inject options into coin. * Inject options into coin.
* @private * @private
* @param {Object} options * @param {Object} options
*/ */
Coin.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
assert(options, 'Coin data is required.'); assert(options, 'Coin data is required.');
if (options.version != null) { if (options.version != null) {
@ -96,12 +96,13 @@ Coin.prototype.fromOptions = function fromOptions(options) {
} }
if (options.index != null) { if (options.index != null) {
assert((options.index >>> 0) === options.index, 'Index must be a uint32.'); assert((options.index >>> 0) === options.index,
'Index must be a uint32.');
this.index = options.index; this.index = options.index;
} }
return this; return this;
}; }
/** /**
* Instantiate Coin from options object. * Instantiate Coin from options object.
@ -109,9 +110,9 @@ Coin.prototype.fromOptions = function fromOptions(options) {
* @param {Object} options * @param {Object} options
*/ */
Coin.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new Coin().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Clone the coin. * Clone the coin.
@ -119,9 +120,9 @@ Coin.fromOptions = function fromOptions(options) {
* @returns {Coin} * @returns {Coin}
*/ */
Coin.prototype.clone = function clone() { clone() {
assert(false, 'Coins are not cloneable.'); assert(false, 'Coins are not cloneable.');
}; }
/** /**
* Calculate number of confirmations since coin was created. * Calculate number of confirmations since coin was created.
@ -130,7 +131,7 @@ Coin.prototype.clone = function clone() {
* @return {Number} * @return {Number}
*/ */
Coin.prototype.getDepth = function getDepth(height) { getDepth(height) {
assert(typeof height === 'number', 'Must pass a height.'); assert(typeof height === 'number', 'Must pass a height.');
if (this.height === -1) if (this.height === -1)
@ -143,7 +144,7 @@ Coin.prototype.getDepth = function getDepth(height) {
return 0; return 0;
return height - this.height + 1; return height - this.height + 1;
}; }
/** /**
* Serialize coin to a key * Serialize coin to a key
@ -151,9 +152,9 @@ Coin.prototype.getDepth = function getDepth(height) {
* @returns {String} * @returns {String}
*/ */
Coin.prototype.toKey = function toKey() { toKey() {
return this.hash + this.index; return this.hash + this.index;
}; }
/** /**
* Inject properties from hash table key. * Inject properties from hash table key.
@ -162,12 +163,12 @@ Coin.prototype.toKey = function toKey() {
* @returns {Coin} * @returns {Coin}
*/ */
Coin.prototype.fromKey = function fromKey(key) { fromKey(key) {
assert(key.length > 64); assert(key.length > 64);
this.hash = key.slice(0, 64); this.hash = key.slice(0, 64);
this.index = parseInt(key.slice(64), 10); this.index = parseInt(key.slice(64), 10);
return this; return this;
}; }
/** /**
* Instantiate coin from hash table key. * Instantiate coin from hash table key.
@ -175,34 +176,34 @@ Coin.prototype.fromKey = function fromKey(key) {
* @returns {Coin} * @returns {Coin}
*/ */
Coin.fromKey = function fromKey(key) { static fromKey(key) {
return new Coin().fromKey(key); return new this().fromKey(key);
}; }
/** /**
* Get little-endian hash. * Get little-endian hash.
* @returns {Hash} * @returns {Hash}
*/ */
Coin.prototype.rhash = function rhash() { rhash() {
return encoding.revHex(this.hash); return encoding.revHex(this.hash);
}; }
/** /**
* Get little-endian hash. * Get little-endian hash.
* @returns {Hash} * @returns {Hash}
*/ */
Coin.prototype.txid = function txid() { txid() {
return this.rhash(); return this.rhash();
}; }
/** /**
* Convert the coin to a more user-friendly object. * Convert the coin to a more user-friendly object.
* @returns {Object} * @returns {Object}
*/ */
Coin.prototype.inspect = function inspect() { inspect() {
return { return {
type: this.getType(), type: this.getType(),
version: this.version, version: this.version,
@ -214,7 +215,7 @@ Coin.prototype.inspect = function inspect() {
index: this.index, index: this.index,
address: this.getAddress() address: this.getAddress()
}; };
}; }
/** /**
* Convert the coin to an object suitable * Convert the coin to an object suitable
@ -222,9 +223,9 @@ Coin.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
Coin.prototype.toJSON = function toJSON() { toJSON() {
return this.getJSON(); return this.getJSON();
}; }
/** /**
* Convert the coin to an object suitable * Convert the coin to an object suitable
@ -236,7 +237,7 @@ Coin.prototype.toJSON = function toJSON() {
* @returns {Object} * @returns {Object}
*/ */
Coin.prototype.getJSON = function getJSON(network, minimal) { getJSON(network, minimal) {
let addr = this.getAddress(); let addr = this.getAddress();
network = Network.get(network); network = Network.get(network);
@ -254,7 +255,7 @@ Coin.prototype.getJSON = function getJSON(network, minimal) {
hash: !minimal ? this.rhash() : undefined, hash: !minimal ? this.rhash() : undefined,
index: !minimal ? this.index : undefined index: !minimal ? this.index : undefined
}; };
}; }
/** /**
* Inject JSON properties into coin. * Inject JSON properties into coin.
@ -262,7 +263,7 @@ Coin.prototype.getJSON = function getJSON(network, minimal) {
* @param {Object} json * @param {Object} json
*/ */
Coin.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
assert(json, 'Coin data required.'); assert(json, 'Coin data required.');
assert((json.version >>> 0) === json.version, 'Version must be a uint32.'); assert((json.version >>> 0) === json.version, 'Version must be a uint32.');
assert(json.height === -1 || (json.height >>> 0) === json.height, assert(json.height === -1 || (json.height >>> 0) === json.height,
@ -286,7 +287,7 @@ Coin.prototype.fromJSON = function fromJSON(json) {
} }
return this; return this;
}; }
/** /**
* Instantiate an Coin from a jsonified coin object. * Instantiate an Coin from a jsonified coin object.
@ -294,25 +295,25 @@ Coin.prototype.fromJSON = function fromJSON(json) {
* @returns {Coin} * @returns {Coin}
*/ */
Coin.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new Coin().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Calculate size of coin. * Calculate size of coin.
* @returns {Number} * @returns {Number}
*/ */
Coin.prototype.getSize = function getSize() { getSize() {
return 17 + this.script.getVarSize(); return 17 + this.script.getVarSize();
}; }
/** /**
* Write the coin to a buffer writer. * Write the coin to a buffer writer.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
Coin.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
let height = this.height; let height = this.height;
if (height === -1) if (height === -1)
@ -325,17 +326,17 @@ Coin.prototype.toWriter = function toWriter(bw) {
bw.writeU8(this.coinbase ? 1 : 0); bw.writeU8(this.coinbase ? 1 : 0);
return bw; return bw;
}; }
/** /**
* Serialize the coin. * Serialize the coin.
* @returns {Buffer|String} * @returns {Buffer|String}
*/ */
Coin.prototype.toRaw = function toRaw() { toRaw() {
const size = this.getSize(); const size = this.getSize();
return this.toWriter(new StaticWriter(size)).render(); return this.toWriter(new StaticWriter(size)).render();
}; }
/** /**
* Inject properties from serialized buffer writer. * Inject properties from serialized buffer writer.
@ -343,7 +344,7 @@ Coin.prototype.toRaw = function toRaw() {
* @param {BufferReader} br * @param {BufferReader} br
*/ */
Coin.prototype.fromReader = function fromReader(br) { fromReader(br) {
this.version = br.readU32(); this.version = br.readU32();
this.height = br.readU32(); this.height = br.readU32();
this.value = br.readI64(); this.value = br.readI64();
@ -354,7 +355,7 @@ Coin.prototype.fromReader = function fromReader(br) {
this.height = -1; this.height = -1;
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -362,9 +363,9 @@ Coin.prototype.fromReader = function fromReader(br) {
* @param {Buffer} data * @param {Buffer} data
*/ */
Coin.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
return this.fromReader(new BufferReader(data)); return this.fromReader(new BufferReader(data));
}; }
/** /**
* Instantiate a coin from a buffer reader. * Instantiate a coin from a buffer reader.
@ -372,9 +373,9 @@ Coin.prototype.fromRaw = function fromRaw(data) {
* @returns {Coin} * @returns {Coin}
*/ */
Coin.fromReader = function fromReader(br) { static fromReader(br) {
return new Coin().fromReader(br); return new this().fromReader(br);
}; }
/** /**
* Instantiate a coin from a serialized Buffer. * Instantiate a coin from a serialized Buffer.
@ -383,11 +384,11 @@ Coin.fromReader = function fromReader(br) {
* @returns {Coin} * @returns {Coin}
*/ */
Coin.fromRaw = function fromRaw(data, enc) { static fromRaw(data, enc) {
if (typeof data === 'string') if (typeof data === 'string')
data = Buffer.from(data, enc); data = Buffer.from(data, enc);
return new Coin().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Inject properties from TX. * Inject properties from TX.
@ -395,7 +396,7 @@ Coin.fromRaw = function fromRaw(data, enc) {
* @param {Number} index * @param {Number} index
*/ */
Coin.prototype.fromTX = function fromTX(tx, index, height) { fromTX(tx, index, height) {
assert(typeof index === 'number'); assert(typeof index === 'number');
assert(typeof height === 'number'); assert(typeof height === 'number');
assert(index >= 0 && index < tx.outputs.length); assert(index >= 0 && index < tx.outputs.length);
@ -407,7 +408,7 @@ Coin.prototype.fromTX = function fromTX(tx, index, height) {
this.hash = tx.hash('hex'); this.hash = tx.hash('hex');
this.index = index; this.index = index;
return this; return this;
}; }
/** /**
* Instantiate a coin from a TX * Instantiate a coin from a TX
@ -416,9 +417,9 @@ Coin.prototype.fromTX = function fromTX(tx, index, height) {
* @returns {Coin} * @returns {Coin}
*/ */
Coin.fromTX = function fromTX(tx, index, height) { static fromTX(tx, index, height) {
return new Coin().fromTX(tx, index, height); return new this().fromTX(tx, index, height);
}; }
/** /**
* Test an object to see if it is a Coin. * Test an object to see if it is a Coin.
@ -426,9 +427,10 @@ Coin.fromTX = function fromTX(tx, index, height) {
* @returns {Boolean} * @returns {Boolean}
*/ */
Coin.isCoin = function isCoin(obj) { static isCoin(obj) {
return obj instanceof Coin; return obj instanceof Coin;
}; }
}
/* /*
* Expose * Expose

View File

@ -14,65 +14,66 @@ const BufferReader = require('bufio/lib/reader');
const encoding = require('bufio/lib/encoding'); const encoding = require('bufio/lib/encoding');
/** /**
* Represents block headers obtained from the network via `headers`. * Headers
* Represents block headers obtained
* from the network via `headers`.
* @alias module:primitives.Headers * @alias module:primitives.Headers
* @constructor
* @extends AbstractBlock * @extends AbstractBlock
* @param {NakedBlock} options
*/ */
function Headers(options) { class Headers extends AbstractBlock {
if (!(this instanceof Headers)) /**
return new Headers(options); * Create headers.
* @constructor
* @param {Object} options
*/
AbstractBlock.call(this); constructor(options) {
super();
if (options) if (options)
this.parseOptions(options); this.parseOptions(options);
} }
Object.setPrototypeOf(Headers.prototype, AbstractBlock.prototype);
/** /**
* Do non-contextual verification on the headers. * Perform non-contextual
* @param {Object?} ret - Return object, may be * verification on the headers.
* set with properties `reason` and `score`.
* @returns {Boolean} * @returns {Boolean}
*/ */
Headers.prototype.verifyBody = function verifyBody(ret) { verifyBody() {
return true; return true;
}; }
/** /**
* Get size of the headers. * Get size of the headers.
* @returns {Number} * @returns {Number}
*/ */
Headers.prototype.getSize = function getSize() { getSize() {
return 81; return 81;
}; }
/** /**
* Serialize the headers to a buffer writer. * Serialize the headers to a buffer writer.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
Headers.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
this.writeHead(bw); this.writeHead(bw);
bw.writeVarint(0); bw.writeVarint(0);
return bw; return bw;
}; }
/** /**
* Serialize the headers. * Serialize the headers.
* @returns {Buffer|String} * @returns {Buffer|String}
*/ */
Headers.prototype.toRaw = function toRaw() { toRaw() {
const size = this.getSize(); const size = this.getSize();
return this.toWriter(new StaticWriter(size)).render(); return this.toWriter(new StaticWriter(size)).render();
}; }
/** /**
* Inject properties from buffer reader. * Inject properties from buffer reader.
@ -80,11 +81,11 @@ Headers.prototype.toRaw = function toRaw() {
* @param {Buffer} data * @param {Buffer} data
*/ */
Headers.prototype.fromReader = function fromReader(br) { fromReader(br) {
this.readHead(br); this.readHead(br);
br.readVarint(); br.readVarint();
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -92,9 +93,9 @@ Headers.prototype.fromReader = function fromReader(br) {
* @param {Buffer} data * @param {Buffer} data
*/ */
Headers.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
return this.fromReader(new BufferReader(data)); return this.fromReader(new BufferReader(data));
}; }
/** /**
* Instantiate headers from buffer reader. * Instantiate headers from buffer reader.
@ -102,9 +103,9 @@ Headers.prototype.fromRaw = function fromRaw(data) {
* @returns {Headers} * @returns {Headers}
*/ */
Headers.fromReader = function fromReader(br) { static fromReader(br) {
return new Headers().fromReader(br); return new this().fromReader(br);
}; }
/** /**
* Instantiate headers from serialized data. * Instantiate headers from serialized data.
@ -113,11 +114,11 @@ Headers.fromReader = function fromReader(br) {
* @returns {Headers} * @returns {Headers}
*/ */
Headers.fromRaw = function fromRaw(data, enc) { static fromRaw(data, enc) {
if (typeof data === 'string') if (typeof data === 'string')
data = Buffer.from(data, enc); data = Buffer.from(data, enc);
return new Headers().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Instantiate headers from serialized data. * Instantiate headers from serialized data.
@ -126,11 +127,11 @@ Headers.fromRaw = function fromRaw(data, enc) {
* @returns {Headers} * @returns {Headers}
*/ */
Headers.fromHead = function fromHead(data, enc) { static fromHead(data, enc) {
if (typeof data === 'string') if (typeof data === 'string')
data = Buffer.from(data, enc); data = Buffer.from(data, enc);
return new Headers().fromHead(data); return new this().fromHead(data);
}; }
/** /**
* Instantiate headers from a chain entry. * Instantiate headers from a chain entry.
@ -138,8 +139,8 @@ Headers.fromHead = function fromHead(data, enc) {
* @returns {Headers} * @returns {Headers}
*/ */
Headers.fromEntry = function fromEntry(entry) { static fromEntry(entry) {
const headers = new Headers(); const headers = new this();
headers.version = entry.version; headers.version = entry.version;
headers.prevBlock = entry.prevBlock; headers.prevBlock = entry.prevBlock;
headers.merkleRoot = entry.merkleRoot; headers.merkleRoot = entry.merkleRoot;
@ -149,16 +150,16 @@ Headers.fromEntry = function fromEntry(entry) {
headers._hash = Buffer.from(entry.hash, 'hex'); headers._hash = Buffer.from(entry.hash, 'hex');
headers._hhash = entry.hash; headers._hhash = entry.hash;
return headers; return headers;
}; }
/** /**
* Convert the block to a headers object. * Convert the block to a headers object.
* @returns {Headers} * @returns {Headers}
*/ */
Headers.prototype.toHeaders = function toHeaders() { toHeaders() {
return this; return this;
}; }
/** /**
* Convert the block to a headers object. * Convert the block to a headers object.
@ -166,12 +167,12 @@ Headers.prototype.toHeaders = function toHeaders() {
* @returns {Headers} * @returns {Headers}
*/ */
Headers.fromBlock = function fromBlock(block) { static fromBlock(block) {
const headers = new Headers(block); const headers = new this(block);
headers._hash = block._hash; headers._hash = block._hash;
headers._hhash = block._hhash; headers._hhash = block._hhash;
return headers; return headers;
}; }
/** /**
* Convert the block to an object suitable * Convert the block to an object suitable
@ -179,9 +180,9 @@ Headers.fromBlock = function fromBlock(block) {
* @returns {Object} * @returns {Object}
*/ */
Headers.prototype.toJSON = function toJSON() { toJSON() {
return this.getJSON(); return this.getJSON();
}; }
/** /**
* Convert the block to an object suitable * Convert the block to an object suitable
@ -194,7 +195,7 @@ Headers.prototype.toJSON = function toJSON() {
* @returns {Object} * @returns {Object}
*/ */
Headers.prototype.getJSON = function getJSON(network, view, height) { getJSON(network, view, height) {
return { return {
hash: this.rhash(), hash: this.rhash(),
height: height, height: height,
@ -205,7 +206,7 @@ Headers.prototype.getJSON = function getJSON(network, view, height) {
bits: this.bits, bits: this.bits,
nonce: this.nonce nonce: this.nonce
}; };
}; }
/** /**
* Inject properties from json object. * Inject properties from json object.
@ -213,10 +214,10 @@ Headers.prototype.getJSON = function getJSON(network, view, height) {
* @param {Object} json * @param {Object} json
*/ */
Headers.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
this.parseJSON(json); this.parseJSON(json);
return this; return this;
}; }
/** /**
* Instantiate a merkle block from a jsonified block object. * Instantiate a merkle block from a jsonified block object.
@ -224,9 +225,9 @@ Headers.prototype.fromJSON = function fromJSON(json) {
* @returns {Headers} * @returns {Headers}
*/ */
Headers.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new Headers().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Inspect the headers and return a more * Inspect the headers and return a more
@ -234,9 +235,9 @@ Headers.fromJSON = function fromJSON(json) {
* @returns {Object} * @returns {Object}
*/ */
Headers.prototype.inspect = function inspect() { inspect() {
return this.format(); return this.format();
}; }
/** /**
* Inspect the headers and return a more * Inspect the headers and return a more
@ -246,7 +247,7 @@ Headers.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
Headers.prototype.format = function format(view, height) { format(view, height) {
return { return {
hash: this.rhash(), hash: this.rhash(),
height: height != null ? height : -1, height: height != null ? height : -1,
@ -258,7 +259,7 @@ Headers.prototype.format = function format(view, height) {
bits: this.bits, bits: this.bits,
nonce: this.nonce nonce: this.nonce
}; };
}; }
/** /**
* Test an object to see if it is a Headers object. * Test an object to see if it is a Headers object.
@ -266,9 +267,10 @@ Headers.prototype.format = function format(view, height) {
* @returns {Boolean} * @returns {Boolean}
*/ */
Headers.isHeaders = function isHeaders(obj) { static isHeaders(obj) {
return obj instanceof Headers; return obj instanceof Headers;
}; }
}
/* /*
* Expose * Expose

View File

@ -16,20 +16,23 @@ const StaticWriter = require('bufio/lib/staticwriter');
const BufferReader = require('bufio/lib/reader'); const BufferReader = require('bufio/lib/reader');
/** /**
* Input
* Represents a transaction input. * Represents a transaction input.
* @alias module:primitives.Input * @alias module:primitives.Input
* @constructor
* @param {NakedInput} options
* @property {Outpoint} prevout - Outpoint. * @property {Outpoint} prevout - Outpoint.
* @property {Script} script - Input script / scriptSig. * @property {Script} script - Input script / scriptSig.
* @property {Number} sequence - nSequence. * @property {Number} sequence - nSequence.
* @property {Witness} witness - Witness (empty if not present). * @property {Witness} witness - Witness (empty if not present).
*/ */
function Input(options) { class Input {
if (!(this instanceof Input)) /**
return new Input(options); * Create transaction input.
* @constructor
* @param {Object} options
*/
constructor(options) {
this.prevout = new Outpoint(); this.prevout = new Outpoint();
this.script = new Script(); this.script = new Script();
this.sequence = 0xffffffff; this.sequence = 0xffffffff;
@ -45,7 +48,7 @@ function Input(options) {
* @param {Object} options * @param {Object} options
*/ */
Input.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
assert(options, 'Input data is required.'); assert(options, 'Input data is required.');
this.prevout.fromOptions(options.prevout); this.prevout.fromOptions(options.prevout);
@ -63,7 +66,7 @@ Input.prototype.fromOptions = function fromOptions(options) {
this.witness.fromOptions(options.witness); this.witness.fromOptions(options.witness);
return this; return this;
}; }
/** /**
* Instantiate an Input from options object. * Instantiate an Input from options object.
@ -71,23 +74,23 @@ Input.prototype.fromOptions = function fromOptions(options) {
* @returns {Input} * @returns {Input}
*/ */
Input.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new Input().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Clone the input. * Clone the input.
* @returns {Input} * @returns {Input}
*/ */
Input.prototype.clone = function clone() { clone() {
const input = new Input(); const input = new this.constructor();
input.prevout = this.prevout; input.prevout = this.prevout;
input.script.inject(this.script); input.script.inject(this.script);
input.sequence = this.sequence; input.sequence = this.sequence;
input.witness.inject(this.witness); input.witness.inject(this.witness);
return input; return input;
}; }
/** /**
* Test equality against another input. * Test equality against another input.
@ -95,10 +98,10 @@ Input.prototype.clone = function clone() {
* @returns {Boolean} * @returns {Boolean}
*/ */
Input.prototype.equals = function equals(input) { equals(input) {
assert(Input.isInput(input)); assert(Input.isInput(input));
return this.prevout.equals(input.prevout); return this.prevout.equals(input.prevout);
}; }
/** /**
* Compare against another input (BIP69). * Compare against another input (BIP69).
@ -106,10 +109,10 @@ Input.prototype.equals = function equals(input) {
* @returns {Number} * @returns {Number}
*/ */
Input.prototype.compare = function compare(input) { compare(input) {
assert(Input.isInput(input)); assert(Input.isInput(input));
return this.prevout.compare(input.prevout); return this.prevout.compare(input.prevout);
}; }
/** /**
* Get the previous output script type as a string. * Get the previous output script type as a string.
@ -119,7 +122,7 @@ Input.prototype.compare = function compare(input) {
* @returns {ScriptType} type * @returns {ScriptType} type
*/ */
Input.prototype.getType = function getType(coin) { getType(coin) {
if (this.isCoinbase()) if (this.isCoinbase())
return 'coinbase'; return 'coinbase';
@ -134,7 +137,7 @@ Input.prototype.getType = function getType(coin) {
type = this.script.getInputType(); type = this.script.getInputType();
return Script.typesByVal[type].toLowerCase(); return Script.typesByVal[type].toLowerCase();
}; }
/** /**
* Get the redeem script. Will attempt to resolve nested * Get the redeem script. Will attempt to resolve nested
@ -143,7 +146,7 @@ Input.prototype.getType = function getType(coin) {
* @returns {Script?} Redeem script. * @returns {Script?} Redeem script.
*/ */
Input.prototype.getRedeem = function getRedeem(coin) { getRedeem(coin) {
if (this.isCoinbase()) if (this.isCoinbase())
return null; return null;
@ -171,7 +174,7 @@ Input.prototype.getRedeem = function getRedeem(coin) {
} }
return redeem; return redeem;
}; }
/** /**
* Get the redeem script type. * Get the redeem script type.
@ -179,7 +182,7 @@ Input.prototype.getRedeem = function getRedeem(coin) {
* @returns {String} subtype * @returns {String} subtype
*/ */
Input.prototype.getSubtype = function getSubtype(coin) { getSubtype(coin) {
if (this.isCoinbase()) if (this.isCoinbase())
return null; return null;
@ -191,7 +194,7 @@ Input.prototype.getSubtype = function getSubtype(coin) {
const type = redeem.getType(); const type = redeem.getType();
return Script.typesByVal[type].toLowerCase(); return Script.typesByVal[type].toLowerCase();
}; }
/** /**
* Get the previous output script's address. Will "guess" * Get the previous output script's address. Will "guess"
@ -201,7 +204,7 @@ Input.prototype.getSubtype = function getSubtype(coin) {
* @returns {Address?} addr * @returns {Address?} addr
*/ */
Input.prototype.getAddress = function getAddress(coin) { getAddress(coin) {
if (this.isCoinbase()) if (this.isCoinbase())
return null; return null;
@ -212,7 +215,7 @@ Input.prototype.getAddress = function getAddress(coin) {
return this.witness.getInputAddress(); return this.witness.getInputAddress();
return this.script.getInputAddress(); return this.script.getInputAddress();
}; }
/** /**
* Get the address hash. * Get the address hash.
@ -220,50 +223,50 @@ Input.prototype.getAddress = function getAddress(coin) {
* @returns {Hash} hash * @returns {Hash} hash
*/ */
Input.prototype.getHash = function getHash(enc) { getHash(enc) {
const addr = this.getAddress(); const addr = this.getAddress();
if (!addr) if (!addr)
return null; return null;
return addr.getHash(enc); return addr.getHash(enc);
}; }
/** /**
* Test to see if nSequence is equal to uint32max. * Test to see if nSequence is equal to uint32max.
* @returns {Boolean} * @returns {Boolean}
*/ */
Input.prototype.isFinal = function isFinal() { isFinal() {
return this.sequence === 0xffffffff; return this.sequence === 0xffffffff;
}; }
/** /**
* Test to see if nSequence is less than 0xfffffffe. * Test to see if nSequence is less than 0xfffffffe.
* @returns {Boolean} * @returns {Boolean}
*/ */
Input.prototype.isRBF = function isRBF() { isRBF() {
return this.sequence < 0xfffffffe; return this.sequence < 0xfffffffe;
}; }
/** /**
* Test to see if outpoint is null. * Test to see if outpoint is null.
* @returns {Boolean} * @returns {Boolean}
*/ */
Input.prototype.isCoinbase = function isCoinbase() { isCoinbase() {
return this.prevout.isNull(); return this.prevout.isNull();
}; }
/** /**
* Convert the input to a more user-friendly object. * Convert the input to a more user-friendly object.
* @returns {Object} * @returns {Object}
*/ */
Input.prototype.inspect = function inspect() { inspect() {
return this.format(); return this.format();
}; }
/** /**
* Convert the input to a more user-friendly object. * Convert the input to a more user-friendly object.
@ -271,7 +274,7 @@ Input.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
Input.prototype.format = function format(coin) { format(coin) {
return { return {
type: this.getType(coin), type: this.getType(coin),
subtype: this.getSubtype(coin), subtype: this.getSubtype(coin),
@ -283,7 +286,7 @@ Input.prototype.format = function format(coin) {
prevout: this.prevout, prevout: this.prevout,
coin: coin || null coin: coin || null
}; };
}; }
/** /**
* Convert the input to an object suitable * Convert the input to an object suitable
@ -291,9 +294,9 @@ Input.prototype.format = function format(coin) {
* @returns {Object} * @returns {Object}
*/ */
Input.prototype.toJSON = function toJSON(network, coin) { toJSON(network, coin) {
return this.getJSON(); return this.getJSON();
}; }
/** /**
* Convert the input to an object suitable * Convert the input to an object suitable
@ -305,7 +308,7 @@ Input.prototype.toJSON = function toJSON(network, coin) {
* @returns {Object} * @returns {Object}
*/ */
Input.prototype.getJSON = function getJSON(network, coin) { getJSON(network, coin) {
network = Network.get(network); network = Network.get(network);
let addr; let addr;
@ -323,7 +326,7 @@ Input.prototype.getJSON = function getJSON(network, coin) {
address: addr, address: addr,
coin: coin ? coin.getJSON(network, true) : undefined coin: coin ? coin.getJSON(network, true) : undefined
}; };
}; }
/** /**
* Inject properties from a JSON object. * Inject properties from a JSON object.
@ -331,15 +334,16 @@ Input.prototype.getJSON = function getJSON(network, coin) {
* @param {Object} json * @param {Object} json
*/ */
Input.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
assert(json, 'Input data is required.'); assert(json, 'Input data is required.');
assert((json.sequence >>> 0) === json.sequence, 'Sequence must be a uint32.'); assert((json.sequence >>> 0) === json.sequence,
'Sequence must be a uint32.');
this.prevout.fromJSON(json.prevout); this.prevout.fromJSON(json.prevout);
this.script.fromJSON(json.script); this.script.fromJSON(json.script);
this.witness.fromJSON(json.witness); this.witness.fromJSON(json.witness);
this.sequence = json.sequence; this.sequence = json.sequence;
return this; return this;
}; }
/** /**
* Instantiate an Input from a jsonified input object. * Instantiate an Input from a jsonified input object.
@ -347,18 +351,18 @@ Input.prototype.fromJSON = function fromJSON(json) {
* @returns {Input} * @returns {Input}
*/ */
Input.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new Input().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Calculate size of serialized input. * Calculate size of serialized input.
* @returns {Number} * @returns {Number}
*/ */
Input.prototype.getSize = function getSize() { getSize() {
return 40 + this.script.getVarSize(); return 40 + this.script.getVarSize();
}; }
/** /**
* Serialize the input. * Serialize the input.
@ -366,22 +370,22 @@ Input.prototype.getSize = function getSize() {
* @returns {Buffer|String} * @returns {Buffer|String}
*/ */
Input.prototype.toRaw = function toRaw() { toRaw() {
const size = this.getSize(); const size = this.getSize();
return this.toWriter(new StaticWriter(size)).render(); return this.toWriter(new StaticWriter(size)).render();
}; }
/** /**
* Write the input to a buffer writer. * Write the input to a buffer writer.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
Input.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
this.prevout.toWriter(bw); this.prevout.toWriter(bw);
bw.writeVarBytes(this.script.toRaw()); bw.writeVarBytes(this.script.toRaw());
bw.writeU32(this.sequence); bw.writeU32(this.sequence);
return bw; return bw;
}; }
/** /**
* Inject properties from buffer reader. * Inject properties from buffer reader.
@ -389,21 +393,21 @@ Input.prototype.toWriter = function toWriter(bw) {
* @param {BufferReader} br * @param {BufferReader} br
*/ */
Input.prototype.fromReader = function fromReader(br) { fromReader(br) {
this.prevout.fromReader(br); this.prevout.fromReader(br);
this.script.fromRaw(br.readVarBytes()); this.script.fromRaw(br.readVarBytes());
this.sequence = br.readU32(); this.sequence = br.readU32();
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
* @param {Buffer} data * @param {Buffer} data
*/ */
Input.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
return this.fromReader(new BufferReader(data)); return this.fromReader(new BufferReader(data));
}; }
/** /**
* Instantiate an input from a buffer reader. * Instantiate an input from a buffer reader.
@ -411,9 +415,9 @@ Input.prototype.fromRaw = function fromRaw(data) {
* @returns {Input} * @returns {Input}
*/ */
Input.fromReader = function fromReader(br) { static fromReader(br) {
return new Input().fromReader(br); return new this().fromReader(br);
}; }
/** /**
* Instantiate an input from a serialized Buffer. * Instantiate an input from a serialized Buffer.
@ -422,11 +426,11 @@ Input.fromReader = function fromReader(br) {
* @returns {Input} * @returns {Input}
*/ */
Input.fromRaw = function fromRaw(data, enc) { static fromRaw(data, enc) {
if (typeof data === 'string') if (typeof data === 'string')
data = Buffer.from(data, enc); data = Buffer.from(data, enc);
return new Input().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Inject properties from outpoint. * Inject properties from outpoint.
@ -434,13 +438,13 @@ Input.fromRaw = function fromRaw(data, enc) {
* @param {Outpoint} outpoint * @param {Outpoint} outpoint
*/ */
Input.prototype.fromOutpoint = function fromOutpoint(outpoint) { fromOutpoint(outpoint) {
assert(typeof outpoint.hash === 'string'); assert(typeof outpoint.hash === 'string');
assert(typeof outpoint.index === 'number'); assert(typeof outpoint.index === 'number');
this.prevout.hash = outpoint.hash; this.prevout.hash = outpoint.hash;
this.prevout.index = outpoint.index; this.prevout.index = outpoint.index;
return this; return this;
}; }
/** /**
* Instantiate input from outpoint. * Instantiate input from outpoint.
@ -448,9 +452,9 @@ Input.prototype.fromOutpoint = function fromOutpoint(outpoint) {
* @returns {Input} * @returns {Input}
*/ */
Input.fromOutpoint = function fromOutpoint(outpoint) { static fromOutpoint(outpoint) {
return new Input().fromOutpoint(outpoint); return new this().fromOutpoint(outpoint);
}; }
/** /**
* Inject properties from coin. * Inject properties from coin.
@ -458,13 +462,13 @@ Input.fromOutpoint = function fromOutpoint(outpoint) {
* @param {Coin} coin * @param {Coin} coin
*/ */
Input.prototype.fromCoin = function fromCoin(coin) { fromCoin(coin) {
assert(typeof coin.hash === 'string'); assert(typeof coin.hash === 'string');
assert(typeof coin.index === 'number'); assert(typeof coin.index === 'number');
this.prevout.hash = coin.hash; this.prevout.hash = coin.hash;
this.prevout.index = coin.index; this.prevout.index = coin.index;
return this; return this;
}; }
/** /**
* Instantiate input from coin. * Instantiate input from coin.
@ -472,9 +476,9 @@ Input.prototype.fromCoin = function fromCoin(coin) {
* @returns {Input} * @returns {Input}
*/ */
Input.fromCoin = function fromCoin(coin) { static fromCoin(coin) {
return new Input().fromCoin(coin); return new this().fromCoin(coin);
}; }
/** /**
* Inject properties from transaction. * Inject properties from transaction.
@ -483,14 +487,14 @@ Input.fromCoin = function fromCoin(coin) {
* @param {Number} index * @param {Number} index
*/ */
Input.prototype.fromTX = function fromTX(tx, index) { fromTX(tx, index) {
assert(tx); assert(tx);
assert(typeof index === 'number'); assert(typeof index === 'number');
assert(index >= 0 && index < tx.outputs.length); assert(index >= 0 && index < tx.outputs.length);
this.prevout.hash = tx.hash('hex'); this.prevout.hash = tx.hash('hex');
this.prevout.index = index; this.prevout.index = index;
return this; return this;
}; }
/** /**
* Instantiate input from tx. * Instantiate input from tx.
@ -499,9 +503,9 @@ Input.prototype.fromTX = function fromTX(tx, index) {
* @returns {Input} * @returns {Input}
*/ */
Input.fromTX = function fromTX(tx, index) { static fromTX(tx, index) {
return new Input().fromTX(tx, index); return new this().fromTX(tx, index);
}; }
/** /**
* Test an object to see if it is an Input. * Test an object to see if it is an Input.
@ -509,9 +513,10 @@ Input.fromTX = function fromTX(tx, index) {
* @returns {Boolean} * @returns {Boolean}
*/ */
Input.isInput = function isInput(obj) { static isInput(obj) {
return obj instanceof Input; return obj instanceof Input;
}; }
}
/* /*
* Expose * Expose

View File

@ -15,20 +15,148 @@ const encoding = require('bufio/lib/encoding');
* Inv Item * Inv Item
* @alias module:primitives.InvItem * @alias module:primitives.InvItem
* @constructor * @constructor
* @param {Number} type
* @param {Hash} hash
* @property {InvType} type * @property {InvType} type
* @property {Hash} hash * @property {Hash} hash
*/ */
function InvItem(type, hash) { class InvItem {
if (!(this instanceof InvItem)) /**
return new InvItem(type, hash); * Create an inv item.
* @constructor
* @param {Number} type
* @param {Hash} hash
*/
constructor(type, hash) {
this.type = type; this.type = type;
this.hash = hash; this.hash = hash;
} }
/**
* Write inv item to buffer writer.
* @param {BufferWriter} bw
*/
getSize() {
return 36;
}
/**
* Write inv item to buffer writer.
* @param {BufferWriter} bw
*/
toWriter(bw) {
bw.writeU32(this.type);
bw.writeHash(this.hash);
return bw;
}
/**
* Serialize inv item.
* @returns {Buffer}
*/
toRaw() {
return this.toWriter(new StaticWriter(36)).render();
}
/**
* Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
fromReader(br) {
this.type = br.readU32();
this.hash = br.readHash('hex');
return this;
}
/**
* Inject properties from serialized data.
* @param {Buffer} data
*/
fromRaw(data) {
return this.fromReader(new BufferReader(data));
}
/**
* Instantiate inv item from buffer reader.
* @param {BufferReader} br
* @returns {InvItem}
*/
static fromReader(br) {
return new this().fromReader(br);
}
/**
* Instantiate inv item from serialized data.
* @param {Buffer} data
* @param {String?} enc
* @returns {InvItem}
*/
static fromRaw(data, enc) {
if (typeof data === 'string')
data = Buffer.from(data, enc);
return new this().fromRaw(data);
}
/**
* Test whether the inv item is a block.
* @returns {Boolean}
*/
isBlock() {
switch (this.type) {
case InvItem.types.BLOCK:
case InvItem.types.WITNESS_BLOCK:
case InvItem.types.FILTERED_BLOCK:
case InvItem.types.WITNESS_FILTERED_BLOCK:
case InvItem.types.CMPCT_BLOCK:
return true;
default:
return false;
}
}
/**
* Test whether the inv item is a tx.
* @returns {Boolean}
*/
isTX() {
switch (this.type) {
case InvItem.types.TX:
case InvItem.types.WITNESS_TX:
return true;
default:
return false;
}
}
/**
* Test whether the inv item has the witness bit set.
* @returns {Boolean}
*/
hasWitness() {
return (this.type & InvItem.WITNESS_FLAG) !== 0;
}
/**
* Get little-endian hash.
* @returns {Hash}
*/
rhash() {
return encoding.revHex(this.hash);
}
}
/** /**
* Inv types. * Inv types.
* @enum {Number} * @enum {Number}
@ -36,7 +164,6 @@ function InvItem(type, hash) {
*/ */
InvItem.types = { InvItem.types = {
ERROR: 0,
TX: 1, TX: 1,
BLOCK: 2, BLOCK: 2,
FILTERED_BLOCK: 3, FILTERED_BLOCK: 3,
@ -52,7 +179,6 @@ InvItem.types = {
*/ */
InvItem.typesByVal = { InvItem.typesByVal = {
0: 'ERROR',
1: 'TX', 1: 'TX',
2: 'BLOCK', 2: 'BLOCK',
3: 'FILTERED_BLOCK', 3: 'FILTERED_BLOCK',
@ -70,130 +196,6 @@ InvItem.typesByVal = {
InvItem.WITNESS_FLAG = 1 << 30; InvItem.WITNESS_FLAG = 1 << 30;
/**
* Write inv item to buffer writer.
* @param {BufferWriter} bw
*/
InvItem.prototype.getSize = function getSize() {
return 36;
};
/**
* Write inv item to buffer writer.
* @param {BufferWriter} bw
*/
InvItem.prototype.toWriter = function toWriter(bw) {
bw.writeU32(this.type);
bw.writeHash(this.hash);
return bw;
};
/**
* Serialize inv item.
* @returns {Buffer}
*/
InvItem.prototype.toRaw = function toRaw() {
return this.toWriter(new StaticWriter(36)).render();
};
/**
* Inject properties from buffer reader.
* @private
* @param {BufferReader} br
*/
InvItem.prototype.fromReader = function fromReader(br) {
this.type = br.readU32();
this.hash = br.readHash('hex');
return this;
};
/**
* Inject properties from serialized data.
* @param {Buffer} data
*/
InvItem.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data));
};
/**
* Instantiate inv item from buffer reader.
* @param {BufferReader} br
* @returns {InvItem}
*/
InvItem.fromReader = function fromReader(br) {
return new InvItem().fromReader(br);
};
/**
* Instantiate inv item from serialized data.
* @param {Buffer} data
* @param {String?} enc
* @returns {InvItem}
*/
InvItem.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = Buffer.from(data, enc);
return new InvItem().fromRaw(data);
};
/**
* Test whether the inv item is a block.
* @returns {Boolean}
*/
InvItem.prototype.isBlock = function isBlock() {
switch (this.type) {
case InvItem.types.BLOCK:
case InvItem.types.WITNESS_BLOCK:
case InvItem.types.FILTERED_BLOCK:
case InvItem.types.WITNESS_FILTERED_BLOCK:
case InvItem.types.CMPCT_BLOCK:
return true;
default:
return false;
}
};
/**
* Test whether the inv item is a tx.
* @returns {Boolean}
*/
InvItem.prototype.isTX = function isTX() {
switch (this.type) {
case InvItem.types.TX:
case InvItem.types.WITNESS_TX:
return true;
default:
return false;
}
};
/**
* Test whether the inv item has the witness bit set.
* @returns {Boolean}
*/
InvItem.prototype.hasWitness = function hasWitness() {
return (this.type & InvItem.WITNESS_FLAG) !== 0;
};
/**
* Get little-endian hash.
* @returns {Hash}
*/
InvItem.prototype.rhash = function rhash() {
return encoding.revHex(this.hash);
};
/* /*
* Expose * Expose
*/ */

View File

@ -21,16 +21,19 @@ const Output = require('./output');
const secp256k1 = require('bcrypto/lib/secp256k1'); const secp256k1 = require('bcrypto/lib/secp256k1');
/** /**
* Key Ring
* Represents a key ring which amounts to an address. * Represents a key ring which amounts to an address.
* @alias module:primitives.KeyRing * @alias module:primitives.KeyRing
*/
class KeyRing {
/**
* Create a key ring.
* @constructor * @constructor
* @param {Object} options * @param {Object} options
*/ */
function KeyRing(options) { constructor(options) {
if (!(this instanceof KeyRing))
return new KeyRing(options);
this.witness = false; this.witness = false;
this.nested = false; this.nested = false;
this.publicKey = encoding.ZERO_KEY; this.publicKey = encoding.ZERO_KEY;
@ -56,7 +59,7 @@ function KeyRing(options) {
* @param {Object} options * @param {Object} options
*/ */
KeyRing.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
let key = toKey(options); let key = toKey(options);
if (options.witness != null) { if (options.witness != null) {
@ -87,7 +90,7 @@ KeyRing.prototype.fromOptions = function fromOptions(options) {
return this.fromScript(key, script, compress); return this.fromScript(key, script, compress);
return this.fromKey(key, compress); return this.fromKey(key, compress);
}; }
/** /**
* Instantiate key ring from options. * Instantiate key ring from options.
@ -95,15 +98,15 @@ KeyRing.prototype.fromOptions = function fromOptions(options) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new KeyRing().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Clear cached key/script hashes. * Clear cached key/script hashes.
*/ */
KeyRing.prototype.refresh = function refresh() { refresh() {
this._keyHash = null; this._keyHash = null;
this._keyAddress = null; this._keyAddress = null;
this._program = null; this._program = null;
@ -112,7 +115,7 @@ KeyRing.prototype.refresh = function refresh() {
this._scriptHash160 = null; this._scriptHash160 = null;
this._scriptHash256 = null; this._scriptHash256 = null;
this._scriptAddress = null; this._scriptAddress = null;
}; }
/** /**
* Inject data from private key. * Inject data from private key.
@ -121,7 +124,7 @@ KeyRing.prototype.refresh = function refresh() {
* @param {Boolean?} compress * @param {Boolean?} compress
*/ */
KeyRing.prototype.fromPrivate = function fromPrivate(key, compress) { fromPrivate(key, compress) {
assert(Buffer.isBuffer(key), 'Private key must be a buffer.'); assert(Buffer.isBuffer(key), 'Private key must be a buffer.');
assert(secp256k1.privateKeyVerify(key), 'Not a valid private key.'); assert(secp256k1.privateKeyVerify(key), 'Not a valid private key.');
@ -129,7 +132,7 @@ KeyRing.prototype.fromPrivate = function fromPrivate(key, compress) {
this.publicKey = secp256k1.publicKeyCreate(key, compress !== false); this.publicKey = secp256k1.publicKeyCreate(key, compress !== false);
return this; return this;
}; }
/** /**
* Instantiate keyring from a private key. * Instantiate keyring from a private key.
@ -138,9 +141,9 @@ KeyRing.prototype.fromPrivate = function fromPrivate(key, compress) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromPrivate = function fromPrivate(key, compress) { static fromPrivate(key, compress) {
return new KeyRing().fromPrivate(key, compress); return new this().fromPrivate(key, compress);
}; }
/** /**
* Inject data from public key. * Inject data from public key.
@ -148,12 +151,12 @@ KeyRing.fromPrivate = function fromPrivate(key, compress) {
* @param {Buffer} key * @param {Buffer} key
*/ */
KeyRing.prototype.fromPublic = function fromPublic(key) { fromPublic(key) {
assert(Buffer.isBuffer(key), 'Public key must be a buffer.'); assert(Buffer.isBuffer(key), 'Public key must be a buffer.');
assert(secp256k1.publicKeyVerify(key), 'Not a valid public key.'); assert(secp256k1.publicKeyVerify(key), 'Not a valid public key.');
this.publicKey = key; this.publicKey = key;
return this; return this;
}; }
/** /**
* Generate a keyring. * Generate a keyring.
@ -162,10 +165,10 @@ KeyRing.prototype.fromPublic = function fromPublic(key) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.prototype.generate = function generate(compress) { generate(compress) {
const key = secp256k1.generatePrivateKey(); const key = secp256k1.generatePrivateKey();
return this.fromKey(key, compress); return this.fromKey(key, compress);
}; }
/** /**
* Generate a keyring. * Generate a keyring.
@ -173,9 +176,9 @@ KeyRing.prototype.generate = function generate(compress) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.generate = function generate(compress) { static generate(compress) {
return new KeyRing().generate(compress); return new this().generate(compress);
}; }
/** /**
* Instantiate keyring from a public key. * Instantiate keyring from a public key.
@ -183,9 +186,9 @@ KeyRing.generate = function generate(compress) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromPublic = function fromPublic(key) { static fromPublic(key) {
return new KeyRing().fromPublic(key); return new this().fromPublic(key);
}; }
/** /**
* Inject data from public key. * Inject data from public key.
@ -194,14 +197,14 @@ KeyRing.fromPublic = function fromPublic(key) {
* @param {Boolean?} compress * @param {Boolean?} compress
*/ */
KeyRing.prototype.fromKey = function fromKey(key, compress) { fromKey(key, compress) {
assert(Buffer.isBuffer(key), 'Key must be a buffer.'); assert(Buffer.isBuffer(key), 'Key must be a buffer.');
if (key.length === 32) if (key.length === 32)
return this.fromPrivate(key, compress !== false); return this.fromPrivate(key, compress !== false);
return this.fromPublic(key); return this.fromPublic(key);
}; }
/** /**
* Instantiate keyring from a public key. * Instantiate keyring from a public key.
@ -210,9 +213,9 @@ KeyRing.prototype.fromKey = function fromKey(key, compress) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromKey = function fromKey(key, compress) { static fromKey(key, compress) {
return new KeyRing().fromKey(key, compress); return new this().fromKey(key, compress);
}; }
/** /**
* Inject data from script. * Inject data from script.
@ -222,14 +225,14 @@ KeyRing.fromKey = function fromKey(key, compress) {
* @param {Boolean?} compress * @param {Boolean?} compress
*/ */
KeyRing.prototype.fromScript = function fromScript(key, script, compress) { fromScript(key, script, compress) {
assert(script instanceof Script, 'Non-script passed into KeyRing.'); assert(script instanceof Script, 'Non-script passed into KeyRing.');
this.fromKey(key, compress); this.fromKey(key, compress);
this.script = script; this.script = script;
return this; return this;
}; }
/** /**
* Instantiate keyring from script. * Instantiate keyring from script.
@ -239,16 +242,16 @@ KeyRing.prototype.fromScript = function fromScript(key, script, compress) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromScript = function fromScript(key, script, compress) { static fromScript(key, script, compress) {
return new KeyRing().fromScript(key, script, compress); return new this().fromScript(key, script, compress);
}; }
/** /**
* Calculate WIF serialization size. * Calculate WIF serialization size.
* @returns {Number} * @returns {Number}
*/ */
KeyRing.prototype.getSecretSize = function getSecretSize() { getSecretSize() {
let size = 0; let size = 0;
size += 1; size += 1;
@ -260,7 +263,7 @@ KeyRing.prototype.getSecretSize = function getSecretSize() {
size += 4; size += 4;
return size; return size;
}; }
/** /**
* Convert key to a CBitcoinSecret. * Convert key to a CBitcoinSecret.
@ -268,7 +271,7 @@ KeyRing.prototype.getSecretSize = function getSecretSize() {
* @returns {Base58String} * @returns {Base58String}
*/ */
KeyRing.prototype.toSecret = function toSecret(network) { toSecret(network) {
const size = this.getSecretSize(); const size = this.getSecretSize();
const bw = new StaticWriter(size); const bw = new StaticWriter(size);
@ -285,7 +288,7 @@ KeyRing.prototype.toSecret = function toSecret(network) {
bw.writeChecksum(hash256.digest); bw.writeChecksum(hash256.digest);
return base58.encode(bw.render()); return base58.encode(bw.render());
}; }
/** /**
* Inject properties from serialized CBitcoinSecret. * Inject properties from serialized CBitcoinSecret.
@ -294,7 +297,7 @@ KeyRing.prototype.toSecret = function toSecret(network) {
* @param {(Network|NetworkType)?} network * @param {(Network|NetworkType)?} network
*/ */
KeyRing.prototype.fromSecret = function fromSecret(data, network) { fromSecret(data, network) {
const br = new BufferReader(base58.decode(data), true); const br = new BufferReader(base58.decode(data), true);
const version = br.readU8(); const version = br.readU8();
@ -313,7 +316,7 @@ KeyRing.prototype.fromSecret = function fromSecret(data, network) {
br.verifyChecksum(hash256.digest); br.verifyChecksum(hash256.digest);
return this.fromPrivate(key, compress); return this.fromPrivate(key, compress);
}; }
/** /**
* Instantiate a keyring from a serialized CBitcoinSecret. * Instantiate a keyring from a serialized CBitcoinSecret.
@ -322,9 +325,9 @@ KeyRing.prototype.fromSecret = function fromSecret(data, network) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromSecret = function fromSecret(data, network) { static fromSecret(data, network) {
return new KeyRing().fromSecret(data, network); return new this().fromSecret(data, network);
}; }
/** /**
* Get private key. * Get private key.
@ -332,7 +335,7 @@ KeyRing.fromSecret = function fromSecret(data, network) {
* @returns {Buffer} Private key. * @returns {Buffer} Private key.
*/ */
KeyRing.prototype.getPrivateKey = function getPrivateKey(enc, network) { getPrivateKey(enc, network) {
if (!this.privateKey) if (!this.privateKey)
return null; return null;
@ -343,7 +346,7 @@ KeyRing.prototype.getPrivateKey = function getPrivateKey(enc, network) {
return this.privateKey.toString('hex'); return this.privateKey.toString('hex');
return this.privateKey; return this.privateKey;
}; }
/** /**
* Get public key. * Get public key.
@ -351,7 +354,7 @@ KeyRing.prototype.getPrivateKey = function getPrivateKey(enc, network) {
* @returns {Buffer} * @returns {Buffer}
*/ */
KeyRing.prototype.getPublicKey = function getPublicKey(enc) { getPublicKey(enc) {
if (enc === 'base58') if (enc === 'base58')
return base58.encode(this.publicKey); return base58.encode(this.publicKey);
@ -359,23 +362,23 @@ KeyRing.prototype.getPublicKey = function getPublicKey(enc) {
return this.publicKey.toString('hex'); return this.publicKey.toString('hex');
return this.publicKey; return this.publicKey;
}; }
/** /**
* Get redeem script. * Get redeem script.
* @returns {Script} * @returns {Script}
*/ */
KeyRing.prototype.getScript = function getScript() { getScript() {
return this.script; return this.script;
}; }
/** /**
* Get witness program. * Get witness program.
* @returns {Buffer} * @returns {Buffer}
*/ */
KeyRing.prototype.getProgram = function getProgram() { getProgram() {
if (!this.witness) if (!this.witness)
return null; return null;
@ -392,7 +395,7 @@ KeyRing.prototype.getProgram = function getProgram() {
} }
return this._program; return this._program;
}; }
/** /**
* Get address' ripemd160 program scripthash * Get address' ripemd160 program scripthash
@ -401,7 +404,7 @@ KeyRing.prototype.getProgram = function getProgram() {
* @returns {Buffer} * @returns {Buffer}
*/ */
KeyRing.prototype.getNestedHash = function getNestedHash(enc) { getNestedHash(enc) {
if (!this.witness) if (!this.witness)
return null; return null;
@ -411,7 +414,7 @@ KeyRing.prototype.getNestedHash = function getNestedHash(enc) {
return enc === 'hex' return enc === 'hex'
? this._nestedHash.toString('hex') ? this._nestedHash.toString('hex')
: this._nestedHash; : this._nestedHash;
}; }
/** /**
* Get address' scripthash address for witness program. * Get address' scripthash address for witness program.
@ -419,7 +422,7 @@ KeyRing.prototype.getNestedHash = function getNestedHash(enc) {
* @returns {Address|Base58Address} * @returns {Address|Base58Address}
*/ */
KeyRing.prototype.getNestedAddress = function getNestedAddress(enc, network) { getNestedAddress(enc, network) {
if (!this.witness) if (!this.witness)
return null; return null;
@ -436,7 +439,7 @@ KeyRing.prototype.getNestedAddress = function getNestedAddress(enc, network) {
return this._nestedAddress.toString(network); return this._nestedAddress.toString(network);
return this._nestedAddress; return this._nestedAddress;
}; }
/** /**
* Get scripthash. * Get scripthash.
@ -444,11 +447,11 @@ KeyRing.prototype.getNestedAddress = function getNestedAddress(enc, network) {
* @returns {Buffer} * @returns {Buffer}
*/ */
KeyRing.prototype.getScriptHash = function getScriptHash(enc) { getScriptHash(enc) {
if (this.witness) if (this.witness)
return this.getScriptHash256(enc); return this.getScriptHash256(enc);
return this.getScriptHash160(enc); return this.getScriptHash160(enc);
}; }
/** /**
* Get ripemd160 scripthash. * Get ripemd160 scripthash.
@ -456,7 +459,7 @@ KeyRing.prototype.getScriptHash = function getScriptHash(enc) {
* @returns {Buffer} * @returns {Buffer}
*/ */
KeyRing.prototype.getScriptHash160 = function getScriptHash160(enc) { getScriptHash160(enc) {
if (!this.script) if (!this.script)
return null; return null;
@ -466,7 +469,7 @@ KeyRing.prototype.getScriptHash160 = function getScriptHash160(enc) {
return enc === 'hex' return enc === 'hex'
? this._scriptHash160.toString('hex') ? this._scriptHash160.toString('hex')
: this._scriptHash160; : this._scriptHash160;
}; }
/** /**
* Get sha256 scripthash. * Get sha256 scripthash.
@ -474,7 +477,7 @@ KeyRing.prototype.getScriptHash160 = function getScriptHash160(enc) {
* @returns {Buffer} * @returns {Buffer}
*/ */
KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) { getScriptHash256(enc) {
if (!this.script) if (!this.script)
return null; return null;
@ -484,7 +487,7 @@ KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) {
return enc === 'hex' return enc === 'hex'
? this._scriptHash256.toString('hex') ? this._scriptHash256.toString('hex')
: this._scriptHash256; : this._scriptHash256;
}; }
/** /**
* Get scripthash address. * Get scripthash address.
@ -492,7 +495,7 @@ KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) {
* @returns {Address|Base58Address} * @returns {Address|Base58Address}
*/ */
KeyRing.prototype.getScriptAddress = function getScriptAddress(enc, network) { getScriptAddress(enc, network) {
if (!this.script) if (!this.script)
return null; return null;
@ -515,7 +518,7 @@ KeyRing.prototype.getScriptAddress = function getScriptAddress(enc, network) {
return this._scriptAddress.toString(network); return this._scriptAddress.toString(network);
return this._scriptAddress; return this._scriptAddress;
}; }
/** /**
* Get public key hash. * Get public key hash.
@ -523,14 +526,14 @@ KeyRing.prototype.getScriptAddress = function getScriptAddress(enc, network) {
* @returns {Buffer} * @returns {Buffer}
*/ */
KeyRing.prototype.getKeyHash = function getKeyHash(enc) { getKeyHash(enc) {
if (!this._keyHash) if (!this._keyHash)
this._keyHash = hash160.digest(this.publicKey); this._keyHash = hash160.digest(this.publicKey);
return enc === 'hex' return enc === 'hex'
? this._keyHash.toString('hex') ? this._keyHash.toString('hex')
: this._keyHash; : this._keyHash;
}; }
/** /**
* Get pubkeyhash address. * Get pubkeyhash address.
@ -538,7 +541,7 @@ KeyRing.prototype.getKeyHash = function getKeyHash(enc) {
* @returns {Address|Base58Address} * @returns {Address|Base58Address}
*/ */
KeyRing.prototype.getKeyAddress = function getKeyAddress(enc, network) { getKeyAddress(enc, network) {
if (!this._keyAddress) { if (!this._keyAddress) {
const hash = this.getKeyHash(); const hash = this.getKeyHash();
@ -558,7 +561,7 @@ KeyRing.prototype.getKeyAddress = function getKeyAddress(enc, network) {
return this._keyAddress.toString(network); return this._keyAddress.toString(network);
return this._keyAddress; return this._keyAddress;
}; }
/** /**
* Get hash. * Get hash.
@ -566,7 +569,7 @@ KeyRing.prototype.getKeyAddress = function getKeyAddress(enc, network) {
* @returns {Buffer} * @returns {Buffer}
*/ */
KeyRing.prototype.getHash = function getHash(enc) { getHash(enc) {
if (this.nested) if (this.nested)
return this.getNestedHash(enc); return this.getNestedHash(enc);
@ -574,7 +577,7 @@ KeyRing.prototype.getHash = function getHash(enc) {
return this.getScriptHash(enc); return this.getScriptHash(enc);
return this.getKeyHash(enc); return this.getKeyHash(enc);
}; }
/** /**
* Get base58 address. * Get base58 address.
@ -582,7 +585,7 @@ KeyRing.prototype.getHash = function getHash(enc) {
* @returns {Address|Base58Address} * @returns {Address|Base58Address}
*/ */
KeyRing.prototype.getAddress = function getAddress(enc, network) { getAddress(enc, network) {
if (this.nested) if (this.nested)
return this.getNestedAddress(enc, network); return this.getNestedAddress(enc, network);
@ -590,7 +593,7 @@ KeyRing.prototype.getAddress = function getAddress(enc, network) {
return this.getScriptAddress(enc, network); return this.getScriptAddress(enc, network);
return this.getKeyAddress(enc, network); return this.getKeyAddress(enc, network);
}; }
/** /**
* Test an address hash against hash and program hash. * Test an address hash against hash and program hash.
@ -598,7 +601,7 @@ KeyRing.prototype.getAddress = function getAddress(enc, network) {
* @returns {Boolean} * @returns {Boolean}
*/ */
KeyRing.prototype.ownHash = function ownHash(hash) { ownHash(hash) {
if (!hash) if (!hash)
return false; return false;
@ -616,7 +619,7 @@ KeyRing.prototype.ownHash = function ownHash(hash) {
} }
return false; return false;
}; }
/** /**
* Check whether transaction output belongs to this address. * Check whether transaction output belongs to this address.
@ -625,7 +628,7 @@ KeyRing.prototype.ownHash = function ownHash(hash) {
* @returns {Boolean} * @returns {Boolean}
*/ */
KeyRing.prototype.ownOutput = function ownOutput(tx, index) { ownOutput(tx, index) {
let output; let output;
if (tx instanceof Output) { if (tx instanceof Output) {
@ -636,7 +639,7 @@ KeyRing.prototype.ownOutput = function ownOutput(tx, index) {
} }
return this.ownHash(output.getHash()); return this.ownHash(output.getHash());
}; }
/** /**
* Test a hash against script hashes to * Test a hash against script hashes to
@ -645,7 +648,7 @@ KeyRing.prototype.ownOutput = function ownOutput(tx, index) {
* @returns {Script|null} * @returns {Script|null}
*/ */
KeyRing.prototype.getRedeem = function getRedeem(hash) { getRedeem(hash) {
if (this.witness) { if (this.witness) {
if (hash.equals(this.getNestedHash())) if (hash.equals(this.getNestedHash()))
return this.getProgram(); return this.getProgram();
@ -660,7 +663,7 @@ KeyRing.prototype.getRedeem = function getRedeem(hash) {
} }
return null; return null;
}; }
/** /**
* Sign a message. * Sign a message.
@ -668,10 +671,10 @@ KeyRing.prototype.getRedeem = function getRedeem(hash) {
* @returns {Buffer} Signature in DER format. * @returns {Buffer} Signature in DER format.
*/ */
KeyRing.prototype.sign = function sign(msg) { sign(msg) {
assert(this.privateKey, 'Cannot sign without private key.'); assert(this.privateKey, 'Cannot sign without private key.');
return secp256k1.sign(msg, this.privateKey); return secp256k1.sign(msg, this.privateKey);
}; }
/** /**
* Verify a message. * Verify a message.
@ -680,16 +683,16 @@ KeyRing.prototype.sign = function sign(msg) {
* @returns {Boolean} * @returns {Boolean}
*/ */
KeyRing.prototype.verify = function verify(msg, sig) { verify(msg, sig) {
return secp256k1.verify(msg, sig, this.publicKey); return secp256k1.verify(msg, sig, this.publicKey);
}; }
/** /**
* Get witness program version. * Get witness program version.
* @returns {Number} * @returns {Number}
*/ */
KeyRing.prototype.getVersion = function getVersion() { getVersion() {
if (!this.witness) if (!this.witness)
return -1; return -1;
@ -697,14 +700,14 @@ KeyRing.prototype.getVersion = function getVersion() {
return -1; return -1;
return 0; return 0;
}; }
/** /**
* Get address type. * Get address type.
* @returns {ScriptType} * @returns {ScriptType}
*/ */
KeyRing.prototype.getType = function getType() { getType() {
if (this.nested) if (this.nested)
return Address.types.SCRIPTHASH; return Address.types.SCRIPTHASH;
@ -715,23 +718,23 @@ KeyRing.prototype.getType = function getType() {
return Address.types.SCRIPTHASH; return Address.types.SCRIPTHASH;
return Address.types.PUBKEYHASH; return Address.types.PUBKEYHASH;
}; }
/** /**
* Inspect keyring. * Inspect keyring.
* @returns {Object} * @returns {Object}
*/ */
KeyRing.prototype.inspect = function inspect() { inspect() {
return this.toJSON(); return this.toJSON();
}; }
/** /**
* Convert an KeyRing to a more json-friendly object. * Convert an KeyRing to a more json-friendly object.
* @returns {Object} * @returns {Object}
*/ */
KeyRing.prototype.toJSON = function toJSON(network) { toJSON(network) {
return { return {
witness: this.witness, witness: this.witness,
nested: this.nested, nested: this.nested,
@ -741,7 +744,7 @@ KeyRing.prototype.toJSON = function toJSON(network) {
type: Address.typesByVal[this.getType()].toLowerCase(), type: Address.typesByVal[this.getType()].toLowerCase(),
address: this.getAddress('string', network) address: this.getAddress('string', network)
}; };
}; }
/** /**
* Inject properties from json object. * Inject properties from json object.
@ -749,7 +752,7 @@ KeyRing.prototype.toJSON = function toJSON(network) {
* @param {Object} json * @param {Object} json
*/ */
KeyRing.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
assert(json); assert(json);
assert(typeof json.witness === 'boolean'); assert(typeof json.witness === 'boolean');
assert(typeof json.nested === 'boolean'); assert(typeof json.nested === 'boolean');
@ -764,7 +767,7 @@ KeyRing.prototype.fromJSON = function fromJSON(json) {
this.script = Buffer.from(json.script, 'hex'); this.script = Buffer.from(json.script, 'hex');
return this; return this;
}; }
/** /**
* Instantiate an KeyRing from a jsonified transaction object. * Instantiate an KeyRing from a jsonified transaction object.
@ -772,16 +775,16 @@ KeyRing.prototype.fromJSON = function fromJSON(json) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new KeyRing().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Calculate serialization size. * Calculate serialization size.
* @returns {Number} * @returns {Number}
*/ */
KeyRing.prototype.getSize = function getSize() { getSize() {
let size = 0; let size = 0;
size += 1; size += 1;
if (this.privateKey) { if (this.privateKey) {
@ -792,14 +795,14 @@ KeyRing.prototype.getSize = function getSize() {
} }
size += this.script ? this.script.getVarSize() : 1; size += this.script ? this.script.getVarSize() : 1;
return size; return size;
}; }
/** /**
* Write the keyring to a buffer writer. * Write the keyring to a buffer writer.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
KeyRing.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
let field = 0; let field = 0;
if (this.witness) if (this.witness)
@ -823,17 +826,17 @@ KeyRing.prototype.toWriter = function toWriter(bw) {
bw.writeVarint(0); bw.writeVarint(0);
return bw; return bw;
}; }
/** /**
* Serialize the keyring. * Serialize the keyring.
* @returns {Buffer} * @returns {Buffer}
*/ */
KeyRing.prototype.toRaw = function toRaw() { toRaw() {
const size = this.getSize(); const size = this.getSize();
return this.toWriter(new StaticWriter(size)).render(); return this.toWriter(new StaticWriter(size)).render();
}; }
/** /**
* Inject properties from buffer reader. * Inject properties from buffer reader.
@ -841,7 +844,7 @@ KeyRing.prototype.toRaw = function toRaw() {
* @param {BufferReader} br * @param {BufferReader} br
*/ */
KeyRing.prototype.fromReader = function fromReader(br) { fromReader(br) {
const field = br.readU8(); const field = br.readU8();
this.witness = (field & 1) !== 0; this.witness = (field & 1) !== 0;
@ -864,7 +867,7 @@ KeyRing.prototype.fromReader = function fromReader(br) {
this.script = Script.fromRaw(script); this.script = Script.fromRaw(script);
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -872,9 +875,9 @@ KeyRing.prototype.fromReader = function fromReader(br) {
* @param {Buffer} data * @param {Buffer} data
*/ */
KeyRing.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
return this.fromReader(new BufferReader(data)); return this.fromReader(new BufferReader(data));
}; }
/** /**
* Instantiate a keyring from buffer reader. * Instantiate a keyring from buffer reader.
@ -882,9 +885,9 @@ KeyRing.prototype.fromRaw = function fromRaw(data) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromReader = function fromReader(br) { static fromReader(br) {
return new KeyRing().fromReader(br); return new this().fromReader(br);
}; }
/** /**
* Instantiate a keyring from serialized data. * Instantiate a keyring from serialized data.
@ -892,9 +895,9 @@ KeyRing.fromReader = function fromReader(br) {
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromRaw = function fromRaw(data) { static fromRaw(data) {
return new KeyRing().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Test whether an object is a KeyRing. * Test whether an object is a KeyRing.
@ -902,9 +905,10 @@ KeyRing.fromRaw = function fromRaw(data) {
* @returns {Boolean} * @returns {Boolean}
*/ */
KeyRing.isKeyRing = function isKeyRing(obj) { static isKeyRing(obj) {
return obj instanceof KeyRing; return obj instanceof KeyRing;
}; }
}
/* /*
* Helpers * Helpers

View File

@ -15,6 +15,7 @@ const BufferReader = require('bufio/lib/reader');
const DUMMY = Buffer.alloc(0); const DUMMY = Buffer.alloc(0);
/** /**
* Mem Block
* A block object which is essentially a "placeholder" * A block object which is essentially a "placeholder"
* for a full {@link Block} object. The v8 garbage * for a full {@link Block} object. The v8 garbage
* collector's head will explode if there is too much * collector's head will explode if there is too much
@ -31,56 +32,56 @@ const DUMMY = Buffer.alloc(0);
* 500mb of blocks on the js heap would not be a good * 500mb of blocks on the js heap would not be a good
* thing. * thing.
* @alias module:primitives.MemBlock * @alias module:primitives.MemBlock
* @constructor * @extends AbstractBlock
* @param {NakedBlock} options
*/ */
function MemBlock() { class MemBlock extends AbstractBlock {
if (!(this instanceof MemBlock)) /**
return new MemBlock(); * Create a mem block.
* @constructor
*/
AbstractBlock.call(this); constructor() {
super();
this._raw = DUMMY; this._raw = DUMMY;
} }
Object.setPrototypeOf(MemBlock.prototype, AbstractBlock.prototype);
/** /**
* Test whether the block is a memblock. * Test whether the block is a memblock.
* @returns {Boolean} * @returns {Boolean}
*/ */
MemBlock.prototype.isMemory = function isMemory() { isMemory() {
return true; return true;
}; }
/** /**
* Serialize the block headers. * Serialize the block headers.
* @returns {Buffer} * @returns {Buffer}
*/ */
MemBlock.prototype.toHead = function toHead() { toHead() {
return this._raw.slice(0, 80); return this._raw.slice(0, 80);
}; }
/** /**
* Get the full block size. * Get the full block size.
* @returns {Number} * @returns {Number}
*/ */
MemBlock.prototype.getSize = function getSize() { getSize() {
return this._raw.length; return this._raw.length;
}; }
/** /**
* Verify the block. * Verify the block.
* @returns {Boolean} * @returns {Boolean}
*/ */
MemBlock.prototype.verifyBody = function verifyBody() { verifyBody() {
return true; return true;
}; }
/** /**
* Retrieve the coinbase height * Retrieve the coinbase height
@ -88,7 +89,7 @@ MemBlock.prototype.verifyBody = function verifyBody() {
* @returns {Number} height (-1 if not present). * @returns {Number} height (-1 if not present).
*/ */
MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() { getCoinbaseHeight() {
if (this.version < 2) if (this.version < 2)
return -1; return -1;
@ -97,7 +98,7 @@ MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
} catch (e) { } catch (e) {
return -1; return -1;
} }
}; }
/** /**
* Parse the coinbase height * Parse the coinbase height
@ -106,7 +107,7 @@ MemBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
* @returns {Number} height (-1 if not present). * @returns {Number} height (-1 if not present).
*/ */
MemBlock.prototype.parseCoinbaseHeight = function parseCoinbaseHeight() { parseCoinbaseHeight() {
const br = new BufferReader(this._raw, true); const br = new BufferReader(this._raw, true);
br.seek(80); br.seek(80);
@ -133,7 +134,7 @@ MemBlock.prototype.parseCoinbaseHeight = function parseCoinbaseHeight() {
const script = br.readVarBytes(); const script = br.readVarBytes();
return Script.getCoinbaseHeight(script); return Script.getCoinbaseHeight(script);
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -141,7 +142,7 @@ MemBlock.prototype.parseCoinbaseHeight = function parseCoinbaseHeight() {
* @param {Buffer} data * @param {Buffer} data
*/ */
MemBlock.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
const br = new BufferReader(data, true); const br = new BufferReader(data, true);
this.readHead(br); this.readHead(br);
@ -149,7 +150,7 @@ MemBlock.prototype.fromRaw = function fromRaw(data) {
this._raw = br.data; this._raw = br.data;
return this; return this;
}; }
/** /**
* Insantiate a memblock from serialized data. * Insantiate a memblock from serialized data.
@ -157,27 +158,27 @@ MemBlock.prototype.fromRaw = function fromRaw(data) {
* @returns {MemBlock} * @returns {MemBlock}
*/ */
MemBlock.fromRaw = function fromRaw(data) { static fromRaw(data) {
return new MemBlock().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Return serialized block data. * Return serialized block data.
* @returns {Buffer} * @returns {Buffer}
*/ */
MemBlock.prototype.toRaw = function toRaw() { toRaw() {
return this._raw; return this._raw;
}; }
/** /**
* Return serialized block data. * Return serialized block data.
* @returns {Buffer} * @returns {Buffer}
*/ */
MemBlock.prototype.toNormal = function toNormal() { toNormal() {
return this._raw; return this._raw;
}; }
/** /**
* Parse the serialized block data * Parse the serialized block data
@ -186,23 +187,23 @@ MemBlock.prototype.toNormal = function toNormal() {
* @throws Parse error * @throws Parse error
*/ */
MemBlock.prototype.toBlock = function toBlock() { toBlock() {
const block = Block.fromRaw(this._raw); const block = Block.fromRaw(this._raw);
block._hash = this._hash; block._hash = this._hash;
block._hhash = this._hhash; block._hhash = this._hhash;
return block; return block;
}; }
/** /**
* Convert the block to a headers object. * Convert the block to a headers object.
* @returns {Headers} * @returns {Headers}
*/ */
MemBlock.prototype.toHeaders = function toHeaders() { toHeaders() {
return Headers.fromBlock(this); return Headers.fromBlock(this);
}; }
/** /**
* Test whether an object is a MemBlock. * Test whether an object is a MemBlock.
@ -210,9 +211,10 @@ MemBlock.prototype.toHeaders = function toHeaders() {
* @returns {Boolean} * @returns {Boolean}
*/ */
MemBlock.isMemBlock = function isMemBlock(obj) { static isMemBlock(obj) {
return obj instanceof MemBlock; return obj instanceof MemBlock;
}; }
}
/* /*
* Expose * Expose

View File

@ -19,18 +19,21 @@ const Headers = require('./headers');
const DUMMY = Buffer.from([0]); const DUMMY = Buffer.from([0]);
/** /**
* Merkle Block
* Represents a merkle (filtered) block. * Represents a merkle (filtered) block.
* @alias module:primitives.MerkleBlock * @alias module:primitives.MerkleBlock
* @constructor
* @extends AbstractBlock * @extends AbstractBlock
* @param {NakedBlock} options
*/ */
function MerkleBlock(options) { class MerkleBlock extends AbstractBlock {
if (!(this instanceof MerkleBlock)) /**
return new MerkleBlock(options); * Create a merkle block.
* @constructor
* @param {Object} options
*/
AbstractBlock.call(this); constructor(options) {
super();
this.txs = []; this.txs = [];
this.hashes = []; this.hashes = [];
@ -43,15 +46,13 @@ function MerkleBlock(options) {
this.fromOptions(options); this.fromOptions(options);
} }
Object.setPrototypeOf(MerkleBlock.prototype, AbstractBlock.prototype);
/** /**
* Inject properties from options object. * Inject properties from options object.
* @private * @private
* @param {NakedBlock} options * @param {NakedBlock} options
*/ */
MerkleBlock.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
this.parseOptions(options); this.parseOptions(options);
assert(options, 'MerkleBlock data is required.'); assert(options, 'MerkleBlock data is required.');
@ -79,7 +80,7 @@ MerkleBlock.prototype.fromOptions = function fromOptions(options) {
} }
return this; return this;
}; }
/** /**
* Instantiate merkle block from options object. * Instantiate merkle block from options object.
@ -87,16 +88,16 @@ MerkleBlock.prototype.fromOptions = function fromOptions(options) {
* @returns {MerkleBlock} * @returns {MerkleBlock}
*/ */
MerkleBlock.fromOptions = function fromOptions(data) { static fromOptions(data) {
return new MerkleBlock().fromOptions(data); return new this().fromOptions(data);
}; }
/** /**
* Clear any cached values. * Clear any cached values.
* @param {Boolean?} all - Clear transactions. * @param {Boolean?} all - Clear transactions.
*/ */
MerkleBlock.prototype.refresh = function refresh(all) { refresh(all) {
this._refresh(); this._refresh();
this._tree = null; this._tree = null;
@ -105,7 +106,7 @@ MerkleBlock.prototype.refresh = function refresh(all) {
for (const tx of this.txs) for (const tx of this.txs)
tx.refresh(); tx.refresh();
}; }
/** /**
* Test the block's _matched_ transaction vector against a hash. * Test the block's _matched_ transaction vector against a hash.
@ -113,9 +114,9 @@ MerkleBlock.prototype.refresh = function refresh(all) {
* @returns {Boolean} * @returns {Boolean}
*/ */
MerkleBlock.prototype.hasTX = function hasTX(hash) { hasTX(hash) {
return this.indexOf(hash) !== -1; return this.indexOf(hash) !== -1;
}; }
/** /**
* Test the block's _matched_ transaction vector against a hash. * Test the block's _matched_ transaction vector against a hash.
@ -123,7 +124,7 @@ MerkleBlock.prototype.hasTX = function hasTX(hash) {
* @returns {Number} Index. * @returns {Number} Index.
*/ */
MerkleBlock.prototype.indexOf = function indexOf(hash) { indexOf(hash) {
const tree = this.getTree(); const tree = this.getTree();
const index = tree.map.get(hash); const index = tree.map.get(hash);
@ -131,7 +132,7 @@ MerkleBlock.prototype.indexOf = function indexOf(hash) {
return -1; return -1;
return index; return index;
}; }
/** /**
* Verify the partial merkletree. * Verify the partial merkletree.
@ -139,10 +140,10 @@ MerkleBlock.prototype.indexOf = function indexOf(hash) {
* @returns {Boolean} * @returns {Boolean}
*/ */
MerkleBlock.prototype.verifyBody = function verifyBody() { verifyBody() {
const [valid] = this.checkBody(); const [valid] = this.checkBody();
return valid; return valid;
}; }
/** /**
* Verify the partial merkletree. * Verify the partial merkletree.
@ -150,14 +151,14 @@ MerkleBlock.prototype.verifyBody = function verifyBody() {
* @returns {Array} [valid, reason, score] * @returns {Array} [valid, reason, score]
*/ */
MerkleBlock.prototype.checkBody = function checkBody() { checkBody() {
const tree = this.getTree(); const tree = this.getTree();
if (tree.root !== this.merkleRoot) if (tree.root !== this.merkleRoot)
return [false, 'bad-txnmrklroot', 100]; return [false, 'bad-txnmrklroot', 100];
return [true, 'valid', 0]; return [true, 'valid', 0];
}; }
/** /**
* Extract the matches from partial merkle * Extract the matches from partial merkle
@ -165,7 +166,7 @@ MerkleBlock.prototype.checkBody = function checkBody() {
* @returns {Object} * @returns {Object}
*/ */
MerkleBlock.prototype.getTree = function getTree() { getTree() {
if (!this._tree) { if (!this._tree) {
try { try {
this._tree = this.extractTree(); this._tree = this.extractTree();
@ -174,7 +175,7 @@ MerkleBlock.prototype.getTree = function getTree() {
} }
} }
return this._tree; return this._tree;
}; }
/** /**
* Extract the matches from partial merkle * Extract the matches from partial merkle
@ -183,13 +184,14 @@ MerkleBlock.prototype.getTree = function getTree() {
* @returns {Object} * @returns {Object}
*/ */
MerkleBlock.prototype.extractTree = function extractTree() { extractTree() {
const matches = []; const matches = [];
const indexes = []; const indexes = [];
const map = new Map(); const map = new Map();
const hashes = this.hashes; const hashes = this.hashes;
const flags = this.flags; const flags = this.flags;
const totalTX = this.totalTX; const totalTX = this.totalTX;
let bitsUsed = 0; let bitsUsed = 0;
let hashUsed = 0; let hashUsed = 0;
let failed = false; let failed = false;
@ -207,7 +209,7 @@ MerkleBlock.prototype.extractTree = function extractTree() {
const parent = (flags[bitsUsed / 8 | 0] >>> (bitsUsed % 8)) & 1; const parent = (flags[bitsUsed / 8 | 0] >>> (bitsUsed % 8)) & 1;
bitsUsed++; bitsUsed += 1;
if (height === 0 || !parent) { if (height === 0 || !parent) {
if (hashUsed >= hashes.length) { if (hashUsed >= hashes.length) {
@ -215,7 +217,9 @@ MerkleBlock.prototype.extractTree = function extractTree() {
return encoding.ZERO_HASH; return encoding.ZERO_HASH;
} }
const hash = hashes[hashUsed++]; const hash = hashes[hashUsed];
hashUsed += 1;
if (height === 0 && parent) { if (height === 0 && parent) {
const txid = hash.toString('hex'); const txid = hash.toString('hex');
@ -254,7 +258,7 @@ MerkleBlock.prototype.extractTree = function extractTree() {
throw new Error('Flags too small.'); throw new Error('Flags too small.');
while (width(height) > 1) while (width(height) > 1)
height++; height += 1;
const root = traverse(height, 0); const root = traverse(height, 0);
@ -268,16 +272,16 @@ MerkleBlock.prototype.extractTree = function extractTree() {
throw new Error('Incorrect number of hashes.'); throw new Error('Incorrect number of hashes.');
return new PartialTree(root, matches, indexes, map); return new PartialTree(root, matches, indexes, map);
}; }
/** /**
* Extract the coinbase height (always -1). * Extract the coinbase height (always -1).
* @returns {Number} * @returns {Number}
*/ */
MerkleBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() { getCoinbaseHeight() {
return -1; return -1;
}; }
/** /**
* Inspect the block and return a more * Inspect the block and return a more
@ -285,9 +289,9 @@ MerkleBlock.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
* @returns {Object} * @returns {Object}
*/ */
MerkleBlock.prototype.inspect = function inspect() { inspect() {
return this.format(); return this.format();
}; }
/** /**
* Inspect the block and return a more * Inspect the block and return a more
@ -297,7 +301,7 @@ MerkleBlock.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
MerkleBlock.prototype.format = function format(view, height) { format(view, height) {
return { return {
hash: this.rhash(), hash: this.rhash(),
height: height != null ? height : -1, height: height != null ? height : -1,
@ -316,14 +320,14 @@ MerkleBlock.prototype.format = function format(view, height) {
map: this.getTree().map, map: this.getTree().map,
txs: this.txs.length txs: this.txs.length
}; };
}; }
/** /**
* Get merkleblock size. * Get merkleblock size.
* @returns {Number} Size. * @returns {Number} Size.
*/ */
MerkleBlock.prototype.getSize = function getSize() { getSize() {
let size = 0; let size = 0;
size += 80; size += 80;
size += 4; size += 4;
@ -332,14 +336,14 @@ MerkleBlock.prototype.getSize = function getSize() {
size += encoding.sizeVarint(this.flags.length); size += encoding.sizeVarint(this.flags.length);
size += this.flags.length; size += this.flags.length;
return size; return size;
}; }
/** /**
* Write the merkleblock to a buffer writer. * Write the merkleblock to a buffer writer.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
MerkleBlock.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
this.writeHead(bw); this.writeHead(bw);
bw.writeU32(this.totalTX); bw.writeU32(this.totalTX);
@ -352,7 +356,7 @@ MerkleBlock.prototype.toWriter = function toWriter(bw) {
bw.writeVarBytes(this.flags); bw.writeVarBytes(this.flags);
return bw; return bw;
}; }
/** /**
* Serialize the merkleblock. * Serialize the merkleblock.
@ -360,10 +364,10 @@ MerkleBlock.prototype.toWriter = function toWriter(bw) {
* @returns {Buffer|String} * @returns {Buffer|String}
*/ */
MerkleBlock.prototype.toRaw = function toRaw() { toRaw() {
const size = this.getSize(); const size = this.getSize();
return this.toWriter(new StaticWriter(size)).render(); return this.toWriter(new StaticWriter(size)).render();
}; }
/** /**
* Inject properties from buffer reader. * Inject properties from buffer reader.
@ -371,7 +375,7 @@ MerkleBlock.prototype.toRaw = function toRaw() {
* @param {BufferReader} br * @param {BufferReader} br
*/ */
MerkleBlock.prototype.fromReader = function fromReader(br) { fromReader(br) {
this.readHead(br); this.readHead(br);
this.totalTX = br.readU32(); this.totalTX = br.readU32();
@ -384,7 +388,7 @@ MerkleBlock.prototype.fromReader = function fromReader(br) {
this.flags = br.readVarBytes(); this.flags = br.readVarBytes();
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -392,9 +396,9 @@ MerkleBlock.prototype.fromReader = function fromReader(br) {
* @param {Buffer} data * @param {Buffer} data
*/ */
MerkleBlock.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
return this.fromReader(new BufferReader(data)); return this.fromReader(new BufferReader(data));
}; }
/** /**
* Instantiate a merkleblock from a buffer reader. * Instantiate a merkleblock from a buffer reader.
@ -402,9 +406,9 @@ MerkleBlock.prototype.fromRaw = function fromRaw(data) {
* @returns {MerkleBlock} * @returns {MerkleBlock}
*/ */
MerkleBlock.fromReader = function fromReader(br) { static fromReader(br) {
return new MerkleBlock().fromReader(br); return new this().fromReader(br);
}; }
/** /**
* Instantiate a merkleblock from a serialized data. * Instantiate a merkleblock from a serialized data.
@ -413,11 +417,11 @@ MerkleBlock.fromReader = function fromReader(br) {
* @returns {MerkleBlock} * @returns {MerkleBlock}
*/ */
MerkleBlock.fromRaw = function fromRaw(data, enc) { static fromRaw(data, enc) {
if (typeof data === 'string') if (typeof data === 'string')
data = Buffer.from(data, enc); data = Buffer.from(data, enc);
return new MerkleBlock().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Convert the block to an object suitable * Convert the block to an object suitable
@ -425,9 +429,9 @@ MerkleBlock.fromRaw = function fromRaw(data, enc) {
* @returns {Object} * @returns {Object}
*/ */
MerkleBlock.prototype.toJSON = function toJSON() { toJSON() {
return this.getJSON(); return this.getJSON();
}; }
/** /**
* Convert the block to an object suitable * Convert the block to an object suitable
@ -440,7 +444,7 @@ MerkleBlock.prototype.toJSON = function toJSON() {
* @returns {Object} * @returns {Object}
*/ */
MerkleBlock.prototype.getJSON = function getJSON(network, view, height) { getJSON(network, view, height) {
return { return {
hash: this.rhash(), hash: this.rhash(),
height: height, height: height,
@ -456,7 +460,7 @@ MerkleBlock.prototype.getJSON = function getJSON(network, view, height) {
}), }),
flags: this.flags.toString('hex') flags: this.flags.toString('hex')
}; };
}; }
/** /**
* Inject properties from json object. * Inject properties from json object.
@ -464,7 +468,7 @@ MerkleBlock.prototype.getJSON = function getJSON(network, view, height) {
* @param {Object} json * @param {Object} json
*/ */
MerkleBlock.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
assert(json, 'MerkleBlock data is required.'); assert(json, 'MerkleBlock data is required.');
assert(Array.isArray(json.hashes)); assert(Array.isArray(json.hashes));
assert(typeof json.flags === 'string'); assert(typeof json.flags === 'string');
@ -482,7 +486,7 @@ MerkleBlock.prototype.fromJSON = function fromJSON(json) {
this.totalTX = json.totalTX; this.totalTX = json.totalTX;
return this; return this;
}; }
/** /**
* Instantiate a merkle block from a jsonified block object. * Instantiate a merkle block from a jsonified block object.
@ -490,9 +494,9 @@ MerkleBlock.prototype.fromJSON = function fromJSON(json) {
* @returns {MerkleBlock} * @returns {MerkleBlock}
*/ */
MerkleBlock.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new MerkleBlock().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Create a merkleblock from a {@link Block} object, passing * Create a merkleblock from a {@link Block} object, passing
@ -503,14 +507,14 @@ MerkleBlock.fromJSON = function fromJSON(json) {
* @returns {MerkleBlock} * @returns {MerkleBlock}
*/ */
MerkleBlock.fromBlock = function fromBlock(block, filter) { static fromBlock(block, filter) {
const matches = []; const matches = [];
for (const tx of block.txs) for (const tx of block.txs)
matches.push(tx.isWatched(filter) ? 1 : 0); matches.push(tx.isWatched(filter) ? 1 : 0);
return MerkleBlock.fromMatches(block, matches); return this.fromMatches(block, matches);
}; }
/** /**
* Create a merkleblock from an array of txids. * Create a merkleblock from an array of txids.
@ -520,7 +524,7 @@ MerkleBlock.fromBlock = function fromBlock(block, filter) {
* @returns {MerkleBlock} * @returns {MerkleBlock}
*/ */
MerkleBlock.fromHashes = function fromHashes(block, hashes) { static fromHashes(block, hashes) {
const filter = new Set(); const filter = new Set();
for (let hash of hashes) { for (let hash of hashes) {
@ -536,8 +540,8 @@ MerkleBlock.fromHashes = function fromHashes(block, hashes) {
matches.push(filter.has(hash) ? 1 : 0); matches.push(filter.has(hash) ? 1 : 0);
} }
return MerkleBlock.fromMatches(block, matches); return this.fromMatches(block, matches);
}; }
/** /**
* Create a merkleblock from an array of matches. * Create a merkleblock from an array of matches.
@ -547,7 +551,7 @@ MerkleBlock.fromHashes = function fromHashes(block, hashes) {
* @returns {MerkleBlock} * @returns {MerkleBlock}
*/ */
MerkleBlock.fromMatches = function fromMatches(block, matches) { static fromMatches(block, matches) {
const txs = []; const txs = [];
const leaves = []; const leaves = [];
const bits = []; const bits = [];
@ -577,7 +581,7 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
const traverse = (height, pos, leaves, matches) => { const traverse = (height, pos, leaves, matches) => {
let parent = 0; let parent = 0;
for (let p = (pos << height); p < ((pos + 1) << height) && p < totalTX; p++) for (let p = pos << height; p < ((pos + 1) << height) && p < totalTX; p++)
parent |= matches[p]; parent |= matches[p];
bits.push(parent); bits.push(parent);
@ -603,7 +607,7 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
} }
while (width(height) > 1) while (width(height) > 1)
height++; height += 1;
traverse(height, 0, leaves, matches); traverse(height, 0, leaves, matches);
@ -613,7 +617,7 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
for (let p = 0; p < bits.length; p++) for (let p = 0; p < bits.length; p++)
flags[p / 8 | 0] |= bits[p] << (p % 8); flags[p / 8 | 0] |= bits[p] << (p % 8);
const merkle = new MerkleBlock(); const merkle = new this();
merkle._hash = block._hash; merkle._hash = block._hash;
merkle._hhash = block._hhash; merkle._hhash = block._hhash;
merkle.version = block.version; merkle.version = block.version;
@ -628,7 +632,7 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
merkle.txs = txs; merkle.txs = txs;
return merkle; return merkle;
}; }
/** /**
* Test whether an object is a MerkleBlock. * Test whether an object is a MerkleBlock.
@ -636,29 +640,32 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
* @returns {Boolean} * @returns {Boolean}
*/ */
MerkleBlock.isMerkleBlock = function isMerkleBlock(obj) { static isMerkleBlock(obj) {
return obj instanceof MerkleBlock; return obj instanceof MerkleBlock;
}; }
/** /**
* Convert the block to a headers object. * Convert the block to a headers object.
* @returns {Headers} * @returns {Headers}
*/ */
MerkleBlock.prototype.toHeaders = function toHeaders() { toHeaders() {
return Headers.fromBlock(this); return Headers.fromBlock(this);
}; }
}
/* /*
* Helpers * Helpers
*/ */
function PartialTree(root, matches, indexes, map) { class PartialTree {
constructor(root, matches, indexes, map) {
this.root = root ? root.toString('hex') : encoding.NULL_HASH; this.root = root ? root.toString('hex') : encoding.NULL_HASH;
this.matches = matches || []; this.matches = matches || [];
this.indexes = indexes || []; this.indexes = indexes || [];
this.map = map || new Map(); this.map = map || new Map();
} }
}
/* /*
* Expose * Expose

File diff suppressed because it is too large Load Diff

View File

@ -15,24 +15,27 @@ const StaticWriter = require('bufio/lib/staticwriter');
const BufferReader = require('bufio/lib/reader'); const BufferReader = require('bufio/lib/reader');
/** /**
* Net Address
* Represents a network address. * Represents a network address.
* @alias module:primitives.NetAddress * @alias module:primitives.NetAddress
* @constructor
* @param {Object} options
* @param {Number?} options.time - Timestamp.
* @param {Number?} options.services - Service bits.
* @param {String?} options.host - IP address (IPv6 or IPv4).
* @param {Number?} options.port - Port.
* @property {Host} host * @property {Host} host
* @property {Number} port * @property {Number} port
* @property {Number} services * @property {Number} services
* @property {Number} time * @property {Number} time
*/ */
function NetAddress(options) { class NetAddress {
if (!(this instanceof NetAddress)) /**
return new NetAddress(options); * Create a network address.
* @constructor
* @param {Object} options
* @param {Number?} options.time - Timestamp.
* @param {Number?} options.services - Service bits.
* @param {String?} options.host - IP address (IPv6 or IPv4).
* @param {Number?} options.port - Port.
*/
constructor(options) {
this.host = '0.0.0.0'; this.host = '0.0.0.0';
this.port = 0; this.port = 0;
this.services = 0; this.services = 0;
@ -44,25 +47,13 @@ function NetAddress(options) {
this.fromOptions(options); this.fromOptions(options);
} }
/**
* Default services for
* unknown outbound peers.
* @const {Number}
* @default
*/
NetAddress.DEFAULT_SERVICES = 0
| common.services.NETWORK
| common.services.WITNESS
| common.services.BLOOM;
/** /**
* Inject properties from options object. * Inject properties from options object.
* @private * @private
* @param {Object} options * @param {Object} options
*/ */
NetAddress.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
assert(typeof options.host === 'string'); assert(typeof options.host === 'string');
assert(typeof options.port === 'number'); assert(typeof options.port === 'number');
@ -83,7 +74,7 @@ NetAddress.prototype.fromOptions = function fromOptions(options) {
this.hostname = IP.toHostname(this.host, this.port); this.hostname = IP.toHostname(this.host, this.port);
return this; return this;
}; }
/** /**
* Instantiate network address from options. * Instantiate network address from options.
@ -91,9 +82,9 @@ NetAddress.prototype.fromOptions = function fromOptions(options) {
* @returns {NetAddress} * @returns {NetAddress}
*/ */
NetAddress.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new NetAddress().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Test whether required services are available. * Test whether required services are available.
@ -101,95 +92,95 @@ NetAddress.fromOptions = function fromOptions(options) {
* @returns {Boolean} * @returns {Boolean}
*/ */
NetAddress.prototype.hasServices = function hasServices(services) { hasServices(services) {
return (this.services & services) === services; return (this.services & services) === services;
}; }
/** /**
* Test whether the address is IPv4. * Test whether the address is IPv4.
* @returns {Boolean} * @returns {Boolean}
*/ */
NetAddress.isIPv4 = function isIPv4() { static isIPv4() {
return IP.isIPv4(this.raw); return IP.isIPv4(this.raw);
}; }
/** /**
* Test whether the address is IPv6. * Test whether the address is IPv6.
* @returns {Boolean} * @returns {Boolean}
*/ */
NetAddress.isIPv6 = function isIPv6() { static isIPv6() {
return IP.isIPv6(this.raw); return IP.isIPv6(this.raw);
}; }
/** /**
* Test whether the host is null. * Test whether the host is null.
* @returns {Boolean} * @returns {Boolean}
*/ */
NetAddress.prototype.isNull = function isNull() { isNull() {
return IP.isNull(this.raw); return IP.isNull(this.raw);
}; }
/** /**
* Test whether the host is a local address. * Test whether the host is a local address.
* @returns {Boolean} * @returns {Boolean}
*/ */
NetAddress.prototype.isLocal = function isLocal() { isLocal() {
return IP.isLocal(this.raw); return IP.isLocal(this.raw);
}; }
/** /**
* Test whether the host is valid. * Test whether the host is valid.
* @returns {Boolean} * @returns {Boolean}
*/ */
NetAddress.prototype.isValid = function isValid() { isValid() {
return IP.isValid(this.raw); return IP.isValid(this.raw);
}; }
/** /**
* Test whether the host is routable. * Test whether the host is routable.
* @returns {Boolean} * @returns {Boolean}
*/ */
NetAddress.prototype.isRoutable = function isRoutable() { isRoutable() {
return IP.isRoutable(this.raw); return IP.isRoutable(this.raw);
}; }
/** /**
* Test whether the host is an onion address. * Test whether the host is an onion address.
* @returns {Boolean} * @returns {Boolean}
*/ */
NetAddress.prototype.isOnion = function isOnion() { isOnion() {
return IP.isOnion(this.raw); return IP.isOnion(this.raw);
}; }
/** /**
* Compare against another network address. * Compare against another network address.
* @returns {Boolean} * @returns {Boolean}
*/ */
NetAddress.prototype.equal = function equal(addr) { equal(addr) {
return this.compare(addr) === 0; return this.compare(addr) === 0;
}; }
/** /**
* Compare against another network address. * Compare against another network address.
* @returns {Number} * @returns {Number}
*/ */
NetAddress.prototype.compare = function compare(addr) { compare(addr) {
const cmp = this.raw.compare(addr.raw); const cmp = this.raw.compare(addr.raw);
if (cmp !== 0) if (cmp !== 0)
return cmp; return cmp;
return this.port - addr.port; return this.port - addr.port;
}; }
/** /**
* Get reachable score to destination. * Get reachable score to destination.
@ -197,41 +188,41 @@ NetAddress.prototype.compare = function compare(addr) {
* @returns {Number} * @returns {Number}
*/ */
NetAddress.prototype.getReachability = function getReachability(dest) { getReachability(dest) {
return IP.getReachability(this.raw, dest.raw); return IP.getReachability(this.raw, dest.raw);
}; }
/** /**
* Set null host. * Set null host.
*/ */
NetAddress.prototype.setNull = function setNull() { setNull() {
this.raw = IP.ZERO_IP; this.raw = IP.ZERO_IP;
this.host = '0.0.0.0'; this.host = '0.0.0.0';
this.hostname = IP.toHostname(this.host, this.port); this.hostname = IP.toHostname(this.host, this.port);
}; }
/** /**
* Set host. * Set host.
* @param {String} host * @param {String} host
*/ */
NetAddress.prototype.setHost = function setHost(host) { setHost(host) {
this.raw = IP.toBuffer(host); this.raw = IP.toBuffer(host);
this.host = IP.toString(this.raw); this.host = IP.toString(this.raw);
this.hostname = IP.toHostname(this.host, this.port); this.hostname = IP.toHostname(this.host, this.port);
}; }
/** /**
* Set port. * Set port.
* @param {Number} port * @param {Number} port
*/ */
NetAddress.prototype.setPort = function setPort(port) { setPort(port) {
assert(port >= 0 && port <= 0xffff); assert(port >= 0 && port <= 0xffff);
this.port = port; this.port = port;
this.hostname = IP.toHostname(this.host, port); this.hostname = IP.toHostname(this.host, port);
}; }
/** /**
* Inject properties from host, port, and network. * Inject properties from host, port, and network.
@ -241,7 +232,7 @@ NetAddress.prototype.setPort = function setPort(port) {
* @param {(Network|NetworkType)?} network * @param {(Network|NetworkType)?} network
*/ */
NetAddress.prototype.fromHost = function fromHost(host, port, network) { fromHost(host, port, network) {
network = Network.get(network); network = Network.get(network);
assert(port >= 0 && port <= 0xffff); assert(port >= 0 && port <= 0xffff);
@ -255,7 +246,7 @@ NetAddress.prototype.fromHost = function fromHost(host, port, network) {
this.hostname = IP.toHostname(this.host, this.port); this.hostname = IP.toHostname(this.host, this.port);
return this; return this;
}; }
/** /**
* Instantiate a network address * Instantiate a network address
@ -266,9 +257,9 @@ NetAddress.prototype.fromHost = function fromHost(host, port, network) {
* @returns {NetAddress} * @returns {NetAddress}
*/ */
NetAddress.fromHost = function fromHost(host, port, network) { static fromHost(host, port, network) {
return new NetAddress().fromHost(host, port, network); return new this().fromHost(host, port, network);
}; }
/** /**
* Inject properties from hostname and network. * Inject properties from hostname and network.
@ -277,13 +268,13 @@ NetAddress.fromHost = function fromHost(host, port, network) {
* @param {(Network|NetworkType)?} network * @param {(Network|NetworkType)?} network
*/ */
NetAddress.prototype.fromHostname = function fromHostname(hostname, network) { fromHostname(hostname, network) {
network = Network.get(network); network = Network.get(network);
const addr = IP.fromHostname(hostname, network.port); const addr = IP.fromHostname(hostname, network.port);
return this.fromHost(addr.host, addr.port, network); return this.fromHost(addr.host, addr.port, network);
}; }
/** /**
* Instantiate a network address * Instantiate a network address
@ -293,9 +284,9 @@ NetAddress.prototype.fromHostname = function fromHostname(hostname, network) {
* @returns {NetAddress} * @returns {NetAddress}
*/ */
NetAddress.fromHostname = function fromHostname(hostname, network) { static fromHostname(hostname, network) {
return new NetAddress().fromHostname(hostname, network); return new this().fromHostname(hostname, network);
}; }
/** /**
* Inject properties from socket. * Inject properties from socket.
@ -303,13 +294,13 @@ NetAddress.fromHostname = function fromHostname(hostname, network) {
* @param {net.Socket} socket * @param {net.Socket} socket
*/ */
NetAddress.prototype.fromSocket = function fromSocket(socket, network) { fromSocket(socket, network) {
const host = socket.remoteAddress; const host = socket.remoteAddress;
const port = socket.remotePort; const port = socket.remotePort;
assert(typeof host === 'string'); assert(typeof host === 'string');
assert(typeof port === 'number'); assert(typeof port === 'number');
return this.fromHost(IP.normalize(host), port, network); return this.fromHost(IP.normalize(host), port, network);
}; }
/** /**
* Instantiate a network address * Instantiate a network address
@ -318,9 +309,9 @@ NetAddress.prototype.fromSocket = function fromSocket(socket, network) {
* @returns {NetAddress} * @returns {NetAddress}
*/ */
NetAddress.fromSocket = function fromSocket(hostname, network) { static fromSocket(hostname, network) {
return new NetAddress().fromSocket(hostname, network); return new this().fromSocket(hostname, network);
}; }
/** /**
* Inject properties from buffer reader. * Inject properties from buffer reader.
@ -329,7 +320,7 @@ NetAddress.fromSocket = function fromSocket(hostname, network) {
* @param {Boolean?} full - Include timestamp. * @param {Boolean?} full - Include timestamp.
*/ */
NetAddress.prototype.fromReader = function fromReader(br, full) { fromReader(br, full) {
this.time = full ? br.readU32() : 0; this.time = full ? br.readU32() : 0;
this.services = br.readU32(); this.services = br.readU32();
@ -343,7 +334,7 @@ NetAddress.prototype.fromReader = function fromReader(br, full) {
this.hostname = IP.toHostname(this.host, this.port); this.hostname = IP.toHostname(this.host, this.port);
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -352,9 +343,9 @@ NetAddress.prototype.fromReader = function fromReader(br, full) {
* @param {Boolean?} full - Include timestamp. * @param {Boolean?} full - Include timestamp.
*/ */
NetAddress.prototype.fromRaw = function fromRaw(data, full) { fromRaw(data, full) {
return this.fromReader(new BufferReader(data), full); return this.fromReader(new BufferReader(data), full);
}; }
/** /**
* Insantiate a network address from buffer reader. * Insantiate a network address from buffer reader.
@ -363,9 +354,9 @@ NetAddress.prototype.fromRaw = function fromRaw(data, full) {
* @returns {NetAddress} * @returns {NetAddress}
*/ */
NetAddress.fromReader = function fromReader(br, full) { static fromReader(br, full) {
return new NetAddress().fromReader(br, full); return new this().fromReader(br, full);
}; }
/** /**
* Insantiate a network address from serialized data. * Insantiate a network address from serialized data.
@ -374,9 +365,9 @@ NetAddress.fromReader = function fromReader(br, full) {
* @returns {NetAddress} * @returns {NetAddress}
*/ */
NetAddress.fromRaw = function fromRaw(data, full) { static fromRaw(data, full) {
return new NetAddress().fromRaw(data, full); return new this().fromRaw(data, full);
}; }
/** /**
* Write network address to a buffer writer. * Write network address to a buffer writer.
@ -385,7 +376,7 @@ NetAddress.fromRaw = function fromRaw(data, full) {
* @returns {Buffer} * @returns {Buffer}
*/ */
NetAddress.prototype.toWriter = function toWriter(bw, full) { toWriter(bw, full) {
if (full) if (full)
bw.writeU32(this.time); bw.writeU32(this.time);
@ -395,16 +386,16 @@ NetAddress.prototype.toWriter = function toWriter(bw, full) {
bw.writeU16BE(this.port); bw.writeU16BE(this.port);
return bw; return bw;
}; }
/** /**
* Calculate serialization size of address. * Calculate serialization size of address.
* @returns {Number} * @returns {Number}
*/ */
NetAddress.prototype.getSize = function getSize(full) { getSize(full) {
return 26 + (full ? 4 : 0); return 26 + (full ? 4 : 0);
}; }
/** /**
* Serialize network address. * Serialize network address.
@ -412,24 +403,24 @@ NetAddress.prototype.getSize = function getSize(full) {
* @returns {Buffer} * @returns {Buffer}
*/ */
NetAddress.prototype.toRaw = function toRaw(full) { toRaw(full) {
const size = this.getSize(full); const size = this.getSize(full);
return this.toWriter(new StaticWriter(size), full).render(); return this.toWriter(new StaticWriter(size), full).render();
}; }
/** /**
* Convert net address to json-friendly object. * Convert net address to json-friendly object.
* @returns {Object} * @returns {Object}
*/ */
NetAddress.prototype.toJSON = function toJSON() { toJSON() {
return { return {
host: this.host, host: this.host,
port: this.port, port: this.port,
services: this.services, services: this.services,
time: this.time time: this.time
}; };
}; }
/** /**
* Inject properties from json object. * Inject properties from json object.
@ -438,7 +429,7 @@ NetAddress.prototype.toJSON = function toJSON() {
* @returns {NetAddress} * @returns {NetAddress}
*/ */
NetAddress.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
assert((json.port & 0xffff) === json.port); assert((json.port & 0xffff) === json.port);
assert((json.services >>> 0) === json.services); assert((json.services >>> 0) === json.services);
assert((json.time >>> 0) === json.time); assert((json.time >>> 0) === json.time);
@ -449,7 +440,7 @@ NetAddress.prototype.fromJSON = function fromJSON(json) {
this.time = json.time; this.time = json.time;
this.hostname = IP.toHostname(this.host, this.port); this.hostname = IP.toHostname(this.host, this.port);
return this; return this;
}; }
/** /**
* Instantiate net address from json object. * Instantiate net address from json object.
@ -457,22 +448,35 @@ NetAddress.prototype.fromJSON = function fromJSON(json) {
* @returns {NetAddress} * @returns {NetAddress}
*/ */
NetAddress.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new NetAddress().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Inspect the network address. * Inspect the network address.
* @returns {Object} * @returns {Object}
*/ */
NetAddress.prototype.inspect = function inspect() { inspect() {
return '<NetAddress:' return '<NetAddress:'
+ ` hostname=${this.hostname}` + ` hostname=${this.hostname}`
+ ` services=${this.services.toString(2)}` + ` services=${this.services.toString(2)}`
+ ` date=${util.date(this.time)}` + ` date=${util.date(this.time)}`
+ '>'; + '>';
}; }
}
/**
* Default services for
* unknown outbound peers.
* @const {Number}
* @default
*/
NetAddress.DEFAULT_SERVICES = 0
| common.services.NETWORK
| common.services.WITNESS
| common.services.BLOOM;
/* /*
* Expose * Expose

View File

@ -12,19 +12,22 @@ const BufferReader = require('bufio/lib/reader');
const encoding = require('bufio/lib/encoding'); const encoding = require('bufio/lib/encoding');
/** /**
* Outpoint
* Represents a COutPoint. * Represents a COutPoint.
* @alias module:primitives.Outpoint * @alias module:primitives.Outpoint
* @constructor
* @param {Hash?} hash
* @param {Number?} index
* @property {Hash} hash * @property {Hash} hash
* @property {Number} index * @property {Number} index
*/ */
function Outpoint(hash, index) { class Outpoint {
if (!(this instanceof Outpoint)) /**
return new Outpoint(hash, index); * Create an outpoint.
* @constructor
* @param {Hash?} hash
* @param {Number?} index
*/
constructor(hash, index) {
this.hash = encoding.NULL_HASH; this.hash = encoding.NULL_HASH;
this.index = 0xffffffff; this.index = 0xffffffff;
@ -42,14 +45,14 @@ function Outpoint(hash, index) {
* @param {Object} options * @param {Object} options
*/ */
Outpoint.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
assert(options, 'Outpoint data is required.'); assert(options, 'Outpoint data is required.');
assert(typeof options.hash === 'string', 'Hash must be a string.'); assert(typeof options.hash === 'string', 'Hash must be a string.');
assert((options.index >>> 0) === options.index, 'Index must be a uint32.'); assert((options.index >>> 0) === options.index, 'Index must be a uint32.');
this.hash = options.hash; this.hash = options.hash;
this.index = options.index; this.index = options.index;
return this; return this;
}; }
/** /**
* Instantate outpoint from options object. * Instantate outpoint from options object.
@ -57,21 +60,21 @@ Outpoint.prototype.fromOptions = function fromOptions(options) {
* @returns {Outpoint} * @returns {Outpoint}
*/ */
Outpoint.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new Outpoint().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Clone the outpoint. * Clone the outpoint.
* @returns {Outpoint} * @returns {Outpoint}
*/ */
Outpoint.prototype.clone = function clone() { clone() {
const outpoint = new Outpoint(); const outpoint = new this.constructor();
outpoint.hash = this.value; outpoint.hash = this.value;
outpoint.index = this.index; outpoint.index = this.index;
return outpoint; return outpoint;
}; }
/** /**
* Test equality against another outpoint. * Test equality against another outpoint.
@ -79,11 +82,11 @@ Outpoint.prototype.clone = function clone() {
* @returns {Boolean} * @returns {Boolean}
*/ */
Outpoint.prototype.equals = function equals(prevout) { equals(prevout) {
assert(Outpoint.isOutpoint(prevout)); assert(Outpoint.isOutpoint(prevout));
return this.hash === prevout.hash return this.hash === prevout.hash
&& this.index === prevout.index; && this.index === prevout.index;
}; }
/** /**
* Compare against another outpoint (BIP69). * Compare against another outpoint (BIP69).
@ -91,7 +94,7 @@ Outpoint.prototype.equals = function equals(prevout) {
* @returns {Number} * @returns {Number}
*/ */
Outpoint.prototype.compare = function compare(prevout) { compare(prevout) {
assert(Outpoint.isOutpoint(prevout)); assert(Outpoint.isOutpoint(prevout));
const cmp = strcmp(this.txid(), prevout.txid()); const cmp = strcmp(this.txid(), prevout.txid());
@ -100,7 +103,7 @@ Outpoint.prototype.compare = function compare(prevout) {
return cmp; return cmp;
return this.index - prevout.index; return this.index - prevout.index;
}; }
/** /**
* Test whether the outpoint is null (hash of zeroes * Test whether the outpoint is null (hash of zeroes
@ -108,27 +111,27 @@ Outpoint.prototype.compare = function compare(prevout) {
* @returns {Boolean} * @returns {Boolean}
*/ */
Outpoint.prototype.isNull = function isNull() { isNull() {
return this.index === 0xffffffff && this.hash === encoding.NULL_HASH; return this.index === 0xffffffff && this.hash === encoding.NULL_HASH;
}; }
/** /**
* Get little-endian hash. * Get little-endian hash.
* @returns {Hash} * @returns {Hash}
*/ */
Outpoint.prototype.rhash = function rhash() { rhash() {
return encoding.revHex(this.hash); return encoding.revHex(this.hash);
}; }
/** /**
* Get little-endian hash. * Get little-endian hash.
* @returns {Hash} * @returns {Hash}
*/ */
Outpoint.prototype.txid = function txid() { txid() {
return this.rhash(); return this.rhash();
}; }
/** /**
* Serialize outpoint to a key * Serialize outpoint to a key
@ -136,9 +139,9 @@ Outpoint.prototype.txid = function txid() {
* @returns {String} * @returns {String}
*/ */
Outpoint.prototype.toKey = function toKey() { toKey() {
return Outpoint.toKey(this.hash, this.index); return Outpoint.toKey(this.hash, this.index);
}; }
/** /**
* Inject properties from hash table key. * Inject properties from hash table key.
@ -147,12 +150,12 @@ Outpoint.prototype.toKey = function toKey() {
* @returns {Outpoint} * @returns {Outpoint}
*/ */
Outpoint.prototype.fromKey = function fromKey(key) { fromKey(key) {
assert(key.length > 64); assert(key.length > 64);
this.hash = key.slice(0, 64); this.hash = key.slice(0, 64);
this.index = parseInt(key.slice(64), 10); this.index = parseInt(key.slice(64), 10);
return this; return this;
}; }
/** /**
* Instantiate outpoint from hash table key. * Instantiate outpoint from hash table key.
@ -160,38 +163,38 @@ Outpoint.prototype.fromKey = function fromKey(key) {
* @returns {Outpoint} * @returns {Outpoint}
*/ */
Outpoint.fromKey = function fromKey(key) { static fromKey(key) {
return new Outpoint().fromKey(key); return new this().fromKey(key);
}; }
/** /**
* Write outpoint to a buffer writer. * Write outpoint to a buffer writer.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
Outpoint.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
bw.writeHash(this.hash); bw.writeHash(this.hash);
bw.writeU32(this.index); bw.writeU32(this.index);
return bw; return bw;
}; }
/** /**
* Calculate size of outpoint. * Calculate size of outpoint.
* @returns {Number} * @returns {Number}
*/ */
Outpoint.prototype.getSize = function getSize() { getSize() {
return 36; return 36;
}; }
/** /**
* Serialize outpoint. * Serialize outpoint.
* @returns {Buffer} * @returns {Buffer}
*/ */
Outpoint.prototype.toRaw = function toRaw() { toRaw() {
return this.toWriter(new StaticWriter(36)).render(); return this.toWriter(new StaticWriter(36)).render();
}; }
/** /**
* Inject properties from buffer reader. * Inject properties from buffer reader.
@ -199,11 +202,11 @@ Outpoint.prototype.toRaw = function toRaw() {
* @param {BufferReader} br * @param {BufferReader} br
*/ */
Outpoint.prototype.fromReader = function fromReader(br) { fromReader(br) {
this.hash = br.readHash('hex'); this.hash = br.readHash('hex');
this.index = br.readU32(); this.index = br.readU32();
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -211,9 +214,9 @@ Outpoint.prototype.fromReader = function fromReader(br) {
* @param {Buffer} data * @param {Buffer} data
*/ */
Outpoint.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
return this.fromReader(new BufferReader(data)); return this.fromReader(new BufferReader(data));
}; }
/** /**
* Instantiate outpoint from a buffer reader. * Instantiate outpoint from a buffer reader.
@ -221,9 +224,9 @@ Outpoint.prototype.fromRaw = function fromRaw(data) {
* @returns {Outpoint} * @returns {Outpoint}
*/ */
Outpoint.fromReader = function fromReader(br) { static fromReader(br) {
return new Outpoint().fromReader(br); return new this().fromReader(br);
}; }
/** /**
* Instantiate outpoint from serialized data. * Instantiate outpoint from serialized data.
@ -231,9 +234,9 @@ Outpoint.fromReader = function fromReader(br) {
* @returns {Outpoint} * @returns {Outpoint}
*/ */
Outpoint.fromRaw = function fromRaw(data) { static fromRaw(data) {
return new Outpoint().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Inject properties from json object. * Inject properties from json object.
@ -241,14 +244,14 @@ Outpoint.fromRaw = function fromRaw(data) {
* @params {Object} json * @params {Object} json
*/ */
Outpoint.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
assert(json, 'Outpoint data is required.'); assert(json, 'Outpoint data is required.');
assert(typeof json.hash === 'string', 'Hash must be a string.'); assert(typeof json.hash === 'string', 'Hash must be a string.');
assert((json.index >>> 0) === json.index, 'Index must be a uint32.'); assert((json.index >>> 0) === json.index, 'Index must be a uint32.');
this.hash = encoding.revHex(json.hash); this.hash = encoding.revHex(json.hash);
this.index = json.index; this.index = json.index;
return this; return this;
}; }
/** /**
* Convert the outpoint to an object suitable * Convert the outpoint to an object suitable
@ -258,12 +261,12 @@ Outpoint.prototype.fromJSON = function fromJSON(json) {
* @returns {Object} * @returns {Object}
*/ */
Outpoint.prototype.toJSON = function toJSON() { toJSON() {
return { return {
hash: encoding.revHex(this.hash), hash: encoding.revHex(this.hash),
index: this.index index: this.index
}; };
}; }
/** /**
* Instantiate outpoint from json object. * Instantiate outpoint from json object.
@ -271,9 +274,9 @@ Outpoint.prototype.toJSON = function toJSON() {
* @returns {Outpoint} * @returns {Outpoint}
*/ */
Outpoint.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new Outpoint().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Inject properties from tx. * Inject properties from tx.
@ -282,14 +285,14 @@ Outpoint.fromJSON = function fromJSON(json) {
* @param {Number} index * @param {Number} index
*/ */
Outpoint.prototype.fromTX = function fromTX(tx, index) { fromTX(tx, index) {
assert(tx); assert(tx);
assert(typeof index === 'number'); assert(typeof index === 'number');
assert(index >= 0); assert(index >= 0);
this.hash = tx.hash('hex'); this.hash = tx.hash('hex');
this.index = index; this.index = index;
return this; return this;
}; }
/** /**
* Instantiate outpoint from tx. * Instantiate outpoint from tx.
@ -298,9 +301,9 @@ Outpoint.prototype.fromTX = function fromTX(tx, index) {
* @returns {Outpoint} * @returns {Outpoint}
*/ */
Outpoint.fromTX = function fromTX(tx, index) { static fromTX(tx, index) {
return new Outpoint().fromTX(tx, index); return new this().fromTX(tx, index);
}; }
/** /**
* Serialize outpoint to a key * Serialize outpoint to a key
@ -310,21 +313,21 @@ Outpoint.fromTX = function fromTX(tx, index) {
* @returns {String} * @returns {String}
*/ */
Outpoint.toKey = function toKey(hash, index) { static toKey(hash, index) {
assert(typeof hash === 'string'); assert(typeof hash === 'string');
assert(hash.length === 64); assert(hash.length === 64);
assert(index >= 0); assert(index >= 0);
return hash + index; return hash + index;
}; }
/** /**
* Convert the outpoint to a user-friendly string. * Convert the outpoint to a user-friendly string.
* @returns {String} * @returns {String}
*/ */
Outpoint.prototype.inspect = function inspect() { inspect() {
return `<Outpoint: ${this.rhash()}/${this.index}>`; return `<Outpoint: ${this.rhash()}/${this.index}>`;
}; }
/** /**
* Test an object to see if it is an outpoint. * Test an object to see if it is an outpoint.
@ -332,9 +335,10 @@ Outpoint.prototype.inspect = function inspect() {
* @returns {Boolean} * @returns {Boolean}
*/ */
Outpoint.isOutpoint = function isOutpoint(obj) { static isOutpoint(obj) {
return obj instanceof Outpoint; return obj instanceof Outpoint;
}; }
}
/* /*
* Helpers * Helpers

View File

@ -20,16 +20,18 @@ const policy = require('../protocol/policy');
/** /**
* Represents a transaction output. * Represents a transaction output.
* @alias module:primitives.Output * @alias module:primitives.Output
* @constructor * @property {Amount} value
* @param {NakedOutput} options
* @property {Amount} value - Value in satoshis.
* @property {Script} script * @property {Script} script
*/ */
function Output(options) { class Output {
if (!(this instanceof Output)) /**
return new Output(options); * Create an output.
* @constructor
* @param {Object?} options
*/
constructor(options) {
this.value = 0; this.value = 0;
this.script = new Script(); this.script = new Script();
@ -43,7 +45,7 @@ function Output(options) {
* @param {NakedOutput} options * @param {NakedOutput} options
*/ */
Output.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
assert(options, 'Output data is required.'); assert(options, 'Output data is required.');
if (options.value) { if (options.value) {
@ -59,7 +61,7 @@ Output.prototype.fromOptions = function fromOptions(options) {
this.script.fromAddress(options.address); this.script.fromAddress(options.address);
return this; return this;
}; }
/** /**
* Instantiate output from options object. * Instantiate output from options object.
@ -67,9 +69,9 @@ Output.prototype.fromOptions = function fromOptions(options) {
* @returns {Output} * @returns {Output}
*/ */
Output.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new Output().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Inject properties from script/value pair. * Inject properties from script/value pair.
@ -79,7 +81,7 @@ Output.fromOptions = function fromOptions(options) {
* @returns {Output} * @returns {Output}
*/ */
Output.prototype.fromScript = function fromScript(script, value) { fromScript(script, value) {
if (typeof script === 'string') if (typeof script === 'string')
script = Address.fromString(script); script = Address.fromString(script);
@ -93,7 +95,7 @@ Output.prototype.fromScript = function fromScript(script, value) {
this.value = value; this.value = value;
return this; return this;
}; }
/** /**
* Instantiate output from script/value pair. * Instantiate output from script/value pair.
@ -102,21 +104,21 @@ Output.prototype.fromScript = function fromScript(script, value) {
* @returns {Output} * @returns {Output}
*/ */
Output.fromScript = function fromScript(script, value) { static fromScript(script, value) {
return new Output().fromScript(script, value); return new this().fromScript(script, value);
}; }
/** /**
* Clone the output. * Clone the output.
* @returns {Output} * @returns {Output}
*/ */
Output.prototype.clone = function clone() { clone() {
const output = new Output(); const output = new this.constructor();
output.value = this.value; output.value = this.value;
output.script.inject(this.script); output.script.inject(this.script);
return output; return output;
}; }
/** /**
* Test equality against another output. * Test equality against another output.
@ -124,11 +126,11 @@ Output.prototype.clone = function clone() {
* @returns {Boolean} * @returns {Boolean}
*/ */
Output.prototype.equals = function equals(output) { equals(output) {
assert(Output.isOutput(output)); assert(Output.isOutput(output));
return this.value === output.value return this.value === output.value
&& this.script.equals(output.script); && this.script.equals(output.script);
}; }
/** /**
* Compare against another output (BIP69). * Compare against another output (BIP69).
@ -136,7 +138,7 @@ Output.prototype.equals = function equals(output) {
* @returns {Number} * @returns {Number}
*/ */
Output.prototype.compare = function compare(output) { compare(output) {
assert(Output.isOutput(output)); assert(Output.isOutput(output));
const cmp = this.value - output.value; const cmp = this.value - output.value;
@ -145,25 +147,25 @@ Output.prototype.compare = function compare(output) {
return cmp; return cmp;
return this.script.compare(output.script); return this.script.compare(output.script);
}; }
/** /**
* Get the script type as a string. * Get the script type as a string.
* @returns {ScriptType} type * @returns {ScriptType} type
*/ */
Output.prototype.getType = function getType() { getType() {
return Script.typesByVal[this.script.getType()].toLowerCase(); return Script.typesByVal[this.script.getType()].toLowerCase();
}; }
/** /**
* Get the address. * Get the address.
* @returns {Address} address * @returns {Address} address
*/ */
Output.prototype.getAddress = function getAddress() { getAddress() {
return this.script.getAddress(); return this.script.getAddress();
}; }
/** /**
* Get the address hash. * Get the address hash.
@ -171,28 +173,28 @@ Output.prototype.getAddress = function getAddress() {
* @returns {Hash} hash * @returns {Hash} hash
*/ */
Output.prototype.getHash = function getHash(enc) { getHash(enc) {
const addr = this.getAddress(); const addr = this.getAddress();
if (!addr) if (!addr)
return null; return null;
return addr.getHash(enc); return addr.getHash(enc);
}; }
/** /**
* Convert the input to a more user-friendly object. * Convert the input to a more user-friendly object.
* @returns {Object} * @returns {Object}
*/ */
Output.prototype.inspect = function inspect() { inspect() {
return { return {
type: this.getType(), type: this.getType(),
value: Amount.btc(this.value), value: Amount.btc(this.value),
script: this.script, script: this.script,
address: this.getAddress() address: this.getAddress()
}; };
}; }
/** /**
* Convert the output to an object suitable * Convert the output to an object suitable
@ -200,9 +202,9 @@ Output.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
Output.prototype.toJSON = function toJSON() { toJSON() {
return this.getJSON(); return this.getJSON();
}; }
/** /**
* Convert the output to an object suitable * Convert the output to an object suitable
@ -211,7 +213,7 @@ Output.prototype.toJSON = function toJSON() {
* @returns {Object} * @returns {Object}
*/ */
Output.prototype.getJSON = function getJSON(network) { getJSON(network) {
let addr = this.getAddress(); let addr = this.getAddress();
network = Network.get(network); network = Network.get(network);
@ -224,7 +226,7 @@ Output.prototype.getJSON = function getJSON(network) {
script: this.script.toJSON(), script: this.script.toJSON(),
address: addr address: addr
}; };
}; }
/** /**
* Calculate the dust threshold for this * Calculate the dust threshold for this
@ -233,7 +235,7 @@ Output.prototype.getJSON = function getJSON(network) {
* @returns {Amount} * @returns {Amount}
*/ */
Output.prototype.getDustThreshold = function getDustThreshold(rate) { getDustThreshold(rate) {
const scale = consensus.WITNESS_SCALE_FACTOR; const scale = consensus.WITNESS_SCALE_FACTOR;
if (this.script.isUnspendable()) if (this.script.isUnspendable())
@ -249,16 +251,16 @@ Output.prototype.getDustThreshold = function getDustThreshold(rate) {
} }
return 3 * policy.getMinFee(size, rate); return 3 * policy.getMinFee(size, rate);
}; }
/** /**
* Calculate size of serialized output. * Calculate size of serialized output.
* @returns {Number} * @returns {Number}
*/ */
Output.prototype.getSize = function getSize() { getSize() {
return 8 + this.script.getVarSize(); return 8 + this.script.getVarSize();
}; }
/** /**
* Test whether the output should be considered dust. * Test whether the output should be considered dust.
@ -266,9 +268,9 @@ Output.prototype.getSize = function getSize() {
* @returns {Boolean} * @returns {Boolean}
*/ */
Output.prototype.isDust = function isDust(rate) { isDust(rate) {
return this.value < this.getDustThreshold(rate); return this.value < this.getDustThreshold(rate);
}; }
/** /**
* Inject properties from a JSON object. * Inject properties from a JSON object.
@ -276,14 +278,14 @@ Output.prototype.isDust = function isDust(rate) {
* @param {Object} json * @param {Object} json
*/ */
Output.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
assert(json, 'Output data is required.'); assert(json, 'Output data is required.');
assert(Number.isSafeInteger(json.value) && json.value >= 0, assert(Number.isSafeInteger(json.value) && json.value >= 0,
'Value must be a uint64.'); 'Value must be a uint64.');
this.value = json.value; this.value = json.value;
this.script.fromJSON(json.script); this.script.fromJSON(json.script);
return this; return this;
}; }
/** /**
* Instantiate an Output from a jsonified output object. * Instantiate an Output from a jsonified output object.
@ -291,20 +293,20 @@ Output.prototype.fromJSON = function fromJSON(json) {
* @returns {Output} * @returns {Output}
*/ */
Output.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new Output().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Write the output to a buffer writer. * Write the output to a buffer writer.
* @param {BufferWriter} bw * @param {BufferWriter} bw
*/ */
Output.prototype.toWriter = function toWriter(bw) { toWriter(bw) {
bw.writeI64(this.value); bw.writeI64(this.value);
bw.writeVarBytes(this.script.toRaw()); bw.writeVarBytes(this.script.toRaw());
return bw; return bw;
}; }
/** /**
* Serialize the output. * Serialize the output.
@ -312,10 +314,10 @@ Output.prototype.toWriter = function toWriter(bw) {
* @returns {Buffer|String} * @returns {Buffer|String}
*/ */
Output.prototype.toRaw = function toRaw() { toRaw() {
const size = this.getSize(); const size = this.getSize();
return this.toWriter(new StaticWriter(size)).render(); return this.toWriter(new StaticWriter(size)).render();
}; }
/** /**
* Inject properties from buffer reader. * Inject properties from buffer reader.
@ -323,11 +325,11 @@ Output.prototype.toRaw = function toRaw() {
* @param {BufferReader} br * @param {BufferReader} br
*/ */
Output.prototype.fromReader = function fromReader(br) { fromReader(br) {
this.value = br.readI64(); this.value = br.readI64();
this.script.fromRaw(br.readVarBytes()); this.script.fromRaw(br.readVarBytes());
return this; return this;
}; }
/** /**
* Inject properties from serialized data. * Inject properties from serialized data.
@ -335,9 +337,9 @@ Output.prototype.fromReader = function fromReader(br) {
* @param {Buffer} data * @param {Buffer} data
*/ */
Output.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
return this.fromReader(new BufferReader(data)); return this.fromReader(new BufferReader(data));
}; }
/** /**
* Instantiate an output from a buffer reader. * Instantiate an output from a buffer reader.
@ -345,9 +347,9 @@ Output.prototype.fromRaw = function fromRaw(data) {
* @returns {Output} * @returns {Output}
*/ */
Output.fromReader = function fromReader(br) { static fromReader(br) {
return new Output().fromReader(br); return new this().fromReader(br);
}; }
/** /**
* Instantiate an output from a serialized Buffer. * Instantiate an output from a serialized Buffer.
@ -356,11 +358,11 @@ Output.fromReader = function fromReader(br) {
* @returns {Output} * @returns {Output}
*/ */
Output.fromRaw = function fromRaw(data, enc) { static fromRaw(data, enc) {
if (typeof data === 'string') if (typeof data === 'string')
data = Buffer.from(data, enc); data = Buffer.from(data, enc);
return new Output().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Test an object to see if it is an Output. * Test an object to see if it is an Output.
@ -368,9 +370,10 @@ Output.fromRaw = function fromRaw(data, enc) {
* @returns {Boolean} * @returns {Boolean}
*/ */
Output.isOutput = function isOutput(obj) { static isOutput(obj) {
return obj instanceof Output; return obj instanceof Output;
}; }
}
/* /*
* Expose * Expose

File diff suppressed because it is too large Load Diff

View File

@ -14,16 +14,19 @@ const BufferReader = require('bufio/lib/reader');
const encoding = require('bufio/lib/encoding'); const encoding = require('bufio/lib/encoding');
/** /**
* TXMeta
* An extended transaction object. * An extended transaction object.
* @alias module:primitives.TXMeta * @alias module:primitives.TXMeta
* @constructor
* @param {Object} options
*/ */
function TXMeta(options) { class TXMeta {
if (!(this instanceof TXMeta)) /**
return new TXMeta(options); * Create an extended transaction.
* @constructor
* @param {Object?} options
*/
constructor(options) {
this.tx = new TX(); this.tx = new TX();
this.mtime = util.now(); this.mtime = util.now();
this.height = -1; this.height = -1;
@ -41,7 +44,7 @@ function TXMeta(options) {
* @param {Object} options * @param {Object} options
*/ */
TXMeta.prototype.fromOptions = function fromOptions(options) { fromOptions(options) {
if (options.tx) { if (options.tx) {
assert(options.tx instanceof TX); assert(options.tx instanceof TX);
this.tx = options.tx; this.tx = options.tx;
@ -73,7 +76,7 @@ TXMeta.prototype.fromOptions = function fromOptions(options) {
} }
return this; return this;
}; }
/** /**
* Instantiate TXMeta from options. * Instantiate TXMeta from options.
@ -81,9 +84,9 @@ TXMeta.prototype.fromOptions = function fromOptions(options) {
* @returns {TXMeta} * @returns {TXMeta}
*/ */
TXMeta.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new TXMeta().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Inject properties from options object. * Inject properties from options object.
@ -91,7 +94,7 @@ TXMeta.fromOptions = function fromOptions(options) {
* @param {Object} options * @param {Object} options
*/ */
TXMeta.prototype.fromTX = function fromTX(tx, entry, index) { fromTX(tx, entry, index) {
this.tx = tx; this.tx = tx;
if (entry) { if (entry) {
this.height = entry.height; this.height = entry.height;
@ -100,7 +103,7 @@ TXMeta.prototype.fromTX = function fromTX(tx, entry, index) {
this.index = index; this.index = index;
} }
return this; return this;
}; }
/** /**
* Instantiate TXMeta from options. * Instantiate TXMeta from options.
@ -108,41 +111,41 @@ TXMeta.prototype.fromTX = function fromTX(tx, entry, index) {
* @returns {TXMeta} * @returns {TXMeta}
*/ */
TXMeta.fromTX = function fromTX(tx, entry, index) { static fromTX(tx, entry, index) {
return new TXMeta().fromTX(tx, entry, index); return new this().fromTX(tx, entry, index);
}; }
/** /**
* Inspect the transaction. * Inspect the transaction.
* @returns {Object} * @returns {Object}
*/ */
TXMeta.prototype.inspect = function inspect() { inspect() {
return this.format(); return this.format();
}; }
/** /**
* Inspect the transaction. * Inspect the transaction.
* @returns {Object} * @returns {Object}
*/ */
TXMeta.prototype.format = function format(view) { format(view) {
const data = this.tx.format(view, null, this.index); const data = this.tx.format(view, null, this.index);
data.mtime = this.mtime; data.mtime = this.mtime;
data.height = this.height; data.height = this.height;
data.block = this.block ? encoding.revHex(this.block) : null; data.block = this.block ? encoding.revHex(this.block) : null;
data.time = this.time; data.time = this.time;
return data; return data;
}; }
/** /**
* Convert transaction to JSON. * Convert transaction to JSON.
* @returns {Object} * @returns {Object}
*/ */
TXMeta.prototype.toJSON = function toJSON() { toJSON() {
return this.getJSON(); return this.getJSON();
}; }
/** /**
* Convert the transaction to an object suitable * Convert the transaction to an object suitable
@ -152,7 +155,7 @@ TXMeta.prototype.toJSON = function toJSON() {
* @returns {Object} * @returns {Object}
*/ */
TXMeta.prototype.getJSON = function getJSON(network, view, chainHeight) { getJSON(network, view, chainHeight) {
const json = this.tx.getJSON(network, view, null, this.index); const json = this.tx.getJSON(network, view, null, this.index);
json.mtime = this.mtime; json.mtime = this.mtime;
json.height = this.height; json.height = this.height;
@ -164,7 +167,7 @@ TXMeta.prototype.getJSON = function getJSON(network, view, chainHeight) {
json.confirmations = chainHeight - this.height + 1; json.confirmations = chainHeight - this.height + 1;
return json; return json;
}; }
/** /**
* Inject properties from a json object. * Inject properties from a json object.
@ -172,7 +175,7 @@ TXMeta.prototype.getJSON = function getJSON(network, view, chainHeight) {
* @param {Object} json * @param {Object} json
*/ */
TXMeta.prototype.fromJSON = function fromJSON(json) { fromJSON(json) {
this.tx.fromJSON(json); this.tx.fromJSON(json);
assert((json.mtime >>> 0) === json.mtime); assert((json.mtime >>> 0) === json.mtime);
@ -187,7 +190,7 @@ TXMeta.prototype.fromJSON = function fromJSON(json) {
this.index = json.index; this.index = json.index;
return this; return this;
}; }
/** /**
* Instantiate a transaction from a * Instantiate a transaction from a
@ -196,16 +199,16 @@ TXMeta.prototype.fromJSON = function fromJSON(json) {
* @returns {TX} * @returns {TX}
*/ */
TXMeta.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new TXMeta().fromJSON(JSON); return new this().fromJSON(JSON);
}; }
/** /**
* Calculate serialization size. * Calculate serialization size.
* @returns {Number} * @returns {Number}
*/ */
TXMeta.prototype.getSize = function getSize() { getSize() {
let size = 0; let size = 0;
size += this.tx.getSize(); size += this.tx.getSize();
@ -220,7 +223,7 @@ TXMeta.prototype.getSize = function getSize() {
} }
return size; return size;
}; }
/** /**
* Serialize a transaction to "extended format". * Serialize a transaction to "extended format".
@ -231,7 +234,7 @@ TXMeta.prototype.getSize = function getSize() {
* @returns {Buffer} * @returns {Buffer}
*/ */
TXMeta.prototype.toRaw = function toRaw() { toRaw() {
const size = this.getSize(); const size = this.getSize();
const bw = new StaticWriter(size); const bw = new StaticWriter(size);
@ -250,7 +253,7 @@ TXMeta.prototype.toRaw = function toRaw() {
} }
return bw.render(); return bw.render();
}; }
/** /**
* Inject properties from "extended" serialization format. * Inject properties from "extended" serialization format.
@ -258,7 +261,7 @@ TXMeta.prototype.toRaw = function toRaw() {
* @param {Buffer} data * @param {Buffer} data
*/ */
TXMeta.prototype.fromRaw = function fromRaw(data) { fromRaw(data) {
const br = new BufferReader(data); const br = new BufferReader(data);
this.tx.fromReader(br); this.tx.fromReader(br);
@ -275,7 +278,7 @@ TXMeta.prototype.fromRaw = function fromRaw(data) {
} }
return this; return this;
}; }
/** /**
* Instantiate a transaction from a Buffer * Instantiate a transaction from a Buffer
@ -285,11 +288,11 @@ TXMeta.prototype.fromRaw = function fromRaw(data) {
* @returns {TX} * @returns {TX}
*/ */
TXMeta.fromRaw = function fromRaw(data, enc) { static fromRaw(data, enc) {
if (typeof data === 'string') if (typeof data === 'string')
data = Buffer.from(data, enc); data = Buffer.from(data, enc);
return new TXMeta().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Test whether an object is an TXMeta. * Test whether an object is an TXMeta.
@ -297,9 +300,10 @@ TXMeta.fromRaw = function fromRaw(data, enc) {
* @returns {Boolean} * @returns {Boolean}
*/ */
TXMeta.isTXMeta = function isTXMeta(obj) { static isTXMeta(obj) {
return obj instanceof TXMeta; return obj instanceof TXMeta;
}; }
}
/* /*
* Expose * Expose

View File

@ -12,17 +12,21 @@ const KeyRing = require('../primitives/keyring');
const Path = require('./path'); const Path = require('./path');
/** /**
* Wallet Key
* Represents a key ring which amounts to an address. * Represents a key ring which amounts to an address.
* @alias module:wallet.WalletKey * @alias module:wallet.WalletKey
* @constructor * @extends KeyRing
* @param {Object} options
*/ */
function WalletKey(options) { class WalletKey extends KeyRing {
if (!(this instanceof WalletKey)) /**
return new WalletKey(options); * Create a wallet key.
* @constructor
* @param {Object?} options
*/
KeyRing.call(this, options); constructor(options) {
super(options);
this.keyType = Path.types.HD; this.keyType = Path.types.HD;
@ -32,17 +36,15 @@ function WalletKey(options) {
this.index = -1; this.index = -1;
} }
Object.setPrototypeOf(WalletKey.prototype, KeyRing.prototype);
/** /**
* Instantiate key ring from options. * Instantiate key ring from options.
* @param {Object} options * @param {Object} options
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromOptions = function fromOptions(options) { static fromOptions(options) {
return new WalletKey().fromOptions(options); return new this().fromOptions(options);
}; }
/** /**
* Instantiate wallet key from a private key. * Instantiate wallet key from a private key.
@ -51,9 +53,9 @@ WalletKey.fromOptions = function fromOptions(options) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromPrivate = function fromPrivate(key, compressed) { static fromPrivate(key, compressed) {
return new WalletKey().fromPrivate(key, compressed); return new this().fromPrivate(key, compressed);
}; }
/** /**
* Generate a wallet key. * Generate a wallet key.
@ -61,9 +63,9 @@ WalletKey.fromPrivate = function fromPrivate(key, compressed) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.generate = function generate(compressed) { static generate(compressed) {
return new WalletKey().generate(compressed); return new this().generate(compressed);
}; }
/** /**
* Instantiate wallet key from a public key. * Instantiate wallet key from a public key.
@ -71,9 +73,9 @@ WalletKey.generate = function generate(compressed) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromPublic = function fromPublic(key) { static fromPublic(key) {
return new WalletKey().fromPublic(key); return new this().fromPublic(key);
}; }
/** /**
* Instantiate wallet key from a public key. * Instantiate wallet key from a public key.
@ -81,9 +83,9 @@ WalletKey.fromPublic = function fromPublic(key) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromKey = function fromKey(key, compressed) { static fromKey(key, compressed) {
return new WalletKey().fromKey(key, compressed); return new this().fromKey(key, compressed);
}; }
/** /**
* Instantiate wallet key from script. * Instantiate wallet key from script.
@ -92,9 +94,9 @@ WalletKey.fromKey = function fromKey(key, compressed) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromScript = function fromScript(key, script, compressed) { static fromScript(key, script, compressed) {
return new WalletKey().fromScript(key, script, compressed); return new this().fromScript(key, script, compressed);
}; }
/** /**
* Instantiate a wallet key from a serialized CBitcoinSecret. * Instantiate a wallet key from a serialized CBitcoinSecret.
@ -103,16 +105,16 @@ WalletKey.fromScript = function fromScript(key, script, compressed) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromSecret = function fromSecret(data, network) { static fromSecret(data, network) {
return new WalletKey().fromSecret(data, network); return new this().fromSecret(data, network);
}; }
/** /**
* Convert an WalletKey to a more json-friendly object. * Convert an WalletKey to a more json-friendly object.
* @returns {Object} * @returns {Object}
*/ */
WalletKey.prototype.toJSON = function toJSON(network) { toJSON(network) {
return { return {
name: this.name, name: this.name,
account: this.account, account: this.account,
@ -126,7 +128,7 @@ WalletKey.prototype.toJSON = function toJSON(network) {
type: Address.typesByVal[this.getType()].toLowerCase(), type: Address.typesByVal[this.getType()].toLowerCase(),
address: this.getAddress('string', network) address: this.getAddress('string', network)
}; };
}; }
/** /**
* Instantiate an WalletKey from a jsonified transaction object. * Instantiate an WalletKey from a jsonified transaction object.
@ -134,9 +136,9 @@ WalletKey.prototype.toJSON = function toJSON(network) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromJSON = function fromJSON(json) { static fromJSON(json) {
return new WalletKey().fromJSON(json); return new this().fromJSON(json);
}; }
/** /**
* Instantiate a wallet key from serialized data. * Instantiate a wallet key from serialized data.
@ -144,9 +146,9 @@ WalletKey.fromJSON = function fromJSON(json) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromRaw = function fromRaw(data) { static fromRaw(data) {
return new WalletKey().fromRaw(data); return new this().fromRaw(data);
}; }
/** /**
* Inject properties from hd key. * Inject properties from hd key.
@ -158,7 +160,7 @@ WalletKey.fromRaw = function fromRaw(data) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.prototype.fromHD = function fromHD(account, key, branch, index) { fromHD(account, key, branch, index) {
this.keyType = Path.types.HD; this.keyType = Path.types.HD;
this.name = account.name; this.name = account.name;
this.account = account.accountIndex; this.account = account.accountIndex;
@ -171,7 +173,7 @@ WalletKey.prototype.fromHD = function fromHD(account, key, branch, index) {
return this.fromPrivate(key.privateKey); return this.fromPrivate(key.privateKey);
return this.fromPublic(key.publicKey); return this.fromPublic(key.publicKey);
}; }
/** /**
* Instantiate a wallet key from hd key. * Instantiate a wallet key from hd key.
@ -182,9 +184,9 @@ WalletKey.prototype.fromHD = function fromHD(account, key, branch, index) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromHD = function fromHD(account, key, branch, index) { static fromHD(account, key, branch, index) {
return new WalletKey().fromHD(account, key, branch, index); return new this().fromHD(account, key, branch, index);
}; }
/** /**
* Inject properties from imported data. * Inject properties from imported data.
@ -194,13 +196,13 @@ WalletKey.fromHD = function fromHD(account, key, branch, index) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.prototype.fromImport = function fromImport(account, data) { fromImport(account, data) {
this.keyType = Path.types.KEY; this.keyType = Path.types.KEY;
this.name = account.name; this.name = account.name;
this.account = account.accountIndex; this.account = account.accountIndex;
this.witness = account.witness; this.witness = account.witness;
return this.fromRaw(data); return this.fromRaw(data);
}; }
/** /**
* Instantiate a wallet key from imported data. * Instantiate a wallet key from imported data.
@ -209,9 +211,9 @@ WalletKey.prototype.fromImport = function fromImport(account, data) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromImport = function fromImport(account, data) { static fromImport(account, data) {
return new WalletKey().fromImport(account, data); return new this().fromImport(account, data);
}; }
/** /**
* Inject properties from key. * Inject properties from key.
@ -221,13 +223,13 @@ WalletKey.fromImport = function fromImport(account, data) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.prototype.fromRing = function fromRing(account, ring) { fromRing(account, ring) {
this.keyType = Path.types.KEY; this.keyType = Path.types.KEY;
this.name = account.name; this.name = account.name;
this.account = account.accountIndex; this.account = account.accountIndex;
this.witness = account.witness; this.witness = account.witness;
return this.fromOptions(ring); return this.fromOptions(ring);
}; }
/** /**
* Instantiate a wallet key from regular key. * Instantiate a wallet key from regular key.
@ -236,16 +238,16 @@ WalletKey.prototype.fromRing = function fromRing(account, ring) {
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromRing = function fromRing(account, ring) { static fromRing(account, ring) {
return new WalletKey().fromRing(account, ring); return new this().fromRing(account, ring);
}; }
/** /**
* Convert wallet key to a path. * Convert wallet key to a path.
* @returns {Path} * @returns {Path}
*/ */
WalletKey.prototype.toPath = function toPath() { toPath() {
const path = new Path(); const path = new Path();
path.name = this.name; path.name = this.name;
@ -268,7 +270,7 @@ WalletKey.prototype.toPath = function toPath() {
path.hash = this.getHash('hex'); path.hash = this.getHash('hex');
return path; return path;
}; }
/** /**
* Test whether an object is a WalletKey. * Test whether an object is a WalletKey.
@ -276,9 +278,10 @@ WalletKey.prototype.toPath = function toPath() {
* @returns {Boolean} * @returns {Boolean}
*/ */
WalletKey.isWalletKey = function isWalletKey(obj) { static isWalletKey(obj) {
return obj instanceof WalletKey; return obj instanceof WalletKey;
}; }
}
/* /*
* Expose * Expose

View File

@ -168,7 +168,7 @@ MemWallet.prototype.getUndo = function getUndo(key) {
}; };
MemWallet.prototype.addCoin = function addCoin(coin) { MemWallet.prototype.addCoin = function addCoin(coin) {
const op = Outpoint(coin.hash, coin.index); const op = new Outpoint(coin.hash, coin.index);
const key = op.toKey(); const key = op.toKey();
this.filter.add(op.toRaw()); this.filter.add(op.toRaw());
@ -301,7 +301,7 @@ MemWallet.prototype.removeTX = function removeTX(tx, height) {
return false; return false;
for (let i = 0; i < tx.outputs.length; i++) { for (let i = 0; i < tx.outputs.length; i++) {
const op = Outpoint(hash, i).toKey(); const op = new Outpoint(hash, i).toKey();
const coin = this.getCoin(op); const coin = this.getCoin(op);
if (!coin) if (!coin)