whole bunch of refactoring.

This commit is contained in:
Christopher Jeffrey 2016-05-18 04:23:05 -07:00
parent a2ddb960f5
commit 6005f0f750
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
9 changed files with 157 additions and 279 deletions

View File

@ -52,10 +52,12 @@ function AbstractBlock(data) {
this.height = data.height != null ? data.height : -1;
this.txs = null;
this.valid = null;
this.mutable = !!data.mutable;
this._valid = null;
this._hash = null;
this._size = data._size || 0;
this._size = null;
this._witnessSize = null;
}
/**
@ -65,10 +67,15 @@ function AbstractBlock(data) {
*/
AbstractBlock.prototype.hash = function hash(enc) {
if (!this._hash)
this._hash = utils.dsha256(this.abbr());
var hash = this._hash;
return enc === 'hex' ? this._hash.toString('hex') : this._hash;
if (!hash) {
hash = utils.dsha256(this.abbr());
if (!this.mutable)
this._hash = hash;
}
return enc === 'hex' ? hash.toString('hex') : hash;
};
/**
@ -80,15 +87,6 @@ AbstractBlock.prototype.abbr = function abbr() {
return bcoin.protocol.framer.blockHeaders(this);
};
/**
* Get the full block size (this may be cached).
* @returns {Number}
*/
AbstractBlock.prototype.getSize = function getSize() {
return this._size || this.render().length;
};
/**
* Verify the block.
* @param {Object?} ret - Return object, may be
@ -97,9 +95,15 @@ AbstractBlock.prototype.getSize = function getSize() {
*/
AbstractBlock.prototype.verify = function verify(ret) {
if (this.valid == null)
this.valid = this._verify(ret);
return this.valid;
var valid = this._valid;
if (valid == null) {
valid = this._verify(ret);
if (!this.mutable)
this._valid = valid;
}
return valid;
};
/**

View File

@ -39,7 +39,7 @@ var BufferReader = require('./reader');
*/
function Block(data) {
var self = this;
var i, tx;
if (!(this instanceof Block))
return new Block(data);
@ -47,19 +47,18 @@ function Block(data) {
bcoin.abstractblock.call(this, data);
this.type = 'block';
this._witnessSize = data._witnessSize || 0;
this.txs = data.txs || [];
this._cbHeight = null;
this._commitmentHash = null;
this.txs = this.txs.map(function(data, i) {
if (data instanceof bcoin.tx)
return data;
for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i];
return bcoin.tx(data, self, i);
});
if (tx instanceof bcoin.tx)
continue;
this.txs[i] = new bcoin.tx(tx, this, i);
}
}
utils.inherits(Block, bcoin.abstractblock);
@ -105,79 +104,77 @@ Block.prototype.getRaw = function getRaw() {
else
raw = bcoin.protocol.framer.block(this);
this._size = raw.length;
this._witnessSize = raw._witnessSize;
if (!this.mutable) {
this._size = raw.length;
this._witnessSize = raw._witnessSize;
}
return raw;
};
Block.prototype._getSize = function _getSize() {
var sizes = bcoin.protocol.framer.block.sizes(this);
this._size = sizes.size;
this._witnessSize = sizes.witnessSize;
/**
* Calculate real size and size of the witness bytes.
* @returns {Object} Contains `size` and `witnessSize`.
*/
Block.prototype.getSizes = function getSizes() {
var sizes;
if (this._size != null) {
return {
size: this._size,
witnessSize: this._witnessSize
};
}
sizes = bcoin.protocol.framer.block.sizes(this);
if (!this.mutable) {
this._size = sizes.size;
this._witnessSize = sizes.witnessSize;
}
return sizes;
};
/**
* Calculate virtual block size.
* @param {Boolean?} force - If true, always recalculate.
* @returns {Number} Virtual size.
*/
Block.prototype.getVirtualSize = function getVirtualSize(force) {
Block.prototype.getVirtualSize = function getVirtualSize() {
var scale = constants.WITNESS_SCALE_FACTOR;
return (this.getCost() + scale - 1) / scale | 0;
};
/**
* Calculate block cost.
* @param {Boolean?} force - If true, always recalculate.
* @returns {Number} cost
*/
Block.prototype.getCost = function getCost(force) {
var size, witnessSize, base;
size = this.getSize(force);
witnessSize = this.getWitnessSize(force);
base = size - witnessSize;
return base * (constants.WITNESS_SCALE_FACTOR - 1) + size;
Block.prototype.getCost = function getCost() {
var sizes = this.getSizes();
var base = sizes.size - sizes.witnessSize;
return base * (constants.WITNESS_SCALE_FACTOR - 1) + sizes.size;
};
/**
* Get real block size.
* @param {Boolean?} force - If true, always recalculate.
* @returns {Number} size
*/
Block.prototype.getSize = function getSize(force) {
if (force || this._size === 0)
this._getSize();
return this._size;
Block.prototype.getSize = function getSize() {
return this.getSizes().size;
};
/**
* Get base block size (without witness).
* @param {Boolean?} force - If true, always recalculate.
* @returns {Number} size
*/
Block.prototype.getBaseSize = function getBaseSize(force) {
if (force || this._size === 0)
this._getSize();
return this._size - this._witnessSize;
};
/**
* Get the total size of the witnesses.
* @param {Boolean?} force - If true, always recalculate.
* @returns {Number} witness size
*/
Block.prototype.getWitnessSize = function getWitnessSize(force) {
if (force || this._size === 0)
this._getSize();
return this._witnessSize;
Block.prototype.getBaseSize = function getBaseSize() {
var sizes = this.getSizes();
return sizes.size - sizes.witnessSize;
};
/**
@ -314,8 +311,10 @@ Block.prototype.__defineGetter__('commitmentHash', function() {
}
}
if (commitmentHash)
this._commitmentHash = commitmentHash.toString('hex');
if (!this.mutable) {
if (commitmentHash)
this._commitmentHash = commitmentHash.toString('hex');
}
return this._commitmentHash;
});
@ -420,7 +419,8 @@ Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
height = coinbase.inputs[0].script.getCoinbaseHeight();
this._cbHeight = height;
if (!this.mutable)
this._cbHeight = height;
return height;
};

View File

@ -510,6 +510,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
return child;
hardened = index >= constants.hd.HARDENED ? true : hardened;
if (index < constants.hd.HARDENED && hardened)
index += constants.hd.HARDENED;
@ -565,7 +566,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
HDPrivateKey.prototype.deriveAccount44 = function deriveAccount44(accountIndex) {
var coinType;
assert(utils.isNumber(accountIndex), 'accountIndex must be a number.');
assert(utils.isNumber(accountIndex), 'Account index must be a number.');
if (this instanceof HDPublicKey) {
assert(this.isAccount44(accountIndex), 'Cannot derive account index.');

View File

@ -64,9 +64,7 @@ Headers.prototype._verify = function _verify(ret) {
*/
Headers.prototype.getSize = function getSize() {
if (this._size == null)
this.getRaw();
return this._size;
return 80;
};
/**
@ -75,11 +73,7 @@ Headers.prototype.getSize = function getSize() {
*/
Headers.prototype.getRaw = function getRaw() {
if (!this._raw) {
this._raw = bcoin.protocol.framer.headers([this]);
this._size = this._raw.length;
}
return this._raw;
return this.abbr();
};
/**
@ -127,7 +121,7 @@ Headers.parseRaw = function parseRaw(data, enc) {
if (enc === 'hex')
data = new Buffer(data, 'hex');
return bcoin.protocol.parser.parseHeaders(data)[0];
return bcoin.protocol.parser.parseBlockHeaders(data);
};
/**

View File

@ -68,24 +68,6 @@ MerkleBlock.prototype.render = function render() {
return this.getRaw();
};
/**
* Serialize the merkleblock.
* @returns {Buffer}
*/
MerkleBlock.prototype.renderNormal = function renderNormal() {
return this.getRaw();
};
/**
* Serialize the merkleblock.
* @returns {Buffer}
*/
MerkleBlock.prototype.renderWitness = function renderWitness() {
return this.getRaw();
};
/**
* Get merkleblock size.
* @returns {Number} Size.
@ -152,7 +134,7 @@ MerkleBlock.prototype.verifyPartial = function verifyPartial() {
height++;
function visit(depth) {
var flag, left, right;
var hash, flag, left, right;
if (i === flags.length * 8 || j === hashes.length)
return null;
@ -162,8 +144,9 @@ MerkleBlock.prototype.verifyPartial = function verifyPartial() {
if (flag === 0 || depth === height) {
if (depth === height) {
tx.push(hashes[j].toString('hex'));
txMap[tx[tx.length - 1]] = true;
hash = hashes[j].toString('hex');
tx.push(hash);
txMap[hash] = true;
}
return hashes[j++];
}

View File

@ -397,6 +397,7 @@ function MinerBlock(options) {
// Create our block
this.block = new bcoin.block({
mutable: true,
version: options.version,
prevBlock: this.tip.hash,
merkleRoot: constants.NULL_HASH,
@ -476,7 +477,7 @@ MinerBlock.prototype.addTX = function addTX(tx) {
if (tx.mutable)
tx = tx.toTX();
cost = this.block.getCost(true) + tx.getCost();
cost = this.block.getCost() + tx.getCost();
if (cost > constants.block.MAX_COST)
return false;

View File

@ -78,8 +78,13 @@ function MTX(options) {
this._hash = null;
this._whash = null;
this._raw = null;
this._size = 0;
this._witnessSize = 0;
this._size = null;
this._witnessSize = null;
this._outputValue = null;
this._inputValue = null;
this._hashPrevouts = null;
this._hashSequence = null;
this._hashOutputs = null;
if (options.inputs) {
for (i = 0; i < options.inputs.length; i++)
@ -110,128 +115,6 @@ MTX.prototype.clone = function clone() {
return tx;
};
/**
* Hash the transaction with the non-witness serialization.
* Note that this is not cached.
* @param {String?} enc - Can be `'hex'` or `null`.
* @returns {Hash|Buffer} hash
*/
MTX.prototype.hash = function hash(enc) {
var hash = utils.dsha256(this.renderNormal());
return enc === 'hex' ? hash.toString('hex') : hash;
};
/**
* Hash the transaction with the witness
* serialization, return the wtxid (normal
* hash if no witness is present, all zeroes
* if coinbase). Note that this is not cached.
* @param {String?} enc - Can be `'hex'` or `null`.
* @returns {Hash|Buffer} hash
*/
MTX.prototype.witnessHash = function witnessHash(enc) {
var hash;
if (this.isCoinbase()) {
return enc === 'hex'
? constants.NULL_HASH
: utils.slice(constants.ZERO_HASH);
}
if (!this.hasWitness())
return this.hash(enc);
hash = utils.dsha256(this.renderWitness());
return enc === 'hex' ? hash.toString('hex') : hash;
};
/**
* Serialize the transaction. Note
* that this is _not_ cached. This will use
* the witness serialization if a
* witness is present.
* @returns {Buffer} Serialized transaction.
*/
MTX.prototype.render = function render() {
return this.getRaw();
};
/**
* Serialize the transaction without the
* witness vector, regardless of whether it
* is a witness transaction or not. Note
* that this is _not_ cached.
* @returns {Buffer} Serialized transaction.
*/
MTX.prototype.renderNormal = function renderNormal() {
return bcoin.protocol.framer.tx(this);
};
/**
* Serialize the transaction with the
* witness vector, regardless of whether it
* is a witness transaction or not. Note that
* this is _not_ cached.
* @returns {Buffer} Serialized transaction.
*/
MTX.prototype.renderWitness = function renderWitness() {
return bcoin.protocol.framer.witnessTX(this);
};
/**
* Serialize the transaction. Note
* that this is cached. This will use
* the witness serialization if a
* witness is present. Note that this
* is _not_ cached.
* @returns {Buffer} Serialized transaction.
*/
MTX.prototype.getRaw = function getRaw() {
if (this.hasWitness())
return bcoin.protocol.framer.witnessTX(this);
return bcoin.protocol.framer.tx(this);
};
/**
* Calculate the real size of the transaction
* with the witness included. Note that this
* is _not_ cached.
* @returns {Number} size
*/
MTX.prototype.getSize = function getSize() {
return bcoin.protocol.framer.tx.witnessSize(this);
};
/**
* Calculate the size of the transaction
* with the witness excluded. Note that this
* is _not_ cached.
* @returns {Number} size
*/
MTX.prototype.getBaseSize = function getBaseSize() {
return bcoin.protocol.framer.tx.size(this);
};
/**
* Calculate the virtual size of the transaction.
* Note that this is _not_ cached.
* @returns {Number} vsize
*/
MTX.prototype.getVirtualSize = function getVirtualSize() {
return bcoin.protocol.framer.tx.virtualSize(this);
};
/**
* Add an input to the transaction.
* @example
@ -246,8 +129,6 @@ MTX.prototype.getVirtualSize = function getVirtualSize() {
MTX.prototype.addInput = function addInput(options, index) {
var input;
assert(this.ts === 0, 'Cannot modify a confirmed tx.');
if (options instanceof bcoin.tx)
options = bcoin.coin(options, index);
@ -282,8 +163,6 @@ MTX.prototype.addInput = function addInput(options, index) {
MTX.prototype.scriptInput = function scriptInput(index, addr) {
var input, prev, n, i, redeemScript, witnessScript, vector, dummy;
assert(this.ts === 0, 'Cannot modify a confirmed tx.');
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
@ -487,8 +366,6 @@ MTX.prototype.signInput = function signInput(index, addr, type) {
var input, prev, signature, index, signatures, i;
var len, m, n, keys, vector, dummy, version;
assert(this.ts === 0, 'Cannot modify a confirmed tx.');
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
@ -790,8 +667,6 @@ MTX.prototype.sign = function sign(index, addr, type) {
MTX.prototype.addOutput = function addOutput(address, value) {
var options, output;
assert(this.ts === 0, 'Cannot modify a confirmed tx.');
if ((address instanceof bcoin.wallet) || (address instanceof bcoin.keyring))
address = address.getAddress();
@ -822,8 +697,6 @@ MTX.prototype.addOutput = function addOutput(address, value) {
MTX.prototype.scriptOutput = function scriptOutput(index, options) {
var output;
assert(this.ts === 0, 'Cannot modify a confirmed tx.');
if (options instanceof bcoin.output)
return;
@ -897,7 +770,7 @@ MTX.prototype.maxSize = function maxSize(options, force) {
wallet = options.wallet;
// Calculate the size, minus the input scripts.
total = bcoin.protocol.framer.tx.size(this);
total = this.getBaseSize();
for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i];
@ -1157,7 +1030,7 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) {
// Calculate max possible size after signing.
size = tx.maxSize(options, true);
if (tryFree && options.height > 0) {
if (tryFree && options.height >= 0) {
// Note that this will only work
// if the mempool's rolling reject
// fee is zero (i.e. the mempool is
@ -1204,7 +1077,7 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) {
min = fee + output.getDustThreshold();
if (output.value < 0)
if (output.value < min)
throw new Error('Could not subtract fee.');
output.value -= fee;
@ -1241,7 +1114,6 @@ MTX.prototype.selectCoins = function selectCoins(coins, options) {
MTX.prototype.fill = function fill(coins, options) {
var result, i, change;
assert(this.ts === 0, 'Cannot modify a confirmed tx.');
assert(this.inputs.length === 0, 'TX is already filled.');
assert(options, '`options` are required.');
assert(options.changeAddress, '`changeAddress` is required.');
@ -1282,8 +1154,6 @@ MTX.prototype.fill = function fill(coins, options) {
MTX.prototype.sortMembers = function sortMembers() {
var changeOutput;
assert(this.ts === 0, 'Cannot modify a confirmed tx.');
if (this.changeIndex !== -1) {
changeOutput = this.outputs[this.changeIndex];
assert(changeOutput);
@ -1338,8 +1208,6 @@ MTX.prototype.avoidFeeSniping = function avoidFeeSniping(height) {
MTX.prototype.setLocktime = function setLocktime(locktime) {
var i, input;
assert(this.ts === 0, 'Cannot modify a confirmed tx.');
for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i];
if (input.sequence === 0xffffffff)
@ -1391,16 +1259,6 @@ MTX.fromExtended = function fromExtended(data, enc) {
return new MTX(MTX.parseExtended(data, enc));
};
/**
* Convert a TX to an MTX.
* @param {TX} tx
* @returns {MTX}
*/
MTX.fromTX = function fromTX(tx) {
return new MTX(tx);
};
/**
* Convert the MTX to a TX.
* @returns {TX}

View File

@ -74,14 +74,18 @@ function TX(data, block, index) {
this.index = data.index != null ? data.index : -1;
this.ps = this.ts === 0 ? (data.ps != null ? data.ps : utils.now()) : 0;
this.height = data.height != null ? data.height : -1;
this.mutable = false;
this._hash = null;
this._whash = null;
this._raw = data._raw || null;
this._size = data._size || 0;
this._witnessSize = data._witnessSize || 0;
this._raw = null;
this._size = null;
this._witnessSize = null;
this._outputValue = null;
this._inputValue = null;
this._hashPrevouts = null;
this._hashSequence = null;
this._hashOutputs = null;
for (i = 0; i < data.inputs.length; i++)
this.inputs.push(new bcoin.input(data.inputs[i]));
@ -182,11 +186,16 @@ TX.prototype.unsetBlock = function unsetBlock() {
* @returns {Hash|Buffer} hash
*/
TX.prototype.hash = function hash(enc) {
if (!this._hash)
this._hash = utils.dsha256(this.renderNormal());
TX.prototype.hash = function _hash(enc) {
var hash = this._hash;
return enc === 'hex' ? this._hash.toString('hex') : this._hash;
if (!hash) {
hash = utils.dsha256(this.renderNormal());
if (!this.mutable)
this._hash = hash;
}
return enc === 'hex' ? hash.toString('hex') : hash;
};
/**
@ -199,6 +208,8 @@ TX.prototype.hash = function hash(enc) {
*/
TX.prototype.witnessHash = function witnessHash(enc) {
var hash = this._whash;
if (this.isCoinbase()) {
return enc === 'hex'
? constants.NULL_HASH
@ -208,10 +219,13 @@ TX.prototype.witnessHash = function witnessHash(enc) {
if (!this.hasWitness())
return this.hash(enc);
if (!this._whash)
this._whash = utils.dsha256(this.renderWitness());
if (!hash) {
hash = utils.dsha256(this.renderWitness());
if (!this.mutable)
this._whash = hash;
}
return enc === 'hex' ? this._whash.toString('hex') : this._whash;
return enc === 'hex' ? hash.toString('hex') : hash;
};
/**
@ -276,13 +290,32 @@ TX.prototype.getRaw = function getRaw() {
else
raw = bcoin.protocol.framer.tx(this);
this._raw = raw;
this._size = raw.length;
this._witnessSize = raw._witnessSize;
if (!this.mutable) {
this._raw = raw;
this._size = raw.length;
this._witnessSize = raw._witnessSize;
}
return raw;
};
/**
* Calculate real size and size of the witness bytes.
* @returns {Object} Contains `size` and `witnessSize`.
*/
TX.prototype.getSizes = function getSizes() {
if (this.mutable)
return bcoin.protocol.framer.tx.sizes(this);
this.getRaw();
return {
size: this._size,
witnessSize: this._witnessSize
};
};
/**
* Calculate the virtual size of the transaction.
* Note that this is cached.
@ -301,15 +334,9 @@ TX.prototype.getVirtualSize = function getVirtualSize() {
*/
TX.prototype.getCost = function getCost() {
var size, witnessSize, base;
this.getRaw();
size = this._size;
witnessSize = this._witnessSize;
base = size - witnessSize;
return base * (constants.WITNESS_SCALE_FACTOR - 1) + size;
var sizes = this.getSizes();
var base = sizes.size - sizes.witnessSize;
return base * (constants.WITNESS_SCALE_FACTOR - 1) + sizes.size;
};
/**
@ -319,7 +346,7 @@ TX.prototype.getCost = function getCost() {
*/
TX.prototype.getSize = function getSize() {
return this.getRaw().length;
return this.getSizes().size;
};
/**
@ -330,8 +357,8 @@ TX.prototype.getSize = function getSize() {
*/
TX.prototype.getBaseSize = function getBaseSize() {
this.getRaw();
return this._size - this._witnessSize;
var sizes = this.getSizes();
return sizes.size - sizes.witnessSize;
};
/**

View File

@ -779,6 +779,7 @@ Wallet.prototype.getTX = function getTX(hash, callback) {
Wallet.prototype.createTX = function createTX(options, outputs, callback) {
var self = this;
var height = 0xffffffff;
var tx, i;
if (typeof outputs === 'function') {
@ -794,6 +795,9 @@ Wallet.prototype.createTX = function createTX(options, outputs, callback) {
if (!Array.isArray(outputs))
outputs = [outputs];
if (options.height >= 0)
height = options.height;
// Create mutable tx
tx = bcoin.mtx();
@ -819,7 +823,13 @@ Wallet.prototype.createTX = function createTX(options, outputs, callback) {
// if (options.locktime != null)
// tx.setLocktime(options.locktime);
// else
// tx.avoidFeeSniping();
// tx.avoidFeeSniping(options.height);
if (!tx.isSane())
return callback(new Error('CheckTransaction failed.'));
if (!tx.checkInputs(height))
return callback(new Error('CheckInputs failed.'));
// Sign the transaction
if (!self.sign(tx))