primitives: refresh call.
This commit is contained in:
parent
a23a5437a4
commit
edf47d67c8
@ -1429,20 +1429,26 @@ RPC.prototype.getwork = co(function* getwork(args) {
|
||||
});
|
||||
|
||||
RPC.prototype.submitblock = co(function* submitblock(args) {
|
||||
var block;
|
||||
var block, tx;
|
||||
|
||||
if (args.help || args.length < 1 || args.length > 2)
|
||||
throw new RPCError('submitblock "hexdata" ( "jsonparametersobject" )');
|
||||
|
||||
block = Block.fromRaw(toString(args[0]), 'hex');
|
||||
|
||||
// Fix eloipool bug (witness nonce is not present).
|
||||
if (block.getCommitmentHash()) {
|
||||
if (!block.txs[0].hasWitness()) {
|
||||
tx = block.txs[0];
|
||||
if (!tx.hasWitness()) {
|
||||
this.logger.warning('Submitted block had no witness nonce.');
|
||||
this.logger.debug(block.txs[0]);
|
||||
block.txs[0].inputs[0].witness.set(0, constants.ZERO_HASH);
|
||||
block.txs[0].clearCache();
|
||||
block.clearCache();
|
||||
this.logger.debug(tx);
|
||||
|
||||
// Recreate witness nonce (all zeroes).
|
||||
tx.inputs[0].witness.set(0, constants.ZERO_HASH);
|
||||
tx.inputs[0].witness.compile();
|
||||
|
||||
tx.refresh();
|
||||
block.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1460,8 +1466,6 @@ RPC.prototype._submitblock = co(function* submitblock(block) {
|
||||
|
||||
RPC.prototype.__submitblock = co(function* submitblock(block) {
|
||||
this.logger.info('Handling submitted block: %s.', block.rhash());
|
||||
this.logger.debug('Coinbase:');
|
||||
this.logger.debug(block.txs[0]);
|
||||
|
||||
try {
|
||||
yield this.chain.add(block);
|
||||
|
||||
@ -35,7 +35,7 @@ function CompactBlock(options) {
|
||||
if (!(this instanceof CompactBlock))
|
||||
return new CompactBlock(options);
|
||||
|
||||
AbstractBlock.call(this, options);
|
||||
AbstractBlock.call(this);
|
||||
|
||||
this.keyNonce = null;
|
||||
this.ids = [];
|
||||
@ -59,6 +59,8 @@ CompactBlock.prototype._verify = function _verify(ret) {
|
||||
};
|
||||
|
||||
CompactBlock.prototype.fromOptions = function fromOptions(options) {
|
||||
this.parseOptions(options);
|
||||
|
||||
assert(Buffer.isBuffer(options.keyNonce));
|
||||
assert(Array.isArray(options.ids));
|
||||
assert(Array.isArray(options.ptx));
|
||||
|
||||
@ -917,7 +917,6 @@ Peer.prototype.needsDrain = function needsDrain(size) {
|
||||
this.hostname);
|
||||
this.destroy();
|
||||
this.error('Peer stalled (drain).');
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ var InvItem = require('./invitem');
|
||||
* @exports AbstractBlock
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @param {NakedBlock} options
|
||||
* @property {Number} version - Block version. Note
|
||||
* that BCoin reads versions as unsigned despite
|
||||
* them being signed on the protocol level. This
|
||||
@ -36,9 +35,9 @@ var InvItem = require('./invitem');
|
||||
* @property {ReversedHash} rhash - Reversed block hash (uint256le).
|
||||
*/
|
||||
|
||||
function AbstractBlock(options) {
|
||||
function AbstractBlock() {
|
||||
if (!(this instanceof AbstractBlock))
|
||||
return new AbstractBlock(options);
|
||||
return new AbstractBlock();
|
||||
|
||||
this.version = 1;
|
||||
this.prevBlock = constants.NULL_HASH;
|
||||
@ -56,13 +55,17 @@ function AbstractBlock(options) {
|
||||
|
||||
this._hash = null;
|
||||
this._hhash = null;
|
||||
this._size = null;
|
||||
this._witness = null;
|
||||
|
||||
if (options)
|
||||
this.parseOptions(options);
|
||||
this._size = -1;
|
||||
this._witness = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory flag.
|
||||
* @const {Boolean}
|
||||
* @default
|
||||
* @memberof AbstractBlock#
|
||||
*/
|
||||
|
||||
AbstractBlock.prototype.memory = false;
|
||||
|
||||
/**
|
||||
@ -125,6 +128,42 @@ AbstractBlock.prototype.parseJSON = function parseJSON(json) {
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear any cached values (abstract).
|
||||
* @param {Boolean?} all - Clear transactions.
|
||||
*/
|
||||
|
||||
AbstractBlock.prototype._refresh = function refresh(all) {
|
||||
var i, tx;
|
||||
|
||||
this._valid = null;
|
||||
this._validHeaders = null;
|
||||
this._hash = null;
|
||||
this._hhash = null;
|
||||
this._size = -1;
|
||||
this._witness = -1;
|
||||
|
||||
if (!all)
|
||||
return;
|
||||
|
||||
if (!this.txs)
|
||||
return;
|
||||
|
||||
for (i = 0; i < this.txs.length; i++) {
|
||||
tx = this.txs[i];
|
||||
tx.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear any cached values.
|
||||
* @param {Boolean?} all - Clear transactions.
|
||||
*/
|
||||
|
||||
AbstractBlock.prototype.refresh = function refresh(all) {
|
||||
return this._refresh(all);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hash the block headers.
|
||||
* @param {String?} enc - Can be `'hex'` or `null`.
|
||||
|
||||
@ -34,7 +34,7 @@ function Block(options) {
|
||||
if (!(this instanceof Block))
|
||||
return new Block(options);
|
||||
|
||||
AbstractBlock.call(this, options);
|
||||
AbstractBlock.call(this);
|
||||
|
||||
this.txs = [];
|
||||
|
||||
@ -60,7 +60,10 @@ util.inherits(Block, AbstractBlock);
|
||||
Block.prototype.fromOptions = function fromOptions(options) {
|
||||
var i;
|
||||
|
||||
this.parseOptions(options);
|
||||
|
||||
if (options.txs) {
|
||||
assert(Array.isArray(options.txs));
|
||||
for (i = 0; i < options.txs.length; i++)
|
||||
this.addTX(options.txs[i]);
|
||||
}
|
||||
@ -78,16 +81,12 @@ Block.fromOptions = function fromOptions(options) {
|
||||
|
||||
/**
|
||||
* Clear any cached values.
|
||||
* @param {Boolean?} all - Clear transactions.
|
||||
*/
|
||||
|
||||
Block.prototype.clearCache = function clearCache() {
|
||||
this._valid = null;
|
||||
this._validHeaders = null;
|
||||
this._hash = null;
|
||||
this._hhash = null;
|
||||
Block.prototype.refresh = function refresh(all) {
|
||||
this._raw = null;
|
||||
this._size = -1;
|
||||
this._witness = -1;
|
||||
this._refresh(all);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -271,13 +270,14 @@ Block.prototype.hasTX = function hasTX(hash) {
|
||||
*/
|
||||
|
||||
Block.prototype.indexOf = function indexOf(hash) {
|
||||
var i;
|
||||
var i, tx;
|
||||
|
||||
if (hash instanceof TX)
|
||||
hash = hash.hash('hex');
|
||||
|
||||
for (i = 0; i < this.txs.length; i++) {
|
||||
if (this.txs[i].hash('hex') === hash)
|
||||
tx = this.txs[i];
|
||||
if (tx.hash('hex') === hash)
|
||||
return i;
|
||||
}
|
||||
|
||||
@ -293,10 +293,12 @@ Block.prototype.indexOf = function indexOf(hash) {
|
||||
|
||||
Block.prototype.createMerkleRoot = function createMerkleRoot(enc) {
|
||||
var leaves = [];
|
||||
var i, root;
|
||||
var i, tx, root;
|
||||
|
||||
for (i = 0; i < this.txs.length; i++)
|
||||
leaves.push(this.txs[i].hash());
|
||||
for (i = 0; i < this.txs.length; i++) {
|
||||
tx = this.txs[i];
|
||||
leaves.push(tx.hash());
|
||||
}
|
||||
|
||||
root = crypto.createMerkleRoot(leaves);
|
||||
|
||||
@ -327,14 +329,16 @@ Block.prototype.createWitnessNonce = function createWitnessNonce() {
|
||||
Block.prototype.createCommitmentHash = function createCommitmentHash(enc) {
|
||||
var nonce = this.getWitnessNonce();
|
||||
var leaves = [];
|
||||
var i, root, data, hash;
|
||||
var i, tx, 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());
|
||||
for (i = 1; i < this.txs.length; i++) {
|
||||
tx = this.txs[i];
|
||||
leaves.push(tx.witnessHash());
|
||||
}
|
||||
|
||||
root = crypto.createMerkleRoot(leaves);
|
||||
|
||||
@ -695,7 +699,6 @@ Block.prototype.fromJSON = function fromJSON(json) {
|
||||
var i;
|
||||
|
||||
assert(json, 'Block data is required.');
|
||||
assert.equal(json.type, 'block');
|
||||
assert(Array.isArray(json.txs));
|
||||
|
||||
this.parseJSON(json);
|
||||
|
||||
@ -25,7 +25,10 @@ function Headers(options) {
|
||||
if (!(this instanceof Headers))
|
||||
return new Headers(options);
|
||||
|
||||
AbstractBlock.call(this, options);
|
||||
AbstractBlock.call(this);
|
||||
|
||||
if (options)
|
||||
this.parseOptions(options);
|
||||
}
|
||||
|
||||
util.inherits(Headers, AbstractBlock);
|
||||
|
||||
@ -45,6 +45,13 @@ function MemBlock() {
|
||||
|
||||
util.inherits(MemBlock, AbstractBlock);
|
||||
|
||||
/**
|
||||
* Memory flag.
|
||||
* @const {Boolean}
|
||||
* @default
|
||||
* @memberof MemBlock#
|
||||
*/
|
||||
|
||||
MemBlock.prototype.memory = true;
|
||||
|
||||
/**
|
||||
|
||||
@ -32,7 +32,7 @@ function MerkleBlock(options) {
|
||||
if (!(this instanceof MerkleBlock))
|
||||
return new MerkleBlock(options);
|
||||
|
||||
AbstractBlock.call(this, options);
|
||||
AbstractBlock.call(this);
|
||||
|
||||
this.hashes = [];
|
||||
this.flags = DUMMY;
|
||||
@ -60,6 +60,8 @@ util.inherits(MerkleBlock, AbstractBlock);
|
||||
MerkleBlock.prototype.fromOptions = function fromOptions(options) {
|
||||
var i, hash;
|
||||
|
||||
this.parseOptions(options);
|
||||
|
||||
assert(options, 'MerkleBlock data is required.');
|
||||
assert(Array.isArray(options.hashes));
|
||||
assert(Buffer.isBuffer(options.flags));
|
||||
@ -89,6 +91,18 @@ MerkleBlock.fromOptions = function fromOptions(data) {
|
||||
return new MerkleBlock().fromOptions(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear any cached values.
|
||||
* @param {Boolean?} all - Clear transactions.
|
||||
*/
|
||||
|
||||
MerkleBlock.prototype.refresh = function refresh(all) {
|
||||
this.map = {};
|
||||
this.matches.length = 0;
|
||||
this._validPartial = null;
|
||||
this._refresh(all);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a transaction to the block's tx vector.
|
||||
* @param {TX} tx
|
||||
@ -243,7 +257,6 @@ MerkleBlock.prototype.extractTree = function extractTree() {
|
||||
if (flags.length * 8 < hashes.length)
|
||||
return;
|
||||
|
||||
height = 0;
|
||||
while (width(height) > 1)
|
||||
height++;
|
||||
|
||||
@ -531,10 +544,7 @@ MerkleBlock.fromBlock = function fromBlock(block, filter) {
|
||||
|
||||
for (i = 0; i < block.txs.length; i++) {
|
||||
tx = block.txs[i];
|
||||
if (tx.isWatched(filter))
|
||||
matches.push(1);
|
||||
else
|
||||
matches.push(0);
|
||||
matches.push(tx.isWatched(filter) ? 1 : 0);
|
||||
}
|
||||
|
||||
return MerkleBlock.fromMatches(block, matches);
|
||||
@ -555,17 +565,15 @@ MerkleBlock.fromHashes = function fromHashes(block, hashes) {
|
||||
|
||||
for (i = 0; i < hashes.length; i++) {
|
||||
hash = hashes[i];
|
||||
if (typeof hash === 'string')
|
||||
hash = new Buffer(hash, 'hex');
|
||||
filter[hash.toString('hex')] = true;
|
||||
if (Buffer.isBuffer(hash))
|
||||
hash = hash.toString('hex');
|
||||
filter[hash] = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < block.txs.length; i++) {
|
||||
tx = block.txs[i];
|
||||
if (filter[tx.hash('hex')])
|
||||
matches.push(1);
|
||||
else
|
||||
matches.push(0);
|
||||
hash = tx.hash('hex');
|
||||
matches.push(filter[hash] ? 1 : 0);
|
||||
}
|
||||
|
||||
return MerkleBlock.fromMatches(block, matches);
|
||||
@ -584,7 +592,9 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
|
||||
var leaves = [];
|
||||
var bits = [];
|
||||
var hashes = [];
|
||||
var i, tx, totalTX, height, flags, p, merkle, buf;
|
||||
var totalTX = block.txs.length;
|
||||
var height = 0;
|
||||
var i, p, tx, flags, merkle, buf;
|
||||
|
||||
for (i = 0; i < block.txs.length; i++) {
|
||||
tx = block.txs[i];
|
||||
@ -593,8 +603,6 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
|
||||
leaves.push(tx.hash());
|
||||
}
|
||||
|
||||
totalTX = leaves.length;
|
||||
|
||||
function width(height) {
|
||||
return (totalTX + (1 << height) - 1) >>> height;
|
||||
}
|
||||
@ -638,7 +646,6 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) {
|
||||
traverse(height - 1, pos * 2 + 1, leaves, matches);
|
||||
}
|
||||
|
||||
height = 0;
|
||||
while (width(height) > 1)
|
||||
height++;
|
||||
|
||||
|
||||
@ -60,6 +60,7 @@ function TX(options) {
|
||||
this.inputs = [];
|
||||
this.outputs = [];
|
||||
this.locktime = 0;
|
||||
|
||||
this.mutable = false;
|
||||
|
||||
this._hash = null;
|
||||
@ -144,7 +145,7 @@ TX.prototype.clone = function clone() {
|
||||
* Clear any cached values.
|
||||
*/
|
||||
|
||||
TX.prototype.clearCache = function clearCache() {
|
||||
TX.prototype.refresh = function refresh() {
|
||||
this._hash = null;
|
||||
this._hhash = null;
|
||||
this._whash = null;
|
||||
@ -155,6 +156,7 @@ TX.prototype.clearCache = function clearCache() {
|
||||
|
||||
this._outputValue = -1;
|
||||
this._inputValue = -1;
|
||||
|
||||
this._hashPrevouts = null;
|
||||
this._hashSequence = null;
|
||||
this._hashOutputs = null;
|
||||
|
||||
@ -194,15 +194,11 @@ describe('Block', function() {
|
||||
var ret = {};
|
||||
block2.hash();
|
||||
block2.merkleRoot = constants.NULL_HASH;
|
||||
block2._valid = null;
|
||||
block2._validHeaders = null;
|
||||
block2.refresh();
|
||||
assert(!block2.verify(ret));
|
||||
assert.equal(ret.reason, 'bad-txnmrklroot');
|
||||
block2._valid = null;
|
||||
block2._validHeaders = null;
|
||||
block2._hash = null;
|
||||
block2._hhash = null;
|
||||
block2.merkleRoot = block.merkleRoot;
|
||||
block2.refresh();
|
||||
assert(block2.verify());
|
||||
});
|
||||
|
||||
@ -213,12 +209,8 @@ describe('Block', function() {
|
||||
mblock2.merkleRoot = constants.NULL_HASH;
|
||||
assert(!mblock2.verify(ret));
|
||||
assert.equal(ret.reason, 'bad-txnmrklroot');
|
||||
mblock2._valid = null;
|
||||
mblock2._validHeaders = null;
|
||||
mblock2._validPartial = null;
|
||||
mblock2._hash = null;
|
||||
mblock2._hhash = null;
|
||||
mblock2.merkleRoot = mblock.merkleRoot;
|
||||
mblock2.refresh();
|
||||
assert(mblock2.verify());
|
||||
});
|
||||
|
||||
@ -229,11 +221,8 @@ describe('Block', function() {
|
||||
block2.bits = 403014710;
|
||||
assert(!block2.verify(ret));
|
||||
assert.equal(ret.reason, 'high-hash');
|
||||
block2._valid = null;
|
||||
block2._validHeaders = null;
|
||||
block2._hash = null;
|
||||
block2._hhash = null;
|
||||
block2.bits = block.bits;
|
||||
block2.refresh();
|
||||
assert(block2.verify());
|
||||
});
|
||||
|
||||
|
||||
@ -308,27 +308,8 @@ describe('Script', function() {
|
||||
});
|
||||
|
||||
if (noCache) {
|
||||
tx._raw = null;
|
||||
tx._size = -1;
|
||||
tx._witnessSize = -1;
|
||||
tx._hash = null;
|
||||
tx._hhash = null;
|
||||
tx._whash = null;
|
||||
tx._inputValue = -1;
|
||||
tx._outputValue = -1;
|
||||
tx._hashPrevouts = null;
|
||||
tx._hashSequence = null;
|
||||
tx._hashOutputs = null;
|
||||
|
||||
prev._raw = null;
|
||||
prev._size = -1;
|
||||
prev._witnessSize = -1;
|
||||
prev._hash = null;
|
||||
prev._inputValue = -1;
|
||||
prev._outputValue = -1;
|
||||
prev._hashPrevouts = null;
|
||||
prev._hashSequence = null;
|
||||
prev._hashOutputs = null;
|
||||
prev.refresh();
|
||||
tx.refresh();
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@ -46,18 +46,7 @@ function clearCache(tx, noCache) {
|
||||
assert.equal(tx.hash('hex'), tx.clone().hash('hex'));
|
||||
return;
|
||||
}
|
||||
|
||||
tx._raw = null;
|
||||
tx._size = -1;
|
||||
tx._witnessSize = -1;
|
||||
tx._hash = null;
|
||||
tx._hhash = null;
|
||||
tx._whash = null;
|
||||
tx._inputValue = -1;
|
||||
tx._outputValue = -1;
|
||||
tx._hashPrevouts = null;
|
||||
tx._hashSequence = null;
|
||||
tx._hashOutputs = null;
|
||||
tx.refresh();
|
||||
}
|
||||
|
||||
function parseTest(data) {
|
||||
@ -542,11 +531,13 @@ describe('TX', function() {
|
||||
raw = tx.toRaw();
|
||||
assert(encoding.readU64(raw, 47) === 0xdeadbeef);
|
||||
raw[54] = 0x7f;
|
||||
|
||||
assert.throws(function() {
|
||||
TX.fromRaw(raw);
|
||||
});
|
||||
tx._raw = null;
|
||||
|
||||
tx.outputs[0].value = 0;
|
||||
tx.refresh();
|
||||
|
||||
raw = tx.toRaw();
|
||||
assert(encoding.readU64(raw, 47) === 0x00);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user