block/crypto: refactor merkle trees.
This commit is contained in:
parent
6520cf32e0
commit
d1e37582d1
@ -22,7 +22,7 @@ log-file: true
|
||||
# witness: true
|
||||
# prune: false
|
||||
use-checkpoints: true
|
||||
coin-cache: true
|
||||
coin-cache: 40000000
|
||||
index-tx: false
|
||||
index-address: false
|
||||
|
||||
|
||||
@ -280,7 +280,7 @@ Chain.prototype.isGenesis = function isGenesis(block) {
|
||||
Chain.prototype.verify = co(function* verify(block, prev) {
|
||||
var ret = new VerifyResult();
|
||||
var i, err, height, ts, tx, medianTime;
|
||||
var commitmentHash, ancestors, state;
|
||||
var commit, ancestors, state;
|
||||
|
||||
// Skip the genesis block.
|
||||
if (this.isGenesis(block))
|
||||
@ -358,15 +358,15 @@ Chain.prototype.verify = co(function* verify(block, prev) {
|
||||
|
||||
// Check the commitment hash for segwit.
|
||||
if (state.hasWitness()) {
|
||||
commitmentHash = block.commitmentHash;
|
||||
if (commitmentHash) {
|
||||
commit = block.getCommitmentHash();
|
||||
if (commit) {
|
||||
// These are totally malleable. Someone
|
||||
// may have even accidentally sent us
|
||||
// the non-witness version of the block.
|
||||
// We don't want to consider this block
|
||||
// "invalid" if either of these checks
|
||||
// fail.
|
||||
if (!block.witnessNonce) {
|
||||
if (!block.getWitnessNonce()) {
|
||||
err = new VerifyError(block,
|
||||
'invalid',
|
||||
'bad-witness-merkle-size',
|
||||
@ -375,7 +375,7 @@ Chain.prototype.verify = co(function* verify(block, prev) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (commitmentHash !== block.getCommitmentHash('hex')) {
|
||||
if (!util.equal(commit, block.createCommitmentHash())) {
|
||||
err = new VerifyError(block,
|
||||
'invalid',
|
||||
'bad-witness-merkle-match',
|
||||
@ -388,7 +388,7 @@ Chain.prototype.verify = co(function* verify(block, prev) {
|
||||
|
||||
// Blocks that do not commit to
|
||||
// witness data cannot contain it.
|
||||
if (!commitmentHash) {
|
||||
if (!commit) {
|
||||
if (block.hasWitness()) {
|
||||
err = new VerifyError(block,
|
||||
'invalid',
|
||||
|
||||
@ -217,59 +217,64 @@ crypto.hkdfExpand = function hkdfExpand(prk, info, len, alg) {
|
||||
|
||||
/**
|
||||
* Build a merkle tree from leaves.
|
||||
* Note that this will mutate the `leaves` array!
|
||||
* @param {Buffer[]} leaves
|
||||
* @returns {Buffer[]} Tree (in rare cases this may return null).
|
||||
* @returns {MerkleTree}
|
||||
*/
|
||||
|
||||
crypto.buildMerkleTree = function buildMerkleTree(leaves) {
|
||||
var tree = leaves.slice();
|
||||
crypto.createMerkleTree = function createMerkleTree(leaves) {
|
||||
var nodes = leaves;
|
||||
var size = leaves.length;
|
||||
var i, j, i2, hash, left, right, buf;
|
||||
var malleated = false;
|
||||
var i, j, k, hash, left, right, lr;
|
||||
|
||||
if (size > 1)
|
||||
buf = new Buffer(64);
|
||||
if (size === 0) {
|
||||
hash = new Buffer(32);
|
||||
hash.fill(0);
|
||||
nodes.push(hash);
|
||||
return new MerkleTree(nodes, malleated);
|
||||
}
|
||||
|
||||
lr = new Buffer(64);
|
||||
|
||||
for (j = 0; size > 1; size = ((size + 1) / 2) | 0) {
|
||||
for (i = 0; i < size; i += 2) {
|
||||
i2 = Math.min(i + 1, size - 1);
|
||||
left = tree[j + i];
|
||||
right = tree[j + i2];
|
||||
k = Math.min(i + 1, size - 1);
|
||||
left = nodes[j + i];
|
||||
right = nodes[j + k];
|
||||
|
||||
if (i2 === i + 1 && i2 + 1 === size
|
||||
if (k === i + 1 && k + 1 === size
|
||||
&& left.compare(right) === 0) {
|
||||
return;
|
||||
malleated = true;
|
||||
}
|
||||
|
||||
left.copy(buf, 0);
|
||||
right.copy(buf, 32);
|
||||
hash = crypto.hash256(buf);
|
||||
left.copy(lr, 0);
|
||||
right.copy(lr, 32);
|
||||
|
||||
tree.push(hash);
|
||||
hash = crypto.hash256(lr);
|
||||
|
||||
nodes.push(hash);
|
||||
}
|
||||
j += size;
|
||||
}
|
||||
|
||||
if (tree.length === 0)
|
||||
return;
|
||||
|
||||
return tree;
|
||||
return new MerkleTree(nodes, malleated);
|
||||
};
|
||||
|
||||
if (native)
|
||||
crypto.buildMerkleTree = native.buildMerkleTree;
|
||||
crypto.createMerkleTree = native.createMerkleTree;
|
||||
|
||||
/**
|
||||
* Calculate merkle root from leaves.
|
||||
* @param {Buffer[]} leaves
|
||||
* @returns {Buffer?} Merkle root.
|
||||
* @returns {MerkleRoot}
|
||||
*/
|
||||
|
||||
crypto.getMerkleRoot = function getMerkleRoot(leaves) {
|
||||
var tree = crypto.buildMerkleTree(leaves);
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
return tree[tree.length - 1];
|
||||
crypto.createMerkleRoot = function createMerkleRoot(leaves) {
|
||||
var tree = crypto.createMerkleTree(leaves);
|
||||
var hash = tree.nodes[tree.nodes.length - 1];
|
||||
var malleated = tree.malleated;
|
||||
return new MerkleRoot(hash, malleated);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -279,16 +284,16 @@ crypto.getMerkleRoot = function getMerkleRoot(leaves) {
|
||||
* @returns {Buffer[]} branch
|
||||
*/
|
||||
|
||||
crypto.getMerkleBranch = function getMerkleBranch(index, leaves) {
|
||||
var tree = crypto.buildMerkleTree(leaves);
|
||||
crypto.createMerkleBranch = function createMerkleBranch(index, leaves) {
|
||||
var size = leaves.length;
|
||||
var tree = crypto.createMerkleTree(leaves);
|
||||
var branch = [];
|
||||
var j = 0;
|
||||
var i;
|
||||
|
||||
for (; size > 1; size = (size + 1) / 2 | 0) {
|
||||
i = Math.min(index ^ 1, size - 1);
|
||||
branch.push(tree[j + i]);
|
||||
branch.push(tree.nodes[j + i]);
|
||||
index >>>= 1;
|
||||
j += size;
|
||||
}
|
||||
@ -304,26 +309,26 @@ crypto.getMerkleBranch = function getMerkleBranch(index, leaves) {
|
||||
* @returns {Buffer} Hash.
|
||||
*/
|
||||
|
||||
crypto.checkMerkleBranch = function checkMerkleBranch(hash, branch, index) {
|
||||
var i, otherside, buf;
|
||||
crypto.verifyMerkleBranch = function verifyMerkleBranch(hash, branch, index) {
|
||||
var i, otherside, lr;
|
||||
|
||||
if (branch.length === 0)
|
||||
return hash;
|
||||
|
||||
buf = new Buffer(64);
|
||||
lr = new Buffer(64);
|
||||
|
||||
for (i = 0; i < branch.length; i++) {
|
||||
otherside = branch[i];
|
||||
|
||||
if (index & 1) {
|
||||
otherside.copy(buf, 0);
|
||||
hash.copy(buf, 32);
|
||||
otherside.copy(lr, 0);
|
||||
hash.copy(lr, 32);
|
||||
} else {
|
||||
hash.copy(buf, 0);
|
||||
otherside.copy(buf, 32);
|
||||
hash.copy(lr, 0);
|
||||
otherside.copy(lr, 32);
|
||||
}
|
||||
|
||||
hash = crypto.hash256(buf);
|
||||
hash = crypto.hash256(lr);
|
||||
index >>>= 1;
|
||||
}
|
||||
|
||||
@ -331,7 +336,7 @@ crypto.checkMerkleBranch = function checkMerkleBranch(hash, branch, index) {
|
||||
};
|
||||
|
||||
if (native)
|
||||
crypto.checkMerkleBranch = native.checkMerkleBranch;
|
||||
crypto.verifyMerkleBranch = native.verifyMerkleBranch;
|
||||
|
||||
/**
|
||||
* Encrypt with aes-256-cbc.
|
||||
@ -465,3 +470,17 @@ crypto.randomRange = function randomRange(min, max) {
|
||||
var num = crypto.randomInt();
|
||||
return Math.floor((num / 0x100000000) * (max - min) + min);
|
||||
};
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
function MerkleTree(nodes, malleated) {
|
||||
this.nodes = nodes;
|
||||
this.malleated = malleated;
|
||||
}
|
||||
|
||||
function MerkleRoot(hash, malleated) {
|
||||
this.hash = hash;
|
||||
this.malleated = malleated;
|
||||
}
|
||||
|
||||
@ -19,10 +19,10 @@ exports.scrypt = crypto.scrypt;
|
||||
exports.scryptAsync = crypto.scryptAsync;
|
||||
exports.hkdfExtract = crypto.hkdfExtract;
|
||||
exports.hkdfExpand = crypto.hkdfExpand;
|
||||
exports.buildMerkleTree = crypto.buildMerkleTree;
|
||||
exports.getMerkleRoot = crypto.getMerkleRoot;
|
||||
exports.getMerkleBranch = crypto.getMerkleBranch;
|
||||
exports.checkMerkleBranch = crypto.checkMerkleBranch;
|
||||
exports.createMerkleTree = crypto.createMerkleTree;
|
||||
exports.createMerkleRoot = crypto.createMerkleRoot;
|
||||
exports.createMerkleBranch = crypto.createMerkleBranch;
|
||||
exports.verifyMerkleBranch = crypto.verifyMerkleBranch;
|
||||
exports.encipher = crypto.encipher;
|
||||
exports.decipher = crypto.decipher;
|
||||
exports.ccmp = crypto.ccmp;
|
||||
|
||||
@ -107,7 +107,16 @@ MinerBlock.prototype._init = function _init() {
|
||||
var scale = constants.WITNESS_SCALE_FACTOR;
|
||||
var block = this.block;
|
||||
var cb = this.coinbase;
|
||||
var input, output, hash, witnessNonce;
|
||||
var input, output, nonce;
|
||||
|
||||
// Setup our block.
|
||||
block.version = this.version;
|
||||
block.prevBlock = this.tip.hash;
|
||||
block.merkleRoot = constants.NULL_HASH;
|
||||
block.ts = Math.max(time.now(), this.tip.ts + 1);
|
||||
block.bits = this.bits;
|
||||
block.nonce = 0;
|
||||
block.height = this.height;
|
||||
|
||||
// Coinbase input.
|
||||
input = new Input();
|
||||
@ -145,26 +154,16 @@ MinerBlock.prototype._init = function _init() {
|
||||
if (this.witness) {
|
||||
// Our witness nonce is the hash256
|
||||
// of the previous block hash.
|
||||
hash = new Buffer(this.tip.hash, 'hex');
|
||||
witnessNonce = crypto.hash256(hash);
|
||||
nonce = block.createWitnessNonce();
|
||||
|
||||
// Set up the witness nonce.
|
||||
input.witness.set(0, witnessNonce);
|
||||
input.witness.set(0, nonce);
|
||||
input.witness.compile();
|
||||
|
||||
// Commitment output.
|
||||
cb.outputs.push(new Output());
|
||||
}
|
||||
|
||||
// Setup our block.
|
||||
block.version = this.version;
|
||||
block.prevBlock = this.tip.hash;
|
||||
block.merkleRoot = constants.NULL_HASH;
|
||||
block.ts = Math.max(time.now(), this.tip.ts + 1);
|
||||
block.bits = this.bits;
|
||||
block.nonce = 0;
|
||||
block.height = this.height;
|
||||
|
||||
block.txs.push(cb);
|
||||
|
||||
// Update coinbase since our coinbase was added.
|
||||
@ -196,7 +195,7 @@ MinerBlock.prototype.updateCommitment = function updateCommitment() {
|
||||
var hash;
|
||||
|
||||
// Recalculate witness merkle root.
|
||||
hash = this.block.getCommitmentHash();
|
||||
hash = this.block.createCommitmentHash();
|
||||
|
||||
// Update commitment.
|
||||
output.script.clear();
|
||||
@ -253,7 +252,7 @@ MinerBlock.prototype.updateMerkle = function updateMerkle() {
|
||||
this.block.ts = Math.max(time.now(), this.tip.ts + 1);
|
||||
|
||||
// Recalculate merkle root.
|
||||
this.block.merkleRoot = this.block.getMerkleRoot('hex');
|
||||
this.block.merkleRoot = this.block.createMerkleRoot('hex');
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -146,35 +146,35 @@ Block.prototype.getRaw = function getRaw() {
|
||||
|
||||
/**
|
||||
* Calculate real size and size of the witness bytes.
|
||||
* @returns {Object} Contains `size` and `witnessSize`.
|
||||
* @returns {Object} Contains `total` and `witness`.
|
||||
*/
|
||||
|
||||
Block.prototype.getSizes = function getSizes() {
|
||||
var sizes = new BlockSizes();
|
||||
var writer;
|
||||
|
||||
if (this._size !== -1) {
|
||||
return {
|
||||
size: this._size,
|
||||
witnessSize: this._witnessSize
|
||||
};
|
||||
sizes.total = this._size;
|
||||
sizes.witness = this._witnessSize;
|
||||
return sizes;
|
||||
}
|
||||
|
||||
if (!this.mutable) {
|
||||
assert(!this._raw);
|
||||
this.getRaw();
|
||||
return {
|
||||
size: this._size,
|
||||
witnessSize: this._witnessSize
|
||||
};
|
||||
sizes.total = this._size;
|
||||
sizes.witness = this._witnessSize;
|
||||
return sizes;
|
||||
}
|
||||
|
||||
writer = new BufferWriter();
|
||||
|
||||
this.toRaw(writer);
|
||||
|
||||
return {
|
||||
size: writer.written,
|
||||
witnessSize: this._lastWitnessSize
|
||||
};
|
||||
sizes.total = writer.written;
|
||||
sizes.witness = this._lastWitnessSize;
|
||||
|
||||
return sizes;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -194,8 +194,8 @@ Block.prototype.getVirtualSize = function getVirtualSize() {
|
||||
|
||||
Block.prototype.getWeight = function getWeight() {
|
||||
var sizes = this.getSizes();
|
||||
var base = sizes.size - sizes.witnessSize;
|
||||
return base * (constants.WITNESS_SCALE_FACTOR - 1) + sizes.size;
|
||||
var base = sizes.total - sizes.witness;
|
||||
return base * (constants.WITNESS_SCALE_FACTOR - 1) + sizes.total;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -204,7 +204,7 @@ Block.prototype.getWeight = function getWeight() {
|
||||
*/
|
||||
|
||||
Block.prototype.getSize = function getSize() {
|
||||
return this.getSizes().size;
|
||||
return this.getSizes().total;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -214,7 +214,7 @@ Block.prototype.getSize = function getSize() {
|
||||
|
||||
Block.prototype.getBaseSize = function getBaseSize() {
|
||||
var sizes = this.getSizes();
|
||||
return sizes.size - sizes.witnessSize;
|
||||
return sizes.total - sizes.witness;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -280,106 +280,148 @@ Block.prototype.indexOf = function indexOf(hash) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate merkle root.
|
||||
* Calculate merkle root. Returns null
|
||||
* if merkle tree has been malleated.
|
||||
* @param {String?} enc - Encoding, can be `'hex'` or null.
|
||||
* @returns {Buffer|Hash} hash
|
||||
* @returns {Hash|null}
|
||||
*/
|
||||
|
||||
Block.prototype.getMerkleRoot = function getMerkleRoot(enc) {
|
||||
Block.prototype.createMerkleRoot = function createMerkleRoot(enc) {
|
||||
var leaves = [];
|
||||
var i, root;
|
||||
|
||||
for (i = 0; i < this.txs.length; i++)
|
||||
leaves.push(this.txs[i].hash());
|
||||
|
||||
root = crypto.getMerkleRoot(leaves);
|
||||
root = crypto.createMerkleRoot(leaves);
|
||||
|
||||
if (!root)
|
||||
return;
|
||||
if (root.malleated)
|
||||
return null;
|
||||
|
||||
return enc === 'hex'
|
||||
? root.toString('hex')
|
||||
: root;
|
||||
? root.hash.toString('hex')
|
||||
: root.hash;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a witness nonce (for mining).
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
Block.prototype.createWitnessNonce = function createWitnessNonce() {
|
||||
return crypto.hash256(new Buffer(this.prevBlock, 'hex'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate commitment hash (the root of the
|
||||
* witness merkle tree hashed with the witnessNonce).
|
||||
* @param {String?} enc - Encoding, can be `'hex'` or null.
|
||||
* @returns {Buffer|Hash} hash
|
||||
* @returns {Hash}
|
||||
*/
|
||||
|
||||
Block.prototype.createCommitmentHash = function createCommitmentHash(enc) {
|
||||
var nonce = this.getWitnessNonce();
|
||||
var leaves = [];
|
||||
var i, root, data, hash;
|
||||
|
||||
assert(nonce, 'No witness nonce present.');
|
||||
|
||||
leaves.push(constants.ZERO_HASH);
|
||||
|
||||
for (i = 1; i < this.txs.length; i++)
|
||||
leaves.push(this.txs[i].witnessHash());
|
||||
|
||||
root = crypto.createMerkleRoot(leaves);
|
||||
|
||||
// Note: malleation check ignored here.
|
||||
// assert(!root.malleated);
|
||||
|
||||
data = util.concat(root.hash, nonce);
|
||||
|
||||
hash = crypto.hash256(data);
|
||||
|
||||
return enc === 'hex'
|
||||
? hash.toString('hex')
|
||||
: hash;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the merkle root from the block header.
|
||||
* @param {String?} enc
|
||||
* @returns {Hash}
|
||||
*/
|
||||
|
||||
Block.prototype.getMerkleRoot = function getMerkleRoot(enc) {
|
||||
if (enc === 'hex')
|
||||
return this.merkleRoot;
|
||||
return new Buffer(this.merkleRoot, 'hex');
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the witness nonce from the
|
||||
* coinbase's witness vector (if present).
|
||||
* @returns {Buffer|null}
|
||||
*/
|
||||
|
||||
Block.prototype.getWitnessNonce = function getWitnessNonce() {
|
||||
var coinbase = this.txs[0];
|
||||
var input;
|
||||
|
||||
if (!coinbase)
|
||||
return null;
|
||||
|
||||
if (coinbase.inputs.length !== 1)
|
||||
return null;
|
||||
|
||||
input = coinbase.inputs[0];
|
||||
|
||||
if (input.witness.items.length !== 1)
|
||||
return null;
|
||||
|
||||
if (input.witness.items[0].length !== 32)
|
||||
return null;
|
||||
|
||||
return input.witness.items[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the commitment hash
|
||||
* from the coinbase's outputs.
|
||||
* @param {String?} enc
|
||||
* @returns {Hash|null}
|
||||
*/
|
||||
|
||||
Block.prototype.getCommitmentHash = function getCommitmentHash(enc) {
|
||||
var leaves = [];
|
||||
var witnessNonce = this.witnessNonce;
|
||||
var i, buf, witnessRoot, commitmentHash;
|
||||
var hash = this._commitmentHash;
|
||||
var i, coinbase, output;
|
||||
|
||||
if (!witnessNonce)
|
||||
return;
|
||||
if (!hash) {
|
||||
coinbase = this.txs[0];
|
||||
|
||||
for (i = 0; i < this.txs.length; i++)
|
||||
leaves.push(this.txs[i].witnessHash());
|
||||
if (!coinbase)
|
||||
return null;
|
||||
|
||||
witnessRoot = crypto.getMerkleRoot(leaves);
|
||||
for (i = coinbase.outputs.length - 1; i >= 0; i--) {
|
||||
output = coinbase.outputs[i];
|
||||
|
||||
if (!witnessRoot)
|
||||
return;
|
||||
if (output.script.isCommitment()) {
|
||||
hash = output.script.getCommitmentHash();
|
||||
|
||||
buf = new Buffer(64);
|
||||
witnessRoot.copy(buf, 0);
|
||||
witnessNonce.copy(buf, 32);
|
||||
if (!this.mutable)
|
||||
this._commitmentHash = hash;
|
||||
|
||||
commitmentHash = crypto.hash256(buf);
|
||||
|
||||
return enc === 'hex'
|
||||
? commitmentHash.toString('hex')
|
||||
: commitmentHash;
|
||||
};
|
||||
|
||||
Block.prototype.__defineGetter__('witnessNonce', function() {
|
||||
var coinbase = this.txs[0];
|
||||
|
||||
if (!coinbase)
|
||||
return;
|
||||
|
||||
if (coinbase.inputs.length !== 1)
|
||||
return;
|
||||
|
||||
if (coinbase.inputs[0].witness.items.length !== 1)
|
||||
return;
|
||||
|
||||
if (coinbase.inputs[0].witness.items[0].length !== 32)
|
||||
return;
|
||||
|
||||
return coinbase.inputs[0].witness.items[0];
|
||||
});
|
||||
|
||||
Block.prototype.__defineGetter__('commitmentHash', function() {
|
||||
var i, coinbase, script, commitmentHash;
|
||||
|
||||
if (this._commitmentHash)
|
||||
return this._commitmentHash;
|
||||
|
||||
coinbase = this.txs[0];
|
||||
|
||||
if (!coinbase)
|
||||
return;
|
||||
|
||||
for (i = coinbase.outputs.length - 1; i >= 0; i--) {
|
||||
script = coinbase.outputs[i].script;
|
||||
if (script.isCommitment()) {
|
||||
commitmentHash = script.getCommitmentHash();
|
||||
commitmentHash = commitmentHash.toString('hex');
|
||||
|
||||
if (!this.mutable)
|
||||
this._commitmentHash = commitmentHash;
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hash)
|
||||
return null;
|
||||
}
|
||||
|
||||
return commitmentHash;
|
||||
});
|
||||
return enc === 'hex'
|
||||
? hash.toString('hex')
|
||||
: hash;
|
||||
};
|
||||
|
||||
/**
|
||||
* Do non-contextual verification on the block. Including checking the block
|
||||
@ -441,7 +483,7 @@ Block.prototype._verify = function _verify(ret) {
|
||||
}
|
||||
|
||||
// Check merkle root
|
||||
merkle = this.getMerkleRoot('hex');
|
||||
merkle = this.createMerkleRoot('hex');
|
||||
|
||||
// If the merkle is mutated,
|
||||
// we have duplicate txs.
|
||||
@ -563,6 +605,7 @@ Block.prototype.getPrevout = function getPrevout() {
|
||||
*/
|
||||
|
||||
Block.prototype.inspect = function inspect() {
|
||||
var commitmentHash = this.getCommitmentHash('hex');
|
||||
return {
|
||||
hash: this.rhash,
|
||||
height: this.height,
|
||||
@ -572,8 +615,8 @@ Block.prototype.inspect = function inspect() {
|
||||
version: util.hex32(this.version),
|
||||
prevBlock: util.revHex(this.prevBlock),
|
||||
merkleRoot: util.revHex(this.merkleRoot),
|
||||
commitmentHash: this.commitmentHash
|
||||
? util.revHex(this.commitmentHash)
|
||||
commitmentHash: commitmentHash
|
||||
? util.revHex(commitmentHash)
|
||||
: null,
|
||||
ts: this.ts,
|
||||
bits: this.bits,
|
||||
@ -783,6 +826,15 @@ Block.isBlock = function isBlock(obj) {
|
||||
&& typeof obj.getClaimed === 'function';
|
||||
};
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
function BlockSizes() {
|
||||
this.total = 0;
|
||||
this.witness = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
@ -356,24 +356,24 @@ TX.prototype.getRaw = function getRaw() {
|
||||
*/
|
||||
|
||||
TX.prototype.getSizes = function getSizes() {
|
||||
var sizes = new TXSizes();
|
||||
var writer;
|
||||
|
||||
if (this.mutable) {
|
||||
assert(!this._raw);
|
||||
writer = new BufferWriter();
|
||||
this.toRaw(writer);
|
||||
return {
|
||||
size: writer.written,
|
||||
witnessSize: this._lastWitnessSize
|
||||
};
|
||||
sizes.total = writer.written;
|
||||
sizes.witness = this._lastWitnessSize;
|
||||
return sizes;
|
||||
}
|
||||
|
||||
this.getRaw();
|
||||
|
||||
return {
|
||||
size: this._size,
|
||||
witnessSize: this._witnessSize
|
||||
};
|
||||
sizes.total = this._size;
|
||||
sizes.witness = this._witnessSize;
|
||||
|
||||
return sizes;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -395,8 +395,8 @@ TX.prototype.getVirtualSize = function getVirtualSize() {
|
||||
|
||||
TX.prototype.getWeight = function getWeight() {
|
||||
var sizes = this.getSizes();
|
||||
var base = sizes.size - sizes.witnessSize;
|
||||
return base * (constants.WITNESS_SCALE_FACTOR - 1) + sizes.size;
|
||||
var base = sizes.total - sizes.witness;
|
||||
return base * (constants.WITNESS_SCALE_FACTOR - 1) + sizes.total;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -406,7 +406,7 @@ TX.prototype.getWeight = function getWeight() {
|
||||
*/
|
||||
|
||||
TX.prototype.getSize = function getSize() {
|
||||
return this.getSizes().size;
|
||||
return this.getSizes().total;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -418,7 +418,7 @@ TX.prototype.getSize = function getSize() {
|
||||
|
||||
TX.prototype.getBaseSize = function getBaseSize() {
|
||||
var sizes = this.getSizes();
|
||||
return sizes.size - sizes.witnessSize;
|
||||
return sizes.total - sizes.witness;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2541,6 +2541,15 @@ TX.isTX = function isTX(obj) {
|
||||
&& typeof obj.witnessHash === 'function';
|
||||
};
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
function TXSizes() {
|
||||
this.total = 0;
|
||||
this.witness = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
@ -3357,7 +3357,7 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i) {
|
||||
}
|
||||
|
||||
scriptRoot = crypto.hash256(scriptRoot.render());
|
||||
scriptRoot = crypto.checkMerkleBranch(scriptRoot, path, pos);
|
||||
scriptRoot = crypto.verifyMerkleBranch(scriptRoot, path, pos);
|
||||
|
||||
mastRoot.writeBytes(scriptRoot);
|
||||
mastRoot = crypto.hash256(mastRoot.render());
|
||||
|
||||
@ -186,12 +186,15 @@ util.isHex = function isHex(obj) {
|
||||
util.equal = function equal(a, b) {
|
||||
var i;
|
||||
|
||||
if (!Buffer.isBuffer(a))
|
||||
if (a == null)
|
||||
return false;
|
||||
|
||||
if (!Buffer.isBuffer(b))
|
||||
if (b == null)
|
||||
return false;
|
||||
|
||||
assert(Buffer.isBuffer(a));
|
||||
assert(Buffer.isBuffer(b));
|
||||
|
||||
if (a.compare)
|
||||
return a.compare(b) === 0;
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
"elliptic": "6.3.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcoin-native": "0.0.11",
|
||||
"bcoin-native": "0.0.12",
|
||||
"leveldown": "1.5.0",
|
||||
"secp256k1": "3.2.0",
|
||||
"socket.io": "1.4.8",
|
||||
|
||||
@ -126,7 +126,7 @@ describe('Block', function() {
|
||||
'8cc72c02a958de5a8b35a23bb7e3bced8bf840cc0a4e1c820000000000000000');
|
||||
assert.equal(block.rhash,
|
||||
'0000000000000000821c4e0acc40f88bedbce3b73ba2358b5ade58a9022cc78c');
|
||||
assert.equal(block.merkleRoot, block.getMerkleRoot('hex'));
|
||||
assert.equal(block.merkleRoot, block.createMerkleRoot('hex'));
|
||||
});
|
||||
|
||||
it('should create a merkle block', function() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user