primitives: refresh call.

This commit is contained in:
Christopher Jeffrey 2016-12-16 22:02:05 -08:00
parent a23a5437a4
commit edf47d67c8
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
12 changed files with 130 additions and 103 deletions

View File

@ -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);

View File

@ -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));

View File

@ -917,7 +917,6 @@ Peer.prototype.needsDrain = function needsDrain(size) {
this.hostname);
this.destroy();
this.error('Peer stalled (drain).');
return;
}
};

View File

@ -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`.

View File

@ -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);

View File

@ -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);

View File

@ -45,6 +45,13 @@ function MemBlock() {
util.inherits(MemBlock, AbstractBlock);
/**
* Memory flag.
* @const {Boolean}
* @default
* @memberof MemBlock#
*/
MemBlock.prototype.memory = true;
/**

View File

@ -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++;

View File

@ -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;

View File

@ -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());
});

View File

@ -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 {

View File

@ -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);