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

View File

@ -9,6 +9,7 @@
var bcoin = require('./env'); var bcoin = require('./env');
var networks = bcoin.protocol.network; var networks = bcoin.protocol.network;
var constants = bcoin.protocol.constants;
var utils = require('./utils'); var utils = require('./utils');
var assert = utils.assert; var assert = utils.assert;
var BufferWriter = require('./writer'); var BufferWriter = require('./writer');
@ -35,10 +36,10 @@ function Address(options) {
if (!(this instanceof Address)) if (!(this instanceof Address))
return new Address(options); return new Address(options);
this.hash = null; this.hash = constants.ZERO_HASH160;
this.type = null; this.type = 'pubkeyhash';
this.version = null; this.version = -1;
this.network = null; this.network = bcoin.network.get().type;
if (options) if (options)
this.fromOptions(options); this.fromOptions(options);
@ -51,13 +52,23 @@ function Address(options) {
*/ */
Address.prototype.fromOptions = function fromOptions(options) { Address.prototype.fromOptions = function fromOptions(options) {
assert(options.hash);
this.hash = options.hash; this.hash = options.hash;
this.type = options.type || 'pubkeyhash';
this.version = options.version == null ? -1 : options.version; if (options.type)
this.network = bcoin.network.get(options.network).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') if (typeof this.hash === 'string')
this.hash = new Buffer(this.hash, 'hex'); 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) { 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.keyNonce = options.keyNonce;
this.ids = options.ids || []; this.ids = options.ids;
this.ptx = options.ptx || []; this.ptx = options.ptx;
this.available = options.available || [];
this.idMap = options.idMap || {}; if (options.available)
this.count = options.count || 0; this.available = options.available;
if (options.idMap)
this.idMap = options.idMap;
if (options.count)
this.count = options.count;
this.k0 = options.k0; this.k0 = options.k0;
this.k1 = options.k1; this.k1 = options.k1;
@ -358,7 +369,10 @@ function BlockTXRequest(options) {
BlockTXRequest.prototype.fromOptions = function fromOptions(options) { BlockTXRequest.prototype.fromOptions = function fromOptions(options) {
this.hash = options.hash; this.hash = options.hash;
this.indexes = options.indexes || [];
if (options.indexes)
this.indexes = options.indexes;
return this; return this;
}; };
@ -452,7 +466,10 @@ function BlockTX(options) {
BlockTX.prototype.fromOptions = function fromOptions(options) { BlockTX.prototype.fromOptions = function fromOptions(options) {
this.hash = options.hash; this.hash = options.hash;
this.txs = options.txs || [];
if (options.txs)
this.txs = options.txs;
return this; return this;
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -29,25 +29,11 @@ var utils = require('./utils');
* @exports MemBlock * @exports MemBlock
* @constructor * @constructor
* @param {NakedBlock} options * @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 {Boolean} memory - Always true.
* @property {Number} coinbaseHeight - The coinbase height which * @property {Number} coinbaseHeight - The coinbase height which
* was extracted by the parser (the coinbase is the only * was extracted by the parser (the coinbase is the only
* transaction we parse ahead of time). * transaction we parse ahead of time).
* @property {Buffer} raw - The raw block data. * @property {Buffer} raw - The raw block data.
* @property {ReversedHash} rhash - Reversed block hash (uint256le).
*/ */
function MemBlock(options) { function MemBlock(options) {
@ -57,7 +43,7 @@ function MemBlock(options) {
bcoin.abstractblock.call(this, options); bcoin.abstractblock.call(this, options);
this.memory = true; this.memory = true;
this.coinbaseHeight = null; this.coinbaseHeight = -1;
this.raw = null; this.raw = null;
if (options) if (options)
@ -199,7 +185,7 @@ MemBlock.prototype.toBlock = function toBlock() {
*/ */
MemBlock.isMemBlock = function isMemBlock(obj) { 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)) if (!(this instanceof MempoolEntry))
return new MempoolEntry(options); 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.tx = options.tx;
this.height = options.height; this.height = options.height;
this.size = options.size; this.size = options.size;
@ -1888,16 +1912,28 @@ function MempoolEntry(options) {
this.sizes = options.sizes; this.sizes = options.sizes;
this.fees = options.fees; this.fees = options.fees;
this.dependencies = options.dependencies; this.dependencies = options.dependencies;
}
return this;
};
/** /**
* Create a mempool entry from a TX. * Instantiate mempool entry from options.
* @param {TX} tx * @param {Object} options
* @param {Number} height - Entry height.
* @returns {MempoolEntry} * @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 data = tx.getPriority(height);
var dependencies = false; var dependencies = false;
var size = tx.getVirtualSize(); var size = tx.getVirtualSize();
@ -1911,19 +1947,30 @@ MempoolEntry.fromTX = function fromTX(tx, height) {
} }
} }
return new MempoolEntry({ this.tx = tx;
tx: tx, this.height = height;
height: height, this.size = size;
size: size, this.priority = data.priority;
priority: data.priority, this.fee = fee;
fee: fee, this.chainValue = data.value;
chainValue: data.value, this.ts = utils.now();
ts: utils.now(), this.count = 1;
count: 1, this.sizes = size;
sizes: size, this.fees = fee;
fees: fee, this.dependencies = dependencies;
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; 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. * Create a mempool entry from serialized data.
* @param {Buffer|BufferReader} data * @param {Buffer|BufferReader} data
@ -1964,20 +2033,7 @@ MempoolEntry.prototype.toRaw = function toRaw(writer) {
*/ */
MempoolEntry.fromRaw = function fromRaw(data) { MempoolEntry.fromRaw = function fromRaw(data) {
var p = new BufferReader(data); return new MempoolEntry().fromRaw(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
});
}; };
/** /**

View File

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

View File

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

View File

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

View File

@ -611,6 +611,25 @@ exports.MAX_HASH = new Buffer(
exports.NULL_HASH = exports.NULL_HASH =
'0000000000000000000000000000000000000000000000000000000000000000'; '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. * BCoin version.
* @const {String} * @const {String}

View File

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

View File

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

View File

@ -69,12 +69,12 @@ function TX(options) {
this._whash = null; this._whash = null;
this._raw = null; this._raw = null;
this._size = null; this._size = -1;
this._witnessSize = null; this._witnessSize = -1;
this._lastWitnessSize = 0; this._lastWitnessSize = 0;
this._outputValue = null; this._outputValue = -1;
this._inputValue = null; this._inputValue = -1;
this._hashPrevouts = null; this._hashPrevouts = null;
this._hashSequence = null; this._hashSequence = null;
this._hashOutputs = null; this._hashOutputs = null;
@ -93,42 +93,63 @@ TX.prototype.fromOptions = function fromOptions(options) {
var i; var i;
assert(options, 'TX data is required.'); assert(options, 'TX data is required.');
assert(utils.isNumber(options.version));
assert(utils.isNumber(options.flag)); assert(utils.isNumber(options.flag));
assert(Array.isArray(options.inputs)); assert(Array.isArray(options.inputs));
assert(Array.isArray(options.outputs)); assert(Array.isArray(options.outputs));
assert(utils.isNumber(options.locktime)); assert(utils.isNumber(options.locktime));
this.version = options.version; if (options.version != null) {
this.flag = options.flag; assert(utils.isNumber(options.version));
this.version = options.version;
}
for (i = 0; i < options.inputs.length; i++) if (options.flag != null) {
this.inputs.push(new bcoin.input(options.inputs[i])); assert(utils.isNumber(options.flag));
this.flag = options.flag;
}
for (i = 0; i < options.outputs.length; i++) if (options.inputs) {
this.outputs.push(new bcoin.output(options.outputs[i])); 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; if (options.locktime != null) {
this.block = options.block || null; assert(utils.isNumber(options.locktime));
this.index = options.index != null this.locktime = options.locktime;
? options.index }
: -1;
this.ps = this.ts === 0
? (options.ps != null ? options.ps : utils.now())
: 0;
this.height = options.height != null
? options.height
: -1;
this._raw = options._raw || null; if (options.ts != null)
this._size = options._size != null assert(utils.isNumber(options.locktime));
? options._size this.ts = options.ts;
: 0;
this._witnessSize = options._witnessSize != null if (options.block !== undefined) {
? options._witnessSize assert(options.block === null || typeof options.block === 'string');
: null; 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; return this;
}; };
@ -416,7 +437,7 @@ TX.prototype.getBaseSize = function getBaseSize() {
TX.prototype.hasWitness = function hasWitness() { TX.prototype.hasWitness = function hasWitness() {
var i; var i;
if (this._witnessSize != null) if (this._witnessSize !== -1)
return this._witnessSize !== 0; return this._witnessSize !== 0;
for (i = 0; i < this.inputs.length; i++) { for (i = 0; i < this.inputs.length; i++) {
@ -459,10 +480,9 @@ TX.prototype.signatureHash = function signatureHash(index, prev, type, version)
* @returns {Buffer} * @returns {Buffer}
*/ */
TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) { TX.prototype.signatureHashCopy = function signatureHashV0(index, prev, type) {
var p = new BufferWriter(); var p = new BufferWriter();
var empty = new Script(); var empty = new Script();
var witness = new bcoin.witness();
var i, copy, input, output; var i, copy, input, output;
if (typeof index !== 'number') if (typeof index !== 'number')
@ -484,7 +504,6 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
input.prevout = this.inputs[i].prevout; input.prevout = this.inputs[i].prevout;
input.script = this.inputs[i].script; input.script = this.inputs[i].script;
input.sequence = this.inputs[i].sequence; input.sequence = this.inputs[i].sequence;
input.witness = witness;
copy.inputs.push(input); copy.inputs.push(input);
} }
@ -553,6 +572,134 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) {
return utils.hash256(p.render()); 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). * Witness sighashing -- O(n).
* @private * @private
@ -777,7 +924,7 @@ TX.prototype.getInputValue = function getInputValue() {
var total = 0; var total = 0;
var i; var i;
if (this._inputValue != null) if (this._inputValue !== -1)
return this._inputValue; return this._inputValue;
if (!this.hasCoins()) if (!this.hasCoins())
@ -801,7 +948,7 @@ TX.prototype.getOutputValue = function getOutputValue() {
var total = 0; var total = 0;
var i; var i;
if (this._outputValue != null) if (this._outputValue !== -1)
return this._outputValue; return this._outputValue;
for (i = 0; i < this.outputs.length; i++) for (i = 0; i < this.outputs.length; i++)

View File

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

View File

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

View File

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

View File

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

View File

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