optimize sighashing. default values for every constructor.

This commit is contained in:
Christopher Jeffrey 2016-06-28 18:11:04 -07:00
parent 05b83fe1c8
commit b6ce94cec3
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
24 changed files with 750 additions and 348 deletions

View File

@ -39,8 +39,8 @@ function AbstractBlock(options) {
return new AbstractBlock(options);
this.version = 1;
this.prevBlock = null;
this.merkleRoot = null;
this.prevBlock = constants.NULL_HASH;
this.merkleRoot = constants.NULL_HASH;
this.ts = 0;
this.bits = 0;
this.nonce = 0;
@ -80,16 +80,19 @@ AbstractBlock.prototype.parseOptions = function parseOptions(options) {
this.ts = options.ts;
this.bits = options.bits;
this.nonce = options.nonce;
this.totalTX = options.totalTX || 0;
this.height = options.height != null ? options.height : -1;
this.txs = null;
this.mutable = !!options.mutable;
if (options.totalTX != null) {
assert(utils.isNumber(options.totalTX));
this.totalTX = options.totalTX;
}
this._valid = null;
this._hash = null;
this._size = null;
this._witnessSize = null;
if (options.height != null) {
assert(utils.isNumber(options.height));
this.height = options.height;
}
if (options.mutable != null)
this.mutable = !!options.mutable;
return this;
};
@ -102,7 +105,6 @@ AbstractBlock.prototype.parseOptions = function parseOptions(options) {
AbstractBlock.prototype.parseJSON = function parseJSON(json) {
assert(json, 'Block data is required.');
assert(utils.isNumber(json.height));
assert(utils.isNumber(json.version));
assert(typeof json.prevBlock === 'string');
assert(typeof json.merkleRoot === 'string');
@ -110,8 +112,8 @@ AbstractBlock.prototype.parseJSON = function parseJSON(json) {
assert(utils.isNumber(json.bits));
assert(utils.isNumber(json.nonce));
assert(utils.isNumber(json.totalTX));
assert(utils.isNumber(json.height));
this.height = json.height;
this.version = json.version;
this.prevBlock = utils.revHex(json.prevBlock);
this.merkleRoot = utils.revHex(json.merkleRoot);
@ -119,6 +121,7 @@ AbstractBlock.prototype.parseJSON = function parseJSON(json) {
this.bits = json.bits;
this.nonce = json.nonce;
this.totalTX = json.totalTX;
this.height = json.height;
return this;
};

View File

@ -9,6 +9,7 @@
var bcoin = require('./env');
var networks = bcoin.protocol.network;
var constants = bcoin.protocol.constants;
var utils = require('./utils');
var assert = utils.assert;
var BufferWriter = require('./writer');
@ -35,10 +36,10 @@ function Address(options) {
if (!(this instanceof Address))
return new Address(options);
this.hash = null;
this.type = null;
this.version = null;
this.network = null;
this.hash = constants.ZERO_HASH160;
this.type = 'pubkeyhash';
this.version = -1;
this.network = bcoin.network.get().type;
if (options)
this.fromOptions(options);
@ -51,13 +52,23 @@ function Address(options) {
*/
Address.prototype.fromOptions = function fromOptions(options) {
assert(options.hash);
this.hash = options.hash;
this.type = options.type || 'pubkeyhash';
this.version = options.version == null ? -1 : options.version;
this.network = bcoin.network.get(options.network).type;
if (options.type)
this.type = options.type;
if (options.version != null)
this.version = options.version;
if (options.network)
this.network = bcoin.network.get(options.network).type;
if (typeof this.hash === 'string')
this.hash = new Buffer(this.hash, 'hex');
return this;
};
/**

View File

@ -49,12 +49,23 @@ CompactBlock.prototype._verify = function _verify(ret) {
};
CompactBlock.prototype.fromOptions = function fromOptions(options) {
assert(bn.isBN(options.keyNonce));
assert(Array.isArray(options.ids));
assert(Array.isArray(options.ptx));
this.keyNonce = options.keyNonce;
this.ids = options.ids || [];
this.ptx = options.ptx || [];
this.available = options.available || [];
this.idMap = options.idMap || {};
this.count = options.count || 0;
this.ids = options.ids;
this.ptx = options.ptx;
if (options.available)
this.available = options.available;
if (options.idMap)
this.idMap = options.idMap;
if (options.count)
this.count = options.count;
this.k0 = options.k0;
this.k1 = options.k1;
@ -358,7 +369,10 @@ function BlockTXRequest(options) {
BlockTXRequest.prototype.fromOptions = function fromOptions(options) {
this.hash = options.hash;
this.indexes = options.indexes || [];
if (options.indexes)
this.indexes = options.indexes;
return this;
};
@ -452,7 +466,10 @@ function BlockTX(options) {
BlockTX.prototype.fromOptions = function fromOptions(options) {
this.hash = options.hash;
this.txs = options.txs || [];
if (options.txs)
this.txs = options.txs;
return this;
};

View File

@ -27,11 +27,13 @@ function Block(options) {
bcoin.abstractblock.call(this, options);
this.txs = [];
this._cbHeight = null;
this._commitmentHash = null;
this._raw = null;
this._size = null;
this._witnessSize = null;
this._size = -1;
this._witnessSize = -1;
this._lastWitnessSize = 0;
if (options)
@ -49,15 +51,6 @@ utils.inherits(Block, bcoin.abstractblock);
Block.prototype.fromOptions = function fromOptions(options) {
var i;
this._cbHeight = null;
this._commitmentHash = null;
this._raw = options._raw || null;
this._size = options._size || null;
this._witnessSize = options._witnessSize != null
? options._witnessSize
: null;
if (options.txs) {
for (i = 0; i < options.txs.length; i++)
this.addTX(options.txs[i]);
@ -150,7 +143,7 @@ Block.prototype.getRaw = function getRaw() {
Block.prototype.getSizes = function getSizes() {
var writer;
if (this._size != null) {
if (this._size !== -1) {
return {
size: this._size,
witnessSize: this._witnessSize
@ -224,7 +217,7 @@ Block.prototype.getBaseSize = function getBaseSize() {
Block.prototype.hasWitness = function hasWitness() {
var i;
if (this._witnessSize != null)
if (this._witnessSize !== -1)
return this._witnessSize !== 0;
for (i = 0; i < this.txs.length; i++) {

View File

@ -9,6 +9,7 @@
var bcoin = require('./env');
var utils = require('./utils');
var constants = bcoin.protocol.constants;
var assert = utils.assert;
/**
@ -34,13 +35,13 @@ function Coin(options) {
if (!(this instanceof Coin))
return new Coin(options);
this.version = null;
this.height = null;
this.value = null;
this.script = null;
this.coinbase = null;
this.hash = null;
this.index = null;
this.version = 1;
this.height = -1;
this.value = 0;
this.script = new bcoin.script();
this.coinbase = true;
this.hash = constants.NULL_HASH;
this.index = 0;
if (options)
this.fromOptions(options);
@ -66,7 +67,10 @@ Coin.prototype.fromOptions = function fromOptions(options) {
this.version = options.version;
this.height = options.height;
this.value = options.value;
this.script = bcoin.script(options.script);
if (options.script)
this.script.fromOptions(options.script);
this.coinbase = options.coinbase;
this.hash = options.hash;
this.index = options.index;
@ -195,7 +199,7 @@ Coin.prototype.fromJSON = function fromJSON(json) {
this.version = json.version;
this.height = json.height;
this.value = utils.satoshi(json.value);
this.script = bcoin.script.fromJSON(json.script);
this.script.fromJSON(json.script);
this.coinbase = json.coinbase;
this.hash = json.hash ? utils.revHex(json.hash) : null;
this.index = json.index;
@ -240,7 +244,7 @@ Coin.prototype.fromRaw = function fromRaw(data) {
this.version = p.readU32();
this.height = p.readU32();
this.value = p.read64N();
this.script = bcoin.script.fromRaw(p.readVarBytes());
this.script.fromRaw(p.readVarBytes());
this.coinbase = p.readU8() === 1;
if (this.height === 0x7fffffff)

View File

@ -10,6 +10,7 @@
var bcoin = require('./env');
var utils = bcoin.utils;
var assert = utils.assert;
var constants = bcoin.protocol.constants;
var BufferReader = require('./reader');
var BufferWriter = require('./writer');
@ -30,10 +31,10 @@ function Coins(options) {
if (!(this instanceof Coins))
return new Coins(options);
this.version = -1;
this.hash = null;
this.version = 1;
this.hash = constants.NULL_HASH;
this.height = -1;
this.coinbase = false;
this.coinbase = true;
this.outputs = [];
if (options)
@ -47,10 +48,17 @@ function Coins(options) {
*/
Coins.prototype.fromOptions = function fromOptions(options) {
this.version = options.version != null ? options.version : -1;
this.hash = options.hash || null;
this.height = options.height != null ? options.height : -1;
this.coinbase = options.coinbase || false;
if (options.version != null)
this.version = options.version;
if (options.hash)
this.hash = options.hash;
if (options.height != null)
this.height = options.height;
if (options.coinbase != null)
this.coinbase = options.coinbase;
if (options.outputs)
this.outputs = options.outputs;
@ -74,13 +82,16 @@ Coins.fromOptions = function fromOptions(options) {
*/
Coins.prototype.add = function add(coin) {
if (this.version === -1) {
if (this.outputs.length === 0) {
this.version = coin.version;
this.hash = coin.hash;
this.height = coin.height;
this.coinbase = coin.coinbase;
}
while (this.outputs.length <= coin.index)
this.outputs.push(null);
if (coin.script.isUnspendable()) {
this.outputs[coin.index] = null;
return;

View File

@ -91,6 +91,16 @@ var BufferWriter = require('./writer');
var BufferReader = require('./reader');
var unorm;
/*
* Constants
*/
var PUBLIC_KEY = new Buffer(33);
PUBLIC_KEY.fill(0);
var FINGER_PRINT = new Buffer(4);
FINGER_PRINT.fill(0);
/**
* HD Mnemonic
* @exports Mnemonic
@ -112,12 +122,6 @@ function Mnemonic(options) {
if (!(this instanceof Mnemonic))
return new Mnemonic(options);
if (!options)
options = {};
if (typeof options === 'string')
options = { phrase: options };
this.bits = 128;
this.entropy = null;
this.phrase = null;
@ -136,17 +140,21 @@ function Mnemonic(options) {
*/
Mnemonic.prototype.fromOptions = function fromOptions(options) {
if (!options)
options = {};
if (typeof options === 'string')
options = { phrase: options };
this.bits = options.bits || 128;
if (options.bits != null)
this.bits = options.bits;
this.entropy = options.entropy;
this.phrase = options.phrase;
this.passphrase = options.passphrase || '';
this.language = options.language || 'english';
if (options.passphrase)
this.passphrase = options.passphrase;
if (options.language)
this.language = options.language;
this.seed = options.seed;
assert(this.bits >= 128);
@ -280,12 +288,27 @@ Mnemonic.prototype.toJSON = function toJSON() {
*/
Mnemonic.prototype.fromJSON = function fromJSON(json) {
assert(utils.isNumber(json.bits));
assert(!json.entropy || typeof json.entropy === 'string');
assert(!json.phrase || typeof json.phrase === 'string');
assert(typeof json.passphrase === 'string');
assert(typeof json.language === 'string');
assert(!json.seed || typeof json.seed === 'string');
this.bits = json.bits;
this.entropy = new Buffer(json.entropy, 'hex');
this.phrase = json.phrase;
if (json.entry)
this.entropy = new Buffer(json.entropy, 'hex');
if (json.phrase)
this.phrase = json.phrase;
this.passphrase = json.passphrase;
this.language = json.language;
this.seed = new Buffer(json.seed, 'hex');
if (json.seed)
this.seed = new Buffer(json.seed, 'hex');
return this;
};
@ -308,11 +331,30 @@ Mnemonic.prototype.toRaw = function toRaw(writer) {
var p = new BufferWriter(writer);
p.writeU16(this.bits);
p.writeBytes(this.entropy);
p.writeVarString(this.phrase, 'utf8');
if (this.entropy) {
p.writeU8(1);
p.writeBytes(this.entropy);
} else {
p.writeU8(0);
}
if (this.phrase) {
p.writeU8(1);
p.writeVarString(this.phrase, 'utf8');
} else {
p.writeU8(0);
}
p.writeVarString(this.passphrase, 'utf8');
p.writeVarString(this.language, 'utf8');
p.writeBytes(this.seed);
if (this.seed) {
p.writeU8(1);
p.writeBytes(this.seed);
} else {
p.writeU8(0);
}
if (!writer)
p = p.render();
@ -328,12 +370,21 @@ Mnemonic.prototype.toRaw = function toRaw(writer) {
Mnemonic.prototype.fromRaw = function fromRaw(data) {
var p = new BufferReader(data);
this.bits = p.readU16();
this.entropy = p.readBytes(this.bits / 8);
this.phrase = p.readVarString('utf8');
if (p.readU8() === 1)
this.entropy = p.readBytes(this.bits / 8);
if (p.readU8() === 1)
this.phrase = p.readVarString('utf8');
this.passphrase = p.readVarString('utf8');
this.language = p.readVarString('utf8');
this.seed = p.readBytes(64);
if (p.readU8() === 1)
this.seed = p.readBytes(64);
return this;
};
@ -607,14 +658,14 @@ function HDPrivateKey(options) {
if (!(this instanceof HDPrivateKey))
return new HDPrivateKey(options);
this.network = null;
this.depth = null;
this.parentFingerPrint = null;
this.childIndex = null;
this.chainCode = null;
this.privateKey = null;
this.network = bcoin.network.get().type;
this.depth = 0;
this.parentFingerPrint = FINGER_PRINT;
this.childIndex = 0;
this.chainCode = constants.ZERO_HASH;
this.privateKey = constants.ZERO_HASH;
this.publicKey = null;
this.publicKey = PUBLIC_KEY;
this.fingerPrint = null;
this.mnemonic = null;
@ -638,9 +689,16 @@ utils.inherits(HDPrivateKey, HD);
HDPrivateKey.prototype.fromOptions = function fromOptions(options) {
assert(options, 'No options for HD private key.');
assert(utils.isNumber(options.depth));
assert(Buffer.isBuffer(options.parentFingerPrint));
assert(utils.isNumber(options.childIndex));
assert(Buffer.isBuffer(options.chainCode));
assert(Buffer.isBuffer(options.privateKey));
assert(options.depth <= 0xff, 'Depth is too high.');
this.network = bcoin.network.get(options.network).type;
if (options.network)
this.network = bcoin.network.get(options.network).type;
this.depth = options.depth;
this.parentFingerPrint = options.parentFingerPrint;
this.childIndex = options.childIndex;
@ -649,8 +707,15 @@ HDPrivateKey.prototype.fromOptions = function fromOptions(options) {
this.publicKey = ec.publicKeyCreate(options.privateKey, true);
this.mnemonic = options.mnemonic || null;
this._xprivkey = options.xprivkey || null;
if (options.mnemonic) {
assert(options.mnemonic instanceof Mnemonic);
this.mnemonic = options.mnemonic;
}
if (options.xprivkey) {
assert(typeof options.xprivkey === 'string');
this._xprivkey = options.xprivkey;
}
return this;
};
@ -1291,14 +1356,13 @@ function HDPublicKey(options) {
if (!(this instanceof HDPublicKey))
return new HDPublicKey(options);
this.network = null;
this.depth = null;
this.parentFingerPrint = null;
this.childIndex = null;
this.chainCode = null;
this.publicKey = null;
this.network = bcoin.network.get().type;
this.depth = 0;
this.parentFingerPrint = FINGER_PRINT;
this.childIndex = 0;
this.chainCode = constants.ZERO_HASH;
this.publicKey = PUBLIC_KEY;
this.privateKey = null;
this.fingerPrint = null;
this._xpubkey = null;
@ -1320,16 +1384,25 @@ utils.inherits(HDPublicKey, HD);
HDPublicKey.prototype.fromOptions = function fromOptions(options) {
assert(options, 'No options for HDPublicKey');
assert(options.depth <= 0xff, 'Depth is too high.');
assert(utils.isNumber(options.depth));
assert(Buffer.isBuffer(options.parentFingerPrint));
assert(utils.isNumber(options.childIndex));
assert(Buffer.isBuffer(options.chainCode));
assert(Buffer.isBuffer(options.publicKey));
if (options.network)
this.network = bcoin.network.get(options.network).type;
this.network = bcoin.network.get(options.network).type;
this.depth = options.depth;
this.parentFingerPrint = options.parentFingerPrint;
this.childIndex = options.childIndex;
this.chainCode = options.chainCode;
this.publicKey = options.publicKey;
this._xpubkey = options.xpubkey;
if (options.xpubkey) {
assert(typeof options.xpubkey === 'string');
this._xpubkey = options.xpubkey;
}
return this;
};

View File

@ -26,8 +26,8 @@ function Outpoint(hash, index) {
if (!(this instanceof Outpoint))
return new Outpoint(hash, index);
this.hash = hash || null;
this.index = index != null ? index : null;
this.hash = hash || constants.NULL_HASH;
this.index = index != null ? index : 0xffffffff;
}
/**
@ -200,10 +200,10 @@ function Input(options, mutable) {
return new Input(options, mutable);
this.mutable = false;
this.prevout = null;
this.script = null;
this.sequence = null;
this.witness = null;
this.prevout = new Outpoint();
this.script = new bcoin.script();
this.sequence = 0xffffffff;
this.witness = new bcoin.witness();
this.coin = null;
if (options)
@ -219,14 +219,22 @@ function Input(options, mutable) {
Input.prototype.fromOptions = function fromOptions(options, mutable) {
assert(options, 'Input data is required.');
assert(options.sequence == null || utils.isNumber(options.sequence));
this.mutable = !!mutable;
this.prevout = Outpoint.fromOptions(options.prevout);
this.script = bcoin.script(options.script);
this.sequence = options.sequence == null ? 0xffffffff : options.sequence;
this.witness = bcoin.witness(options.witness);
this.coin = null;
if (options.prevout)
this.prevout.fromOptions(options.prevout);
if (options.script)
this.script.fromOptions(options.script);
if (options.sequence != null) {
assert(utils.isNumber(options.sequence));
this.sequence = options.sequence;
}
if (options.witness)
this.witness.fromOptions(options.witness);
if (options.coin)
this.coin = bcoin.coin(options.coin);
@ -496,10 +504,10 @@ Input.prototype.toJSON = function toJSON() {
Input.prototype.fromJSON = function fromJSON(json) {
assert(json, 'Input data is required.');
assert(utils.isNumber(json.sequence));
this.prevout = Outpoint.fromJSON(json.prevout);
this.prevout.fromJSON(json.prevout);
this.coin = json.coin ? bcoin.coin.fromJSON(json.coin) : null;
this.script = bcoin.script.fromJSON(json.script);
this.witness = bcoin.witness.fromJSON(json.witness);
this.script.fromJSON(json.script);
this.witness.fromJSON(json.witness);
this.sequence = json.sequence;
return this;
};
@ -541,8 +549,8 @@ Input.prototype.toRaw = function toRaw(writer) {
Input.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
this.prevout = Outpoint.fromRaw(p);
this.script = bcoin.script.fromRaw(p.readVarBytes());
this.prevout.fromRaw(p);
this.script.fromRaw(p.readVarBytes());
this.sequence = p.readU32();
return this;
@ -589,7 +597,7 @@ Input.prototype.toExtended = function toExtended(writer) {
Input.prototype.fromExtended = function fromExtended(data) {
var p = bcoin.reader(data);
this.fromRaw(p);
this.witness = bcoin.witness.fromRaw(p);
this.witness.fromRaw(p);
return this;
};
@ -616,10 +624,8 @@ Input.fromExtended = function fromExtended(data, enc) {
Input.prototype.fromCoin = function fromCoin(coin) {
assert(typeof coin.hash === 'string');
assert(typeof coin.index === 'number');
this.prevout = new Outpoint(coin.hash, coin.index);
this.script = new bcoin.script();
this.sequence = 0xffffffff;
this.witness = new bcoin.witness();
this.prevout.hash = coin.hash;
this.prevout.index = coin.index;
this.coin = coin;
return this;
};

View File

@ -29,10 +29,10 @@ function KeyPair(options) {
if (!(this instanceof KeyPair))
return new KeyPair(options);
this.network = null;
this.network = bcoin.network.get().type;
this.compressed = true;
this.privateKey = null;
this._publicKey = null;
this.publicKey = null;
if (options)
this.fromOptions(options);
@ -45,20 +45,24 @@ function KeyPair(options) {
*/
KeyPair.prototype.fromOptions = function fromOptions(options) {
if (!options)
options = {};
this.compressed = options.compressed !== false;
this.network = bcoin.network.get(options.network);
if (!options.privateKey && !options.publicKey)
throw new Error('No options for keypair');
assert(options.privateKey || options.publicKey);
assert(!options.privateKey || Buffer.isBuffer(options.privateKey));
assert(!options.publicKey || Buffer.isBuffer(options.publicKey));
if (options.compressed != null)
this.compressed = options.compressed;
if (options.network)
this.network = bcoin.network.get(options.network);
this.privateKey = options.privateKey;
this._publicKey = options.publicKey;
this.publicKey = options.publicKey;
if (!this.publicKey) {
this.publicKey = bcoin.ec.publicKeyCreate(
this.privateKey, this.compressed
);
}
return this;
};
@ -83,6 +87,7 @@ KeyPair.generate = function(network) {
var key = new KeyPair();
key.network = bcoin.network.get(network);
key.privateKey = bcoin.ec.generatePrivateKey();
key.publicKey = bcoin.ec.publicKeyCreate(key.privateKey, true);
return key;
};
@ -107,19 +112,6 @@ KeyPair.prototype.verify = function verify(msg, sig) {
return bcoin.ec.verify(msg, sig, this.getPublicKey());
};
KeyPair.prototype.__defineGetter__('publicKey', function() {
if (!this._publicKey) {
if (!this.privateKey)
return;
this._publicKey = bcoin.ec.publicKeyCreate(
this.privateKey, this.compressed
);
}
return this._publicKey;
});
/**
* Get private key.
* @param {String?} enc - Can be `"hex"`, `"base58"`, or `null`.
@ -220,10 +212,16 @@ KeyPair.prototype.fromRaw = function fromRaw(data) {
if (p.left() > 4) {
assert(p.readU8() === 1, 'Bad compression flag.');
this.compressed = true;
} else {
this.compressed = false;
}
p.verifyChecksum();
this.publicKey = bcoin.ec.publicKeyCreate(
this.privateKey, this.compressed
);
return this;
};
@ -312,7 +310,7 @@ KeyPair.fromJSON = function fromJSON(json) {
KeyPair.isKeyPair = function isKeyPair(obj) {
return obj
&& obj._privateKey !== undefined
&& obj.privateKey !== undefined
&& typeof obj.fromSecret === 'function';
};

View File

@ -34,8 +34,8 @@ function KeyRing(options) {
if (!(this instanceof KeyRing))
return new KeyRing(options);
this.network = null;
this.type = null;
this.network = bcoin.network.get();
this.type = 'pubkeyhash';
this.m = 1;
this.n = 1;
this.witness = false;
@ -71,18 +71,37 @@ function KeyRing(options) {
KeyRing.prototype.fromOptions = function fromOptions(options) {
var i;
this.network = bcoin.network.get(options.network);
this.type = options.type || 'pubkeyhash';
this.m = options.m || 1;
this.n = options.n || 1;
this.witness = options.witness || false;
this.id = options.id;
this.name = options.name;
this.account = options.account;
this.change = options.change;
this.index = options.index;
if (options.network)
this.network = bcoin.network.get(options.network);
if (options.type)
this.type = options.type;
if (options.m)
this.m = options.m;
if (options.n)
this.n = options.n;
if (options.witness != null)
this.witness = options.witness;
if (options.id)
this.id = options.id;
if (options.name)
this.name = options.name;
if (options.account != null)
this.account = options.account;
if (options.change != null)
this.change = options.change;
if (options.index != null)
this.index = options.index;
this.key = options.key;
this.keys = [];
if (this.n > 1)
this.type = 'multisig';

View File

@ -29,25 +29,11 @@ var utils = require('./utils');
* @exports MemBlock
* @constructor
* @param {NakedBlock} options
* @param {Buffer} options.raw
* @param {Number} options.coinbaseHeight
* @property {Number} version - Block version. Note
* that BCoin reads versions as unsigned despite
* them being signed on the protocol level. This
* number will never be negative.
* @property {Hash} prevBlock - Previous block hash.
* @property {Hash} merkleRoot - Merkle root hash.
* @property {Number} ts - Timestamp.
* @property {Number} bits
* @property {Number} nonce
* @property {Number} totalTX - Transaction count.
* @property {Number} height - Block height (-1 if not present).
* @property {Boolean} memory - Always true.
* @property {Number} coinbaseHeight - The coinbase height which
* was extracted by the parser (the coinbase is the only
* transaction we parse ahead of time).
* @property {Buffer} raw - The raw block data.
* @property {ReversedHash} rhash - Reversed block hash (uint256le).
*/
function MemBlock(options) {
@ -57,7 +43,7 @@ function MemBlock(options) {
bcoin.abstractblock.call(this, options);
this.memory = true;
this.coinbaseHeight = null;
this.coinbaseHeight = -1;
this.raw = null;
if (options)
@ -199,7 +185,7 @@ MemBlock.prototype.toBlock = function toBlock() {
*/
MemBlock.isMemBlock = function isMemBlock(obj) {
return obj && typeof obj.toBlock === 'function';
return obj && obj.memory && typeof obj.toBlock === 'function';
};
/*

View File

@ -1876,6 +1876,30 @@ function MempoolEntry(options) {
if (!(this instanceof MempoolEntry))
return new MempoolEntry(options);
this.tx = null;
this.height = -1;
this.size = 0;
this.priority = 0;
this.fee = 0;
this.ts = 0;
this.chainValue = 0;
this.count = 0;
this.sizes = 0;
this.fees = 0;
this.dependencies = false;
if (options)
this.fromOptions(options);
}
/**
* Inject properties from options object.
* @private
* @param {Object} options
*/
MempoolEntry.prototype.fromOptions = function fromOptions(options) {
this.tx = options.tx;
this.height = options.height;
this.size = options.size;
@ -1888,16 +1912,28 @@ function MempoolEntry(options) {
this.sizes = options.sizes;
this.fees = options.fees;
this.dependencies = options.dependencies;
}
return this;
};
/**
* Create a mempool entry from a TX.
* @param {TX} tx
* @param {Number} height - Entry height.
* Instantiate mempool entry from options.
* @param {Object} options
* @returns {MempoolEntry}
*/
MempoolEntry.fromTX = function fromTX(tx, height) {
MempoolEntry.fromOptions = function fromOptions(options) {
return new MempoolEntry().fromOptions(options);
};
/**
* Inject properties from transaction.
* @private
* @param {TX} tx
* @param {Number} height
*/
MempoolEntry.prototype.fromTX = function fromTX(tx, height) {
var data = tx.getPriority(height);
var dependencies = false;
var size = tx.getVirtualSize();
@ -1911,19 +1947,30 @@ MempoolEntry.fromTX = function fromTX(tx, height) {
}
}
return new MempoolEntry({
tx: tx,
height: height,
size: size,
priority: data.priority,
fee: fee,
chainValue: data.value,
ts: utils.now(),
count: 1,
sizes: size,
fees: fee,
dependencies: dependencies
});
this.tx = tx;
this.height = height;
this.size = size;
this.priority = data.priority;
this.fee = fee;
this.chainValue = data.value;
this.ts = utils.now();
this.count = 1;
this.sizes = size;
this.fees = fee;
this.dependencies = dependencies;
return this;
};
/**
* Create a mempool entry from a TX.
* @param {TX} tx
* @param {Number} height - Entry height.
* @returns {MempoolEntry}
*/
MempoolEntry.fromTX = function fromTX(tx, height) {
return new MempoolEntry().fromTX(tx, height);
};
/**
@ -1957,6 +2004,28 @@ MempoolEntry.prototype.toRaw = function toRaw(writer) {
return p;
};
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
*/
MempoolEntry.prototype.fromRaw = function fromRaw(data) {
var p = new BufferReader(data);
this.tx = bcoin.tx.fromRaw(p);
this.height = p.readU32();
this.size = p.readU32();
this.priority = p.readDouble();
this.fee = p.readVarint();
this.chainValue = p.readVarint();
this.ts = p.readU32();
this.count = p.readU32();
this.sizes = p.readU32();
this.fees = p.readVarint();
this.dependencies = p.readU8() === 1;
return this;
};
/**
* Create a mempool entry from serialized data.
* @param {Buffer|BufferReader} data
@ -1964,20 +2033,7 @@ MempoolEntry.prototype.toRaw = function toRaw(writer) {
*/
MempoolEntry.fromRaw = function fromRaw(data) {
var p = new BufferReader(data);
return new MempoolEntry({
tx: bcoin.tx.fromRaw(p),
height: p.readU32(),
size: p.readU32(),
priority: p.readDouble(),
fee: p.readVarint(),
chainValue: p.readVarint(),
ts: p.readU32(),
count: p.readU32(),
sizes: p.readU32(),
fees: p.readVarint(),
dependencies: p.readU8() === 1
});
return new MempoolEntry().fromRaw(data);
};
/**

View File

@ -11,6 +11,7 @@ var bcoin = require('./env');
var utils = require('./utils');
var assert = utils.assert;
var constants = bcoin.protocol.constants;
var DUMMY = new Buffer([0]);
/**
* Represents a merkle (filtered) block.
@ -26,8 +27,8 @@ function MerkleBlock(options) {
bcoin.abstractblock.call(this, options);
this.hashes = null;
this.flags = null;
this.hashes = [];
this.flags = DUMMY;
// List of matched TXs
this.map = {};
@ -54,8 +55,11 @@ MerkleBlock.prototype.fromOptions = function fromOptions(options) {
assert(Array.isArray(options.hashes));
assert(Buffer.isBuffer(options.flags));
this.hashes = options.hashes;
this.flags = options.flags;
if (options.hashes)
this.hashes = options.hashes;
if (options.flags)
this.flags = options.flags;
return this;
};

View File

@ -79,15 +79,17 @@ function MTX(options) {
this._hash = null;
this._whash = null;
this._raw = null;
this._size = null;
this._witnessSize = null;
this._outputValue = null;
this._inputValue = null;
this._size = -1;
this._witnessSize = -1;
this._lastWitnessSize = 0;
this._outputValue = -1;
this._inputValue = -1;
this._hashPrevouts = null;
this._hashSequence = null;
this._hashOutputs = null;
this._lastWitnessSize = 0;
if (options.inputs) {
for (i = 0; i < options.inputs.length; i++)

View File

@ -30,8 +30,8 @@ function Output(options, mutable) {
return new Output(options, mutable);
this.mutable = false;
this.value = null;
this.script = null;
this.value = 0;
this.script = new bcoin.script();
if (options)
this.fromOptions(options, mutable);
@ -51,7 +51,8 @@ Output.prototype.fromOptions = function fromOptions(options, mutable) {
this.mutable = !!mutable;
this.value = options.value || 0;
this.script = bcoin.script(options.script);
if (options.script)
this.script.fromOptions(options.script);
return this;
};
@ -232,7 +233,7 @@ Output.prototype.isDust = function isDust(rate) {
Output.prototype.fromJSON = function fromJSON(json) {
this.value = utils.satoshi(json.value);
this.script = bcoin.script.fromJSON(json.script);
this.script.fromJSON(json.script);
return this;
};
@ -274,7 +275,7 @@ Output.prototype.fromRaw = function fromRaw(data) {
var p = bcoin.reader(data);
this.value = p.read64N();
this.script = bcoin.script.fromRaw(p.readVarBytes());
this.script.fromRaw(p.readVarBytes());
return this;
};

View File

@ -611,6 +611,25 @@ exports.MAX_HASH = new Buffer(
exports.NULL_HASH =
'0000000000000000000000000000000000000000000000000000000000000000';
/**
* A hash of all zeroes.
* @const {Buffer}
* @default
*/
exports.ZERO_HASH160 = new Buffer(
'0000000000000000000000000000000000000000',
'hex'
);
/**
* A hash of all zeroes.
* @const {String}
* @default
*/
exports.NULL_HASH160 = '0000000000000000000000000000000000000000';
/**
* BCoin version.
* @const {String}

View File

@ -47,10 +47,10 @@ function VersionPacket(options) {
this.version = constants.VERSION;
this.services = constants.LOCAL_SERVICES;
this.ts = 0;
this.recv = null;
this.from = null;
this.nonce = null;
this.ts = bcoin.now();
this.recv = new NetworkAddress();
this.from = new NetworkAddress();
this.nonce = new bn(0);
this.agent = constants.USER_AGENT;
this.height = 0;
this.relay = true;
@ -66,21 +66,33 @@ function VersionPacket(options) {
*/
VersionPacket.prototype.fromOptions = function fromOptions(options) {
this.version = options.version != null
? options.version
: constants.VERSION;
this.services = options.services != null
? options.services
: constants.LOCAL_SERVICES;
this.ts = options.ts != null
? options.ts
: bcoin.now();
this.recv = options.recv || new NetworkAddress();
this.from = options.from || new NetworkAddress();
this.nonce = options.nonce || utils.nonce();
this.agent = options.agent || constants.USER_AGENT;
this.height = options.height || 0;
this.relay = options.relay != null ? options.relay : true;
if (options.version != null)
this.version = options.version;
if (options.services != null)
this.services = options.services;
if (options.ts != null)
this.ts = options.ts;
if (options.recv)
this.recv.fromOptions(options.recv);
if (options.from)
this.from.fromOptions(options.from);
if (options.nonce)
this.nonce = options.nonce;
if (options.agent)
this.agent = options.agent;
if (options.height != null)
this.height = options.height;
if (options.relay != null)
this.relay = options.relay;
return this;
};
@ -176,30 +188,21 @@ VersionPacket.prototype.fromRaw = function fromRaw(data) {
this.version = p.read32();
this.services = p.readU53();
this.ts = p.read53();
this.recv = NetworkAddress.fromRaw(p, false);
this.recv.fromRaw(p, false);
if (p.left() > 0) {
this.from = NetworkAddress.fromRaw(p, false);
this.from.fromRaw(p, false);
this.nonce = p.readU64();
} else {
this.from = new NetworkAddress();
this.nonce = new bn(0);
}
if (p.left() > 0)
this.agent = p.readVarString('ascii', 256);
else
this.agent = '';
if (p.left() > 0)
this.height = p.read32();
else
this.height = 0;
if (p.left() > 0)
this.relay = p.readU8() === 1;
else
this.relay = true;
if (this.version === 10300)
this.version = 300;
@ -393,19 +396,23 @@ GetBlocksPacket.fromRaw = function fromRaw(data, enc) {
*/
function AlertPacket(options) {
var time;
if (!(this instanceof AlertPacket))
return new AlertPacket(options);
this.version = 0;
this.relayUntil = 0;
this.expiration = 0;
this.id = 0;
time = bcoin.now() + 7 * 86400;
this.version = 1;
this.relayUntil = time;
this.expiration = time;
this.id = 1;
this.cancel = 0;
this.cancels = [];
this.minVer = 0;
this.minVer = 10000;
this.maxVer = constants.VERSION;
this.subVers = [];
this.priority = 0;
this.priority = 100;
this.comment = '';
this.statusBar = '';
this.reserved = '';
@ -425,21 +432,45 @@ function AlertPacket(options) {
*/
AlertPacket.prototype.fromOptions = function fromOptions(options) {
var time = bcoin.now() + 7 * 86400;
if (options.version != null)
this.version = options.version;
if (options.relayUntil != null)
this.relayUntil = options.relayUntil;
if (options.expiration != null)
this.expiration = options.expiration;
if (options.id != null)
this.id = options.id;
if (options.cancel != null)
this.cancel = options.cancel;
if (options.cancels)
this.cancels = options.cancels;
if (options.minVer != null)
this.minVer = options.minVer;
if (options.maxVer != null)
this.maxVer = options.maxVer;
if (options.subVers)
this.subVers = options.subVers;
if (options.priority != null)
this.priority = options.priority;
if (options.comment != null)
this.comment = options.comment;
if (options.statusBar != null)
this.statusBar = options.statusBar;
if (options.reserved != null)
this.reserved = options.reserved;
this.version = options.version != null ? options.version : 1;
this.relayUntil = options.relayUntil != null ? options.relayUntil : time;
this.expiration = options.expiration != null ? options.expiration : time;
this.id = options.id != null ? options.id : 0;
this.cancel = options.cancel != null ? options.cancel : 0;
this.cancels = options.cancels || [];
this.minVer = options.minVer != null ? options.minVer : 10000;
this.maxVer = options.maxVer != null ? options.maxVer : constants.VERSION;
this.subVers = options.subVers || [];
this.priority = options.priority != null ? options.priority : 100;
this.comment = options.comment || '';
this.statusBar = options.statusBar || '';
this.reserved = options.reserved || '';
this.signature = options.signature;
return this;
@ -639,19 +670,24 @@ function RejectPacket(options) {
RejectPacket.prototype.fromOptions = function fromOptions(options) {
var code = options.code;
if (typeof code === 'string')
code = constants.reject[code.toUpperCase()];
if (options.message)
this.message = options.message;
if (!code)
code = constants.reject.INVALID;
if (code != null) {
if (typeof code === 'string')
code = constants.reject[code.toUpperCase()];
if (code >= constants.reject.INTERNAL)
code = constants.reject.INVALID;
if (code >= constants.reject.INTERNAL)
code = constants.reject.INVALID;
this.message = options.message || '';
this.code = code;
this.reason = options.reason || '';
this.data = options.data || null;
this.code = code;
}
if (options.reason)
this.reason = options.reason;
if (options.data)
this.data = options.data;
return this;
};

View File

@ -3587,7 +3587,7 @@ Script.isHashType = function isHashType(sig) {
type = sig[sig.length - 1] & ~constants.hashType.ANYONECANPAY;
if (!constants.hashTypeByVal[type])
if (!(type >= constants.hashType.ALL && type <= constants.hashType.SINGLE))
return false;
return true;

View File

@ -69,12 +69,12 @@ function TX(options) {
this._whash = null;
this._raw = null;
this._size = null;
this._witnessSize = null;
this._size = -1;
this._witnessSize = -1;
this._lastWitnessSize = 0;
this._outputValue = null;
this._inputValue = null;
this._outputValue = -1;
this._inputValue = -1;
this._hashPrevouts = null;
this._hashSequence = null;
this._hashOutputs = null;
@ -93,42 +93,63 @@ TX.prototype.fromOptions = function fromOptions(options) {
var i;
assert(options, 'TX data is required.');
assert(utils.isNumber(options.version));
assert(utils.isNumber(options.flag));
assert(Array.isArray(options.inputs));
assert(Array.isArray(options.outputs));
assert(utils.isNumber(options.locktime));
this.version = options.version;
this.flag = options.flag;
if (options.version != null) {
assert(utils.isNumber(options.version));
this.version = options.version;
}
for (i = 0; i < options.inputs.length; i++)
this.inputs.push(new bcoin.input(options.inputs[i]));
if (options.flag != null) {
assert(utils.isNumber(options.flag));
this.flag = options.flag;
}
for (i = 0; i < options.outputs.length; i++)
this.outputs.push(new bcoin.output(options.outputs[i]));
if (options.inputs) {
assert(Array.isArray(options.inputs));
for (i = 0; i < options.inputs.length; i++)
this.inputs.push(new bcoin.input(options.inputs[i]));
}
this.locktime = options.locktime;
if (options.outputs) {
assert(Array.isArray(options.outputs));
for (i = 0; i < options.outputs.length; i++)
this.outputs.push(new bcoin.output(options.outputs[i]));
}
this.ts = options.ts || 0;
this.block = options.block || null;
this.index = options.index != null
? options.index
: -1;
this.ps = this.ts === 0
? (options.ps != null ? options.ps : utils.now())
: 0;
this.height = options.height != null
? options.height
: -1;
if (options.locktime != null) {
assert(utils.isNumber(options.locktime));
this.locktime = options.locktime;
}
this._raw = options._raw || null;
this._size = options._size != null
? options._size
: 0;
this._witnessSize = options._witnessSize != null
? options._witnessSize
: null;
if (options.ts != null)
assert(utils.isNumber(options.locktime));
this.ts = options.ts;
if (options.block !== undefined) {
assert(options.block === null || typeof options.block === 'string');
this.block = options.block;
}
if (options.index != null) {
assert(utils.isNumber(options.index));
this.index = options.index;
}
if (options.ps != null) {
assert(utils.isNumber(options.ps));
this.ps = this.ts === 0
? options.ps
: 0;
}
if (options.height != null) {
assert(utils.isNumber(options.height));
this.height = options.height;
}
return this;
};
@ -416,7 +437,7 @@ TX.prototype.getBaseSize = function getBaseSize() {
TX.prototype.hasWitness = function hasWitness() {
var i;
if (this._witnessSize != null)
if (this._witnessSize !== -1)
return this._witnessSize !== 0;
for (i = 0; i < this.inputs.length; i++) {
@ -459,10 +480,9 @@ TX.prototype.signatureHash = function signatureHash(index, prev, type, version)
* @returns {Buffer}
*/
TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
TX.prototype.signatureHashCopy = function signatureHashV0(index, prev, type) {
var p = new BufferWriter();
var empty = new Script();
var witness = new bcoin.witness();
var i, copy, input, output;
if (typeof index !== 'number')
@ -484,7 +504,6 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
input.prevout = this.inputs[i].prevout;
input.script = this.inputs[i].script;
input.sequence = this.inputs[i].sequence;
input.witness = witness;
copy.inputs.push(input);
}
@ -553,6 +572,134 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
return utils.hash256(p.render());
};
/**
* Legacy sighashing -- O(n^2).
* Note: Optimized version. No
* transaction copy necessary.
* @private
* @param {Number} index
* @param {Script} prev
* @param {SighashType} type
* @returns {Buffer}
*/
TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
var i, input, output;
var p = new BufferWriter();
var hashType;
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
if (typeof type === 'string')
type = constants.hashType[type.toUpperCase()];
assert(index >= 0 && index < this.inputs.length);
assert(prev instanceof Script);
// Get the unmasked hash type.
hashType = type & 0x1f;
if (hashType === constants.hashType.SINGLE) {
// Bitcoind used to return 1 as an error code:
// it ended up being treated like a hash.
if (index >= this.outputs.length)
return utils.copy(constants.ONE_HASH);
}
// Remove all code separators.
prev = prev.removeSeparators();
p.write32(this.version);
if (type & constants.hashType.ANYONECANPAY) {
p.writeVarint(1);
// Serialize only the current
// input if ANYONECANPAY.
input = this.inputs[index];
// Outpoint.
p.writeHash(input.prevout.hash);
p.writeU32(input.prevout.index);
// Replace script with previous
// output script if current index.
p.writeVarBytes(prev.toRaw());
p.writeU32(input.sequence);
} else {
p.writeVarint(this.inputs.length);
for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i];
// Outpoint.
p.writeHash(input.prevout.hash);
p.writeU32(input.prevout.index);
// Replace script with previous
// output script if current index.
if (i === index) {
p.writeVarBytes(prev.toRaw());
p.writeU32(input.sequence);
continue;
}
// Script is null.
p.writeVarint(0);
// Sequences are 0 if NONE or SINGLE.
if (hashType === constants.hashType.NONE
|| hashType === constants.hashType.SINGLE) {
p.writeU32(0);
} else {
p.writeU32(input.sequence);
}
}
}
if (hashType === constants.hashType.NONE) {
// No outputs if NONE.
p.writeVarint(0);
} else if (hashType === constants.hashType.SINGLE) {
// Drop all outputs after the
// current input index if SINGLE.
p.writeVarint(index + 1);
for (i = 0; i < index + 1; i++) {
output = this.outputs[i];
// Regular serialization if
// at current input index.
if (i === index) {
p.write64(output.value);
p.writeVarBytes(output.script.toRaw());
continue;
}
// Null all outputs not at
// current input index.
p.write64(-1);
p.writeVarint(0);
}
} else {
// Regular output serialization if ALL.
p.writeVarint(this.outputs.length);
for (i = 0; i < this.outputs.length; i++) {
output = this.outputs[i];
p.write64(output.value);
p.writeVarBytes(output.script.toRaw());
}
}
p.writeU32(this.locktime);
// Append the hash type.
p.writeU32(type);
return utils.hash256(p.render());
};
/**
* Witness sighashing -- O(n).
* @private
@ -777,7 +924,7 @@ TX.prototype.getInputValue = function getInputValue() {
var total = 0;
var i;
if (this._inputValue != null)
if (this._inputValue !== -1)
return this._inputValue;
if (!this.hasCoins())
@ -801,7 +948,7 @@ TX.prototype.getOutputValue = function getOutputValue() {
var total = 0;
var i;
if (this._outputValue != null)
if (this._outputValue !== -1)
return this._outputValue;
for (i = 0; i < this.outputs.length; i++)

View File

@ -1677,7 +1677,7 @@ function WalletMap() {
this.inputs = [];
this.outputs = [];
this.accounts = [];
this.table = null;
this.table = {};
}
WalletMap.prototype.fromTX = function fromTX(table, tx) {

View File

@ -1731,6 +1731,7 @@ utils.readVarint2 = function readVarint2(data, off, big) {
}
if (bnum) {
assert(bnum.bitLength() <= 256);
bnum.iushln(7).iaddn(ch & 0x7f);
if ((ch & 0x80) === 0)
break;

View File

@ -1565,15 +1565,15 @@ function Account(db, options) {
this.id = null;
this.name = null;
this.witness = false;
this.witness = this.network.witness;
this.accountKey = null;
this.accountIndex = 0;
this.receiveDepth = 0;
this.changeDepth = 0;
this.type = null;
this.keys = [];
this.type = 'pubkeyhash';
this.m = 1;
this.n = 1;
this.keys = [];
this.initialized = false;
if (options)
@ -1598,18 +1598,32 @@ Account.prototype.fromOptions = function fromOptions(options) {
this.id = options.id;
this.name = options.name;
this.witness = options.witness != null
? options.witness
: this.network.witness;
if (options.witness != null)
this.witness = options.witness;
this.accountKey = options.accountKey;
this.accountIndex = options.accountIndex;
this.receiveDepth = options.receiveDepth || 0;
this.changeDepth = options.changeDepth || 0;
this.type = options.type || 'pubkeyhash';
this.keys = [];
this.m = options.m || 1;
this.n = options.n || 1;
this.initialized = options.initialized || false;
if (options.accountIndex != null)
this.accountIndex = options.accountIndex;
if (options.receiveDepth != null)
this.receiveDepth = options.receiveDepth;
if (options.changeDepth != null)
this.changeDepth = options.changeDepth;
if (options.type)
this.type = options.type;
if (options.m)
this.m = options.m;
if (options.n)
this.n = options.n;
if (options.initialized != null)
this.initialized = options.initialized;
if (this.n > 1)
this.type = 'multisig';
@ -1673,11 +1687,11 @@ Account.prototype.init = function init(callback) {
return this.save(callback);
}
this.initialized = true;
assert(this.receiveDepth === 0);
assert(this.changeDepth === 0);
this.initialized = true;
this.setDepth(1, 1, callback);
};
@ -2236,7 +2250,8 @@ Account.prototype.toJSON = function toJSON() {
Account.prototype.fromJSON = function fromJSON(json) {
var i;
this.network = bcoin.network.get(json.network);
assert.equal(json.network, this.network.type);
this.id = json.id;
this.name = json.name;
this.initialized = json.initialized;

View File

@ -344,23 +344,23 @@ describe('Script', function() {
});
if (nocache) {
tx._raw = null;
tx._size = null;
tx._witnessSize = null;
tx._size = -1;
tx._witnessSize = -1;
tx._lastWitnessSize = 0;
tx._hash = null;
tx._inputValue = null;
tx._outputValue = null;
tx._inputValue = -1;
tx._outputValue = -1;
tx._hashPrevouts = null;
tx._hashSequence = null;
tx._hashOutputs = null;
coin._raw = null;
coin._size = null;
coin._witnessSize = null;
coin._size = -1;
coin._witnessSize = -1;
coin._lastWitnessSize = 0;
coin._hash = null;
coin._inputValue = null;
coin._outputValue = null;
coin._inputValue = -1;
coin._outputValue = -1;
coin._hashPrevouts = null;
coin._hashSequence = null;
coin._hashOutputs = null;

View File

@ -48,12 +48,12 @@ function clearCache(tx, nocache) {
}
tx._raw = null;
tx._size = null;
tx._witnessSize = null;
tx._size = -1;
tx._witnessSize = -1;
tx._lastWitnessSize = 0;
tx._hash = null;
tx._inputValue = null;
tx._outputValue = null;
tx._inputValue = -1;
tx._outputValue = -1;
tx._hashPrevouts = null;
tx._hashSequence = null;
tx._hashOutputs = null;