better witnessSize.

This commit is contained in:
Christopher Jeffrey 2016-02-28 10:23:39 -08:00
parent 8755b16235
commit d53050993c
4 changed files with 176 additions and 144 deletions

View File

@ -42,61 +42,58 @@ function Block(data) {
utils.inherits(Block, bcoin.abstractblock);
Block.prototype.render = function render() {
if (this._raw) {
if (this._witnessSize === 0)
return this._raw;
return bcoin.protocol.framer.block(this);
}
return this.getRaw();
};
if (this.hasWitness())
return bcoin.protocol.framer.block(this);
Block.prototype.renderNormal = function renderNormal() {
if (!this._witnessSize)
return this._raw;
this._raw = bcoin.protocol.framer.block(this);
this._size = this._raw.length;
this._witnessSize = 0;
return this._raw;
return bcoin.protocol.framer.block(this);
};
Block.prototype.renderWitness = function renderWitness() {
this.getRaw();
if (this._witnessSize)
return this._raw;
return bcoin.protocol.framer.witnessBlock(this);
};
Block.prototype.getRaw = function getRaw() {
if (this._raw) {
if (this._witnessSize > 0)
return this._raw;
return bcoin.protocol.framer.witnessBlock(this);
assert(this._size > 0);
assert(this._witnessSize >= 0);
return this._raw;
}
if (!this.hasWitness())
return bcoin.protocol.framer.witnessBlock(this);
if (this.hasWitness())
raw = bcoin.protocol.framer.witnessBlock(this);
else
raw = bcoin.protocol.framer.block(this);
this._raw = bcoin.protocol.framer.witnessBlock(this);
this._size = this._raw.length;
this._witnessSize = this._raw._witnessSize;
this._raw = raw;
this._size = raw.length;
this._witnessSize = raw._witnessSize;
return this._raw;
};
Block.prototype.getBlockSize = function getBlockSize() {
var size = this._size;
var witnessSize = this._witnessSize;
var raw, base;
Block.prototype.getVirtualSize = function getVirtualSize() {
var size, witnessSize, base;
if (!this._size) {
raw = this.renderWitness();
size = raw.length;
witnessSize = raw._witnessSize;
}
this.getRaw();
// Virtual size:
if (witnessSize > 0) {
base = size - witnessSize;
return (base * 4 + witnessSize + 3) / 4 | 0;
}
size = this._size;
witnessSize = this._witnessSize;
base = size - witnessSize;
return size;
return (base * 4 + witnessSize + 3) / 4 | 0;
};
Block.prototype.getSize = function getSize() {
return this._raw.length;
return this.getRaw().length;
};
Block.prototype.hasWitness = function hasWitness() {
@ -186,7 +183,7 @@ Block.prototype._verify = function _verify() {
// Size can't be bigger than MAX_BLOCK_SIZE
if (this.txs.length > constants.block.maxSize
|| this.getBlockSize() > constants.block.maxSize) {
|| this.getVirtualSize() > constants.block.maxSize) {
utils.debug('Block is too large: %s', this.rhash);
return false;
}

View File

@ -40,6 +40,7 @@ function MTX(options) {
this._raw = null;
this._size = 0;
this._offset = 0;
this._witnessSize = 0;
this.height = -1;
@ -78,16 +79,32 @@ MTX.prototype.clone = function clone() {
};
MTX.prototype.hash = function hash(enc) {
var hash = utils.dsha256(this.render());
var hash = utils.dsha256(this.renderNormal());
return enc === 'hex' ? utils.toHex(hash) : hash;
};
MTX.prototype.witnessHash = function hash(enc) {
var hash = utils.dsha256(this.renderWitness());
MTX.prototype.witnessHash = function witnessHash(enc) {
var raw, hash;
if (this.isCoinbase()) {
return enc === 'hex'
? utils.toHex(constants.zeroHash)
: new Buffer(constants.zeroHash);
}
if (!this.hasWitness())
return this.hash(enc);
hash = utils.dsha256(this.renderWitness());
return enc === 'hex' ? utils.toHex(hash) : hash;
};
MTX.prototype.render = function render() {
return this.getRaw();
};
MTX.prototype.renderNormal = function renderNormal() {
return bcoin.protocol.framer.tx(this);
};
@ -95,8 +112,24 @@ MTX.prototype.renderWitness = function renderWitness() {
return bcoin.protocol.framer.witnessTX(this);
};
MTX.prototype.getRaw = function getRaw() {
if (this.hasWitness())
return bcoin.protocol.framer.witnessTX(this);
return bcoin.protocol.framer.tx(this);
};
MTX.prototype.getSize = function getSize() {
return this.render().length;
return this.getRaw().length;
};
MTX.prototype.getVirtualSize = function getVirtualSize() {
var raw = this.getRaw();
var size = raw.length;
var witnessSize = raw._witnessSize;
var base = size - witnessSize;
return (base * 4 + witnessSize + 3) / 4 | 0;
};
MTX.prototype.addInput = function addInput(options, index) {
@ -648,6 +681,7 @@ MTX.prototype.scriptOutput = function scriptOutput(index, options) {
MTX.prototype.maxSize = function maxSize(maxM, maxN) {
var copy = this.clone();
var i, j, input, total, size, prev, m, n;
var witness;
// Create copy with 0-script inputs
for (i = 0; i < copy.inputs.length; i++) {
@ -661,6 +695,7 @@ MTX.prototype.maxSize = function maxSize(maxM, maxN) {
for (i = 0; i < copy.inputs.length; i++) {
input = copy.inputs[i];
size = 0;
witness = false;
assert(input.output);
@ -670,18 +705,22 @@ MTX.prototype.maxSize = function maxSize(maxM, maxN) {
// If we have access to the redeem script,
// we can use it to calculate size much easier.
if (this.inputs[i].script.length && bcoin.script.isScripthash(prev)) {
prev = bcoin.script.getRedeem(this.inputs[i].script);
// Need to add the redeem script size
// here since it will be ignored by
// the isMultisig clause.
// OP_PUSHDATA2 [redeem]
size += 3 + bcoin.script.getSize(prev);
prev = this.inputs[i].script[this.inputs[i].script.length - 1];
size += utils.sizeIntv(prev.length) + prev.length;
prev = bcoin.script.decode(prev);
}
if (this.inputs[i].witness.length) {
if (bcoin.script.isWitnessScripthash(prev)) {
prev = bcoin.script.getRedeem(this.inputs[i].witness);
size += 3 + bcoin.script.getSize(prev);
if (bcoin.script.isWitnessProgram(prev)) {
witness = true;
size *= 4;
if (this.inputs[i].witness.length && bcoin.script.isWitnessScripthash(prev)) {
prev = this.inputs[i].witness[this.inputs[i].witness.length - 1];
size += utils.sizeIntv(prev.length) + prev.length;
prev = bcoin.script.decode(prev);
} else if (bcoin.script.isWitnessPubkeyhash(prev)) {
prev = bcoin.script.createPubkeyhash(prev[1]);
}
@ -744,6 +783,9 @@ MTX.prototype.maxSize = function maxSize(maxM, maxN) {
// Byte for varint size of input script
size += utils.sizeIntv(size);
if (witness)
size = (size + 3) / 4 | 0;
total += size;
}
@ -1027,17 +1069,19 @@ MTX.prototype.setLocktime = function setLocktime(locktime) {
};
MTX.prototype.increaseFee = function increaseFee(unspent, address, fee) {
var i, input, result;
var i, input;
this.inputs.length = 0;
if (this.changeIndex !== -1)
if (this.changeIndex !== -1) {
this.outputs.splice(this.changeIndex, 1);
this.changeIndex = -1;
}
if (!fee)
fee = this.getFee().add(new bn(10000));
result = this.fill(unspent, address, fee);
this.fill(unspent, address, fee);
for (i = 0; i < this.inputs.length; i++) {
input = this.inputs[i];

View File

@ -507,6 +507,7 @@ Framer.witnessTX = function _witnessTX(tx) {
+ 2
+ utils.sizeIntv(tx.inputs.length) + inputSize
+ utils.sizeIntv(tx.outputs.length) + outputSize
+ utils.sizeIntv(witnesses.length) + witnessSize
+ 4);
off += utils.write32(p, tx.version, off);
@ -609,23 +610,18 @@ Framer.witnessBlock = function _witnessBlock(block) {
return Framer._block(block, true);
};
Framer._block = function _block(block, witness) {
Framer._block = function _block(block, useWitness) {
var off = 0;
var txSize = 0;
var witnessSize = 0;
var txs = [];
var hasWitness;
var i, tx, p;
for (i = 0; i < block.txs.length; i++) {
if (witness) {
hasWitness = block.txs[i].hasWitness
? block.txs[i].hasWitness()
: block.txs[i]._witness;
}
tx = hasWitness
tx = useWitness && bcoin.tx.prototype.hasWitness.call(block.txs[i])
? Framer.witnessTX(block.txs[i])
: Framer.tx(block.txs[i]);
txs.push(tx);
txSize += tx.length;
witnessSize += tx._witnessSize;

View File

@ -37,6 +37,7 @@ function TX(data, block, index) {
this._raw = data._raw || null;
this._size = data._size || 0;
this._offset = data._offset || 0;
this._witnessSize = data._witnessSize || 0;
this.height = data.height != null ? data.height : -1;
@ -72,41 +73,18 @@ TX.prototype.setBlock = function setBlock(block, index) {
TX.prototype.clone = function clone() {
var tx = new TX(this);
// tx.inputs = tx.inputs.map(function(input) {
// var _raw = input.script._raw;
// input.script = input.script.slice();
// if (_raw)
// utils.hidden(input.script, '_raw', _raw);
// return input;
// });
// tx.outputs = tx.outputs.map(function(output) {
// var _raw = output.script._raw;
// output.script = output.script.slice();
// if (_raw)
// utils.hidden(output.script, '_raw', _raw);
// return output;
// });
delete tx._raw;
delete tx._size;
delete tx._offset;
delete tx._hash;
delete tx._whash;
delete tx._witnessSize;
return tx;
};
TX.prototype.txid = function txid(enc) {
if (this.hasWitness())
return this.witnessHash(enc);
return this.hash(enc);
};
TX.prototype.hash = function hash(enc) {
if (!this._hash)
this._hash = utils.dsha256(this.render());
this._hash = utils.dsha256(this.renderNormal());
return enc === 'hex' ? utils.toHex(this._hash) : this._hash;
};
@ -127,6 +105,61 @@ TX.prototype.witnessHash = function witnessHash(enc) {
return enc === 'hex' ? utils.toHex(this._whash) : this._whash;
};
TX.prototype.render = function render() {
return this.getRaw();
};
TX.prototype.renderNormal = function renderNormal() {
var raw = this.getRaw();
if (!bcoin.protocol.parser.isWitnessTX(raw))
return raw;
return bcoin.protocol.framer.tx(this);
};
TX.prototype.renderWitness = function renderWitness() {
var raw = this.getRaw();
if (bcoin.protocol.parser.isWitnessTX(raw))
return raw;
return bcoin.protocol.framer.witnessTX(this);
};
TX.prototype.getRaw = function getRaw() {
var raw;
if (this._raw) {
assert(this._size > 0);
assert(this._witnessSize >= 0);
return this._raw;
}
if (this.hasWitness())
raw = bcoin.protocol.framer.witnessTX(this);
else
raw = bcoin.protocol.framer.tx(this);
this._raw = raw;
this._size = raw.length;
this._witnessSize = raw._witnessSize;
return this._raw;
};
TX.prototype.getVirtualSize = function getVirtualSize() {
var size, witnessSize, base;
this.getRaw();
size = this._size;
witnessSize = this._witnessSize;
base = size - witnessSize;
return (base * 4 + witnessSize + 3) / 4 | 0;
};
TX.prototype.getSize = function getSize() {
return this.getRaw().length;
};
TX.prototype.hasWitness = function hasWitness() {
var i;
@ -138,46 +171,6 @@ TX.prototype.hasWitness = function hasWitness() {
return false;
};
TX.prototype.render = function render() {
if (this._raw) {
if (!bcoin.protocol.parser.isWitnessTX(this._raw))
return this._raw;
return bcoin.protocol.framer.tx(this);
}
if (this.hasWitness())
return bcoin.protocol.framer.tx(this);
this._raw = bcoin.protocol.framer.tx(this);
this._size = this._raw.length;
return this._raw;
};
TX.prototype.renderWitness = function renderWitness() {
if (this._raw) {
if (bcoin.protocol.parser.isWitnessTX(this._raw))
return this._raw;
// We probably shouldn't even render it
// as a witness tx if it doesn't have a witness.
return bcoin.protocol.framer.witnessTX(this);
}
// We probably shouldn't even render it
// as a witness tx if it doesn't have a witness.
if (!this.hasWitness())
return bcoin.protocol.framer.witnessTX(this);
this._raw = bcoin.protocol.framer.witnessTX(this);
this._size = this._raw.length;
return this._raw;
};
TX.prototype.getSize = function getSize() {
return this._raw.length;
};
TX.prototype._inputIndex = function _inputIndex(hash, index) {
var i, ex;
@ -212,9 +205,31 @@ TX.prototype.signatureHash = function signatureHash(index, s, type, version) {
};
TX.prototype.signatureHashV0 = function signatureHashV0(index, s, type) {
var copy = this.clone();
var i, msg, hash;
var copy = {
version: this.version,
inputs: [],
outputs: [],
locktime: this.locktime
};
for (i = 0; i < this.inputs.length; i++) {
copy.inputs.push({
prevout: this.inputs[i].prevout,
script: this.inputs[i].script.slice(),
witness: this.inputs[i].witness.slice(),
sequence: this.inputs[i].sequence
});
}
for (i = 0; i < this.outputs.length; i++) {
copy.outputs.push({
value: this.outputs[i].value,
script: this.outputs[i].script.slice()
});
}
if (typeof index !== 'number')
index = this.inputs.indexOf(index);
@ -379,26 +394,6 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, s, type) {
return hash;
};
TX.prototype.normalizedHash = function normalizedHash(enc, force) {
var copy = this.clone();
var i;
if (this.isCoinbase())
return this.hash(enc);
if (!this._nhash || force) {
for (i = 0; i < copy.inputs.length; i++)
copy.inputs[i].script = [];
copy = bcoin.protocol.framer.tx(copy);
this._nhash = utils.dsha256(copy);
}
return enc === 'hex'
? utils.toHex(this._nhash)
: this._nhash.slice();
};
TX.prototype.verify = function verify(index, force, flags) {
// Valid if included in block
if (!force && this.ts !== 0)