add tx.isFinal. refactor chain usage.
This commit is contained in:
parent
c6c75d509b
commit
680bf01e98
@ -42,6 +42,8 @@ function Block(data, subtype) {
|
|||||||
this.network = data.network || false;
|
this.network = data.network || false;
|
||||||
this.relayedBy = data.relayedBy || '0.0.0.0';
|
this.relayedBy = data.relayedBy || '0.0.0.0';
|
||||||
|
|
||||||
|
this._chain = data.chain;
|
||||||
|
|
||||||
this.valid = null;
|
this.valid = null;
|
||||||
this._hash = null;
|
this._hash = null;
|
||||||
|
|
||||||
@ -226,7 +228,8 @@ Block.prototype.getMerkleRoot = function getMerkleRoot() {
|
|||||||
// This mimics the behavior of CheckBlockHeader()
|
// This mimics the behavior of CheckBlockHeader()
|
||||||
// and CheckBlock() in bitcoin/src/main.cpp.
|
// and CheckBlock() in bitcoin/src/main.cpp.
|
||||||
Block.prototype._verify = function _verify() {
|
Block.prototype._verify = function _verify() {
|
||||||
var i, unique, hash, merkleRoot;
|
var uniq = {};
|
||||||
|
var i, tx, hash;
|
||||||
|
|
||||||
// Check proof of work matches claimed amount
|
// Check proof of work matches claimed amount
|
||||||
if (!utils.testTarget(this.bits, this.hash()))
|
if (!utils.testTarget(this.bits, this.hash()))
|
||||||
@ -251,55 +254,106 @@ Block.prototype._verify = function _verify() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// First TX must be a coinbase
|
// First TX must be a coinbase
|
||||||
if (!this.txs.length
|
if (!this.txs.length || !this.txs[0].isCoinbase())
|
||||||
|| this.txs[0].inputs.length !== 1
|
|
||||||
|| +this.txs[0].inputs[0].out.hash !== 0)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// The rest of the txs must not be coinbases
|
// Test all txs
|
||||||
for (i = 1; i < this.txs.length; i++) {
|
|
||||||
if (this.txs[i].inputs.length === 1
|
|
||||||
&& +this.txs[i].inputs[0].out.hash === 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for duplicate tx ids
|
|
||||||
unique = {};
|
|
||||||
for (i = 0; i < this.txs.length; i++) {
|
for (i = 0; i < this.txs.length; i++) {
|
||||||
hash = this.txs[i].hash('hex');
|
tx = this.txs[i];
|
||||||
if (unique[hash])
|
|
||||||
return false;
|
|
||||||
unique[hash] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build MerkleTree
|
// The rest of the txs must not be coinbases
|
||||||
merkleRoot = this.getMerkleRoot();
|
if (i > 0 && tx.isCoinbase())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check for duplicate txids
|
||||||
|
hash = tx.hash('hex');
|
||||||
|
if (uniq[hash])
|
||||||
|
return false;
|
||||||
|
uniq[hash] = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Check merkle root
|
// Check merkle root
|
||||||
if (merkleRoot !== this.merkleRoot)
|
if (this.getMerkleRoot() !== this.merkleRoot)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Block.prototype.getHeight = function getHeight(chain) {
|
Block.prototype.postVerify = function postVerify() {
|
||||||
chain = chain || bcoin.chain.global;
|
var prev, i, tx, cb;
|
||||||
|
|
||||||
if (!chain)
|
if (this.subtype !== 'block')
|
||||||
return -1;
|
return true;
|
||||||
|
|
||||||
return chain.getHeight(this.hash('hex'));
|
if (!this.chain)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
prev = this.chain.getBlock(this.prevBlock);
|
||||||
|
|
||||||
|
// Ensure it's not an orphan
|
||||||
|
if (!prev)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Ensure the timestamp is correct
|
||||||
|
if (this.ts <= prev.getMedianTime())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Test all txs
|
||||||
|
for (i = 0; i < this.txs.length; i++) {
|
||||||
|
tx = this.txs[i];
|
||||||
|
|
||||||
|
// TXs must be finalized with regards to seq and locktime
|
||||||
|
if (!tx.isFinal(this, prev))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.bits !== this.chain.target(prev, this))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this.version < 2 && prev.isOutdated(2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this.version < 3 && prev.isOutdated(3))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this.version < 4 && prev.isOutdated(4))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Enforce height in coinbase
|
||||||
|
if (this.version >= 2 && prev.needsUpgrade(2)) {
|
||||||
|
cb = bcoin.script.isCoinbase(this.txs[0].inputs[0].script, this);
|
||||||
|
|
||||||
|
if (!cb)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (cb.height !== prev.height + 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sig validation (bip66)
|
||||||
|
if (this.version >= 3 && prev.needsUpgrade(3))
|
||||||
|
this.scriptFlags |= 1; // dersig
|
||||||
|
|
||||||
|
// checklocktimeverify (bip65)
|
||||||
|
if (this.version >= 4 && prev.needsUpgrade(4))
|
||||||
|
this.scriptFlags |= 2;
|
||||||
|
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Block.prototype.getNextBlock = function getNextBlock(chain) {
|
Block.prototype.getHeight = function getHeight() {
|
||||||
|
if (!this.chain)
|
||||||
|
return -1;
|
||||||
|
return this.chain.getHeight(this.hash('hex'));
|
||||||
|
};
|
||||||
|
|
||||||
|
Block.prototype.getNextBlock = function getNextBlock() {
|
||||||
var next;
|
var next;
|
||||||
|
|
||||||
chain = chain || bcoin.chain.global;
|
if (!this.chain)
|
||||||
|
|
||||||
if (!chain)
|
|
||||||
return utils.toHex(constants.zeroHash);
|
return utils.toHex(constants.zeroHash);
|
||||||
|
|
||||||
next = chain.getNextBlock(this.hash('hex'));
|
next = this.chain.getNextBlock(this.hash('hex'));
|
||||||
|
|
||||||
if (!next)
|
if (!next)
|
||||||
return utils.toHex(constants.zeroHash);
|
return utils.toHex(constants.zeroHash);
|
||||||
@ -361,26 +415,32 @@ Block.prototype.getReward = function getReward() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Block.prototype.getEntry = function getEntry(chain) {
|
Block.prototype.getEntry = function getEntry() {
|
||||||
chain = chain || bcoin.chain.global;
|
if (!this.chain)
|
||||||
return chain.getBlock(this);
|
return;
|
||||||
|
return this.chain.getBlock(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
Block.prototype.isOrphan = function isOrphan(chain) {
|
Block.prototype.isOrphan = function isOrphan() {
|
||||||
chain = chain || bcoin.chain.global;
|
if (!this.chain)
|
||||||
return chain.hasBlock(this.prevBlock);
|
return true;
|
||||||
|
return this.chain.hasBlock(this.prevBlock);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Block.prototype.__defineGetter__('chain', function() {
|
||||||
|
return this._chain || bcoin.chain.global;
|
||||||
|
});
|
||||||
|
|
||||||
Block.prototype.__defineGetter__('rhash', function() {
|
Block.prototype.__defineGetter__('rhash', function() {
|
||||||
return utils.revHex(this.hash('hex'));
|
return utils.revHex(this.hash('hex'));
|
||||||
});
|
});
|
||||||
|
|
||||||
Block.prototype.__defineGetter__('height', function() {
|
Block.prototype.__defineGetter__('height', function() {
|
||||||
return this.getHeight(bcoin.chain.global);
|
return this.getHeight();
|
||||||
});
|
});
|
||||||
|
|
||||||
Block.prototype.__defineGetter__('nextBlock', function() {
|
Block.prototype.__defineGetter__('nextBlock', function() {
|
||||||
return this.getNextBlock(bcoin.chain.global);
|
return this.getNextBlock();
|
||||||
});
|
});
|
||||||
|
|
||||||
Block.prototype.__defineGetter__('reward', function() {
|
Block.prototype.__defineGetter__('reward', function() {
|
||||||
@ -399,17 +459,18 @@ Block.prototype.__defineGetter__('coinbase', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Block.prototype.__defineGetter__('entry', function() {
|
Block.prototype.__defineGetter__('entry', function() {
|
||||||
return this.getEntry(bcoin.chain.global);
|
return this.getEntry();
|
||||||
});
|
});
|
||||||
|
|
||||||
Block.prototype.__defineGetter__('orphan', function() {
|
Block.prototype.__defineGetter__('orphan', function() {
|
||||||
return this.isOrphan(bcoin.chain.global);
|
return this.isOrphan();
|
||||||
});
|
});
|
||||||
|
|
||||||
Block.prototype.inspect = function inspect() {
|
Block.prototype.inspect = function inspect() {
|
||||||
var copy = bcoin.block(this, this.subtype);
|
var copy = bcoin.block(this, this.subtype);
|
||||||
copy.__proto__ = null;
|
copy.__proto__ = null;
|
||||||
delete copy._raw;
|
delete copy._raw;
|
||||||
|
delete copy._chain;
|
||||||
copy.hash = this.hash('hex');
|
copy.hash = this.hash('hex');
|
||||||
copy.rhash = this.rhash;
|
copy.rhash = this.rhash;
|
||||||
copy.height = this.height;
|
copy.height = this.height;
|
||||||
|
|||||||
@ -149,7 +149,7 @@ Chain.prototype._addIndex = function _addIndex(entry) {
|
|||||||
return Chain.codes.unchanged;
|
return Chain.codes.unchanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplcate height
|
// Duplicate height
|
||||||
if (this.index.hashes[entry.height] === entry.hash)
|
if (this.index.hashes[entry.height] === entry.hash)
|
||||||
return Chain.codes.unchanged;
|
return Chain.codes.unchanged;
|
||||||
|
|
||||||
@ -294,8 +294,16 @@ Chain.prototype.add = function add(block, peer) {
|
|||||||
// If we have a block at the same height, use chain with higher work
|
// If we have a block at the same height, use chain with higher work
|
||||||
if (this.index.hashes[entry.height]) {
|
if (this.index.hashes[entry.height]) {
|
||||||
if (this.tip.chainwork.cmp(entry.chainwork) < 0) {
|
if (this.tip.chainwork.cmp(entry.chainwork) < 0) {
|
||||||
|
if (!block.postVerify()) {
|
||||||
|
throw new Error;
|
||||||
|
//code = Chain.codes.invalid;
|
||||||
|
//break;
|
||||||
|
}
|
||||||
this.resetHeight(entry.height - 1);
|
this.resetHeight(entry.height - 1);
|
||||||
this._addIndex(entry);
|
code = this._addIndex(entry);
|
||||||
|
assert(code !== Chain.codes.unchanged);
|
||||||
|
if (code !== Chain.codes.okay)
|
||||||
|
break;
|
||||||
code = Chain.codes.forked;
|
code = Chain.codes.forked;
|
||||||
// Breaking here only works because
|
// Breaking here only works because
|
||||||
// we deleted the orphan map in resetHeight.
|
// we deleted the orphan map in resetHeight.
|
||||||
@ -308,7 +316,15 @@ Chain.prototype.add = function add(block, peer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validated known block at this point - add it to index
|
// Validated known block at this point - add it to index
|
||||||
|
if (!block.postVerify()) {
|
||||||
|
throw new Error;
|
||||||
|
//code = Chain.codes.invalid;
|
||||||
|
//break;
|
||||||
|
}
|
||||||
code = this._addIndex(entry);
|
code = this._addIndex(entry);
|
||||||
|
assert(code !== Chain.codes.unchanged);
|
||||||
|
if (code !== Chain.codes.okay)
|
||||||
|
break;
|
||||||
this.emit('block', block, peer);
|
this.emit('block', block, peer);
|
||||||
this.emit('entry', entry);
|
this.emit('entry', entry);
|
||||||
if (block !== initial)
|
if (block !== initial)
|
||||||
@ -531,26 +547,24 @@ Chain.prototype.height = function height() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.target = function target(last, block) {
|
Chain.prototype.target = function target(last, block) {
|
||||||
var proofOfWorkLimit = utils.toCompact(network.powLimit);
|
var powLimit = utils.toCompact(network.powLimit);
|
||||||
var adjustmentInterval = network.powTargetTimespan / network.powTargetSpacing;
|
var interval = network.powTargetTimespan / network.powTargetSpacing | 0;
|
||||||
var newBlockTs, heightFirst, first;
|
var first, ts;
|
||||||
|
|
||||||
adjustmentInterval |= 0;
|
|
||||||
|
|
||||||
if (!last)
|
if (!last)
|
||||||
last = this.getTip();
|
last = this.getTip();
|
||||||
|
|
||||||
// Do not retarget
|
// Do not retarget
|
||||||
if ((last.height + 1) % adjustmentInterval) {
|
if ((last.height + 1) % interval) {
|
||||||
if (network.powAllowMinDifficultyBlocks) {
|
if (network.powAllowMinDifficultyBlocks) {
|
||||||
// Special behavior for testnet:
|
// Special behavior for testnet:
|
||||||
newBlockTs = block ? block.ts : utils.now();
|
ts = block ? (block.ts || block) : utils.now();
|
||||||
if (newBlockTs > last.ts + network.powTargetSpacing * 2)
|
if (ts > last.ts + network.powTargetSpacing * 2)
|
||||||
return proofOfWorkLimit;
|
return powLimit;
|
||||||
|
|
||||||
while (last.prev
|
while (last.prev
|
||||||
&& last.height % adjustmentInterval !== 0
|
&& last.height % interval !== 0
|
||||||
&& last.bits !== proofOfWorkLimit) {
|
&& last.bits !== powLimit) {
|
||||||
last = last.prev;
|
last = last.prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,23 +574,22 @@ Chain.prototype.target = function target(last, block) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Back 2 weeks
|
// Back 2 weeks
|
||||||
heightFirst = last.height - (adjustmentInterval - 1);
|
first = this.byHeight(last.height - (interval - 1));
|
||||||
first = this.byHeight(heightFirst);
|
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return this.retarget(last, first.ts);
|
return this.retarget(last, first);
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.retarget = function retarget(last, firstTs) {
|
Chain.prototype.retarget = function retarget(last, first) {
|
||||||
var powTargetTimespan = new bn(network.powTargetTimespan);
|
var powTargetTimespan = new bn(network.powTargetTimespan);
|
||||||
var actualTimespan, powLimit, target;
|
var actualTimespan, powLimit, target;
|
||||||
|
|
||||||
if (network.powNoRetargeting)
|
if (network.powNoRetargeting)
|
||||||
return last.bits;
|
return last.bits;
|
||||||
|
|
||||||
actualTimespan = new bn(last.ts).subn(firstTs);
|
actualTimespan = new bn(last.ts).subn(first.ts);
|
||||||
if (actualTimespan.cmp(powTargetTimespan.divn(4)) < 0)
|
if (actualTimespan.cmp(powTargetTimespan.divn(4)) < 0)
|
||||||
actualTimespan = powTargetTimespan.divn(4);
|
actualTimespan = powTargetTimespan.divn(4);
|
||||||
|
|
||||||
@ -752,6 +765,45 @@ ChainBlock.prototype.getChainwork = function() {
|
|||||||
return (this.prev ? this.prev.chainwork : new bn(0)).add(this.proof);
|
return (this.prev ? this.prev.chainwork : new bn(0)).add(this.proof);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.getMedianTime = function() {
|
||||||
|
var entry = this;
|
||||||
|
var median = [];
|
||||||
|
var timeSpan = constants.block.medianTimespan;
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < timeSpan && entry; i++, entry = entry.prev)
|
||||||
|
median.push(entry.ts);
|
||||||
|
|
||||||
|
median = median.sort();
|
||||||
|
|
||||||
|
return median[median.length / 2 | 0];
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.isOutdated = function(version) {
|
||||||
|
return this.isSuperMajority(version,
|
||||||
|
network.block.majorityRejectBlockOutdated);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.needsUpgrade = function(version) {
|
||||||
|
return this.isSuperMajority(version,
|
||||||
|
network.block.majorityEnforceBlockUpgrade);
|
||||||
|
};
|
||||||
|
|
||||||
|
ChainBlock.prototype.isSuperMajority = function(version, required) {
|
||||||
|
var entry = this;
|
||||||
|
var found = 0;
|
||||||
|
var majorityWindow = network.block.majorityWindow;
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < majorityWindow && found < required && entry; i++) {
|
||||||
|
if (entry.version >= version)
|
||||||
|
found++;
|
||||||
|
entry = entry.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return found >= required;
|
||||||
|
};
|
||||||
|
|
||||||
ChainBlock.prototype.toJSON = function() {
|
ChainBlock.prototype.toJSON = function() {
|
||||||
// return [
|
// return [
|
||||||
// this.hash,
|
// this.hash,
|
||||||
|
|||||||
@ -134,12 +134,17 @@ Miner.prototype.addTX = function addTX(tx) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pretty important
|
// Ignore if it's already in a block
|
||||||
|
if (tx.height !== -1)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!tx.verify())
|
if (!tx.verify())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Ignore if it's already in a block
|
if (tx.isCoinbase())
|
||||||
if (tx.height !== -1)
|
return;
|
||||||
|
|
||||||
|
if (!tx.isFinal(this.block, this.last))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Deliver me from the block size debate, please
|
// Deliver me from the block size debate, please
|
||||||
@ -161,10 +166,12 @@ Miner.prototype.addTX = function addTX(tx) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Miner.prototype.createBlock = function createBlock(tx) {
|
Miner.prototype.createBlock = function createBlock(tx) {
|
||||||
var target, coinbase, headers, block;
|
var ts, target, coinbase, headers, block;
|
||||||
|
|
||||||
// Update target
|
ts = Math.max(utils.now(), this.last.ts + 1);
|
||||||
target = this.chain.target(this.last);
|
|
||||||
|
// Find target
|
||||||
|
target = this.chain.target(this.last, ts);
|
||||||
|
|
||||||
// Create a coinbase
|
// Create a coinbase
|
||||||
coinbase = bcoin.tx();
|
coinbase = bcoin.tx();
|
||||||
@ -194,7 +201,7 @@ Miner.prototype.createBlock = function createBlock(tx) {
|
|||||||
? this.last.hash('hex')
|
? this.last.hash('hex')
|
||||||
: this.last.hash,
|
: this.last.hash,
|
||||||
merkleRoot: utils.toHex(constants.zeroHash.slice()),
|
merkleRoot: utils.toHex(constants.zeroHash.slice()),
|
||||||
ts: utils.now(),
|
ts: ts,
|
||||||
bits: utils.toCompact(target),
|
bits: utils.toCompact(target),
|
||||||
nonce: 0
|
nonce: 0
|
||||||
};
|
};
|
||||||
|
|||||||
@ -149,8 +149,9 @@ Peer.prototype._init = function init() {
|
|||||||
|
|
||||||
this._req('verack', function(err, payload) {
|
this._req('verack', function(err, payload) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
self._error(err);
|
||||||
self.destroy();
|
self.destroy();
|
||||||
return self._error(err);
|
return;
|
||||||
}
|
}
|
||||||
self.ack = true;
|
self.ack = true;
|
||||||
self.emit('ack');
|
self.emit('ack');
|
||||||
@ -318,7 +319,7 @@ Peer.prototype._res = function _res(cmd, payload) {
|
|||||||
for (i = 0; i < this._request.queue.length; i++) {
|
for (i = 0; i < this._request.queue.length; i++) {
|
||||||
entry = this._request.queue[i];
|
entry = this._request.queue[i];
|
||||||
|
|
||||||
if (!entry || entry.cmd && entry.cmd !== cmd)
|
if (!entry || (entry.cmd && entry.cmd !== cmd))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
res = entry.cb(null, payload, cmd);
|
res = entry.cb(null, payload, cmd);
|
||||||
|
|||||||
@ -43,7 +43,9 @@ function Pool(options) {
|
|||||||
this.size = options.size || 32;
|
this.size = options.size || 32;
|
||||||
this.parallel = options.parallel || 2000;
|
this.parallel = options.parallel || 2000;
|
||||||
this.redundancy = options.redundancy || 2;
|
this.redundancy = options.redundancy || 2;
|
||||||
this.seeds = network.seeds.slice();
|
this.seeds = options.seeds
|
||||||
|
? options.seeds.slice()
|
||||||
|
: network.seeds.slice();
|
||||||
|
|
||||||
this._createConnection = options.createConnection;
|
this._createConnection = options.createConnection;
|
||||||
this._createSocket = options.createSocket;
|
this._createSocket = options.createSocket;
|
||||||
@ -280,6 +282,10 @@ Pool.prototype._addLoader = function _addLoader() {
|
|||||||
relay: this.options.relay
|
relay: this.options.relay
|
||||||
});
|
});
|
||||||
|
|
||||||
|
peer.once('socket', function() {
|
||||||
|
self.emit('debug', 'Added loader peer: %s', peer.host);
|
||||||
|
});
|
||||||
|
|
||||||
this.peers.load = peer;
|
this.peers.load = peer;
|
||||||
this.peers.all.push(peer);
|
this.peers.all.push(peer);
|
||||||
|
|
||||||
@ -494,8 +500,10 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Make sure the block is valid
|
// Make sure the block is valid
|
||||||
if (!block.verify())
|
if (!block.verify()) {
|
||||||
|
this.emit('debug', 'Block verification failed for %s', block.hash('hex'));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve orphan chain
|
// Resolve orphan chain
|
||||||
if (!this.options.headers) {
|
if (!this.options.headers) {
|
||||||
@ -768,8 +776,15 @@ Pool.prototype._removePeer = function _removePeer(peer) {
|
|||||||
if (i !== -1)
|
if (i !== -1)
|
||||||
this.peers.all.splice(i, 1);
|
this.peers.all.splice(i, 1);
|
||||||
|
|
||||||
if (this.peers.load === peer)
|
if (this.peers.load === peer) {
|
||||||
|
this.emit('debug', 'Removed loader peer (%s).', peer.host);
|
||||||
this.peers.load = null;
|
this.peers.load = null;
|
||||||
|
// i = this.seeds.indexOf(peer.host);
|
||||||
|
// if (i === -1)
|
||||||
|
// i = this.seeds.indexOf(peer.host + ':' + peer.port);
|
||||||
|
// if (i !== -1)
|
||||||
|
// this.seeds.splice(i, 1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.watch = function watch(id) {
|
Pool.prototype.watch = function watch(id) {
|
||||||
@ -1407,9 +1422,15 @@ Pool.prototype.usableSeed = function usableSeed(addrs, force) {
|
|||||||
if (!addrs)
|
if (!addrs)
|
||||||
addrs = this.seeds;
|
addrs = this.seeds;
|
||||||
|
|
||||||
for (i = 0; i < addrs.length; i++) {
|
addrs = addrs.slice().sort(function() {
|
||||||
if (!this.getPeer(addrs[i]))
|
return Math.random() > 0.50 ? 1 : -1;
|
||||||
return addrs[i];
|
});
|
||||||
|
|
||||||
|
if (this.peers.loader) {
|
||||||
|
for (i = 0; i < addrs.length; i++) {
|
||||||
|
if (!this.getPeer(addrs[i]))
|
||||||
|
return addrs[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!force)
|
if (!force)
|
||||||
|
|||||||
@ -155,7 +155,8 @@ exports.hashTypeByVal = Object.keys(exports.hashType).reduce(function(out, type)
|
|||||||
exports.block = {
|
exports.block = {
|
||||||
maxSize: 1000000,
|
maxSize: 1000000,
|
||||||
maxSigops: 1000000 / 50,
|
maxSigops: 1000000 / 50,
|
||||||
maxOrphanTx: 1000000 / 100
|
maxOrphanTx: 1000000 / 100,
|
||||||
|
medianTimeSpan: 11
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.script = {
|
exports.script = {
|
||||||
|
|||||||
@ -140,6 +140,12 @@ main.powTargetSpacing = 10 * 60;
|
|||||||
main.powAllowMinDifficultyBlocks = false;
|
main.powAllowMinDifficultyBlocks = false;
|
||||||
main.powNoRetargeting = false;
|
main.powNoRetargeting = false;
|
||||||
|
|
||||||
|
main.block = {
|
||||||
|
majorityEnforceBlockUpgrade: 750,
|
||||||
|
majorityRejectBlockOutdated: 950,
|
||||||
|
majorityWindow: 1000
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Testnet (v3)
|
* Testnet (v3)
|
||||||
* https://en.bitcoin.it/wiki/Testnet
|
* https://en.bitcoin.it/wiki/Testnet
|
||||||
@ -237,3 +243,9 @@ testnet.powTargetTimespan = 14 * 24 * 60 * 60; // two weeks
|
|||||||
testnet.powTargetSpacing = 10 * 60;
|
testnet.powTargetSpacing = 10 * 60;
|
||||||
testnet.powAllowMinDifficultyBlocks = true;
|
testnet.powAllowMinDifficultyBlocks = true;
|
||||||
testnet.powNoRetargeting = false;
|
testnet.powNoRetargeting = false;
|
||||||
|
|
||||||
|
testnet.block = {
|
||||||
|
majorityEnforceBlockUpgrade: 51,
|
||||||
|
majorityRejectBlockOutdated: 75,
|
||||||
|
majorityWindow: 100
|
||||||
|
};
|
||||||
|
|||||||
@ -37,6 +37,8 @@ function TX(data, block) {
|
|||||||
this.network = data.network || false;
|
this.network = data.network || false;
|
||||||
this.relayedBy = data.relayedBy || '0.0.0.0';
|
this.relayedBy = data.relayedBy || '0.0.0.0';
|
||||||
|
|
||||||
|
this._chain = data.chain;
|
||||||
|
|
||||||
this._lock = this.lock;
|
this._lock = this.lock;
|
||||||
|
|
||||||
if (data.inputs) {
|
if (data.inputs) {
|
||||||
@ -834,25 +836,66 @@ TX.prototype.funds = function funds(side) {
|
|||||||
return acc;
|
return acc;
|
||||||
};
|
};
|
||||||
|
|
||||||
TX.prototype.getHeight = function getHeight(chain) {
|
// Used for postVerify/ContextualBlockCheck and miner isFinalTx call.
|
||||||
chain = chain || bcoin.chain.global;
|
// BIP113 will require that time-locked transactions have nLockTime set to
|
||||||
|
// less than the median time of the previous block they're contained in.
|
||||||
if (!chain)
|
TX.prototype.isFinal = function isFinal(block, prev) {
|
||||||
return -1;
|
var height = prev.height + 1;
|
||||||
|
var ts = this.locktimeMedian ? prev.getMedianTime() : block.ts;
|
||||||
return this.block ? chain.getHeight(this.block) : -1;
|
return this._isFinal(height, ts);
|
||||||
};
|
};
|
||||||
|
|
||||||
TX.prototype.getConfirmations = function getConfirmations(chain) {
|
// Used in AcceptToMemoryPool
|
||||||
|
TX.prototype.isFinalAccept = function isFinalAccept() {
|
||||||
|
var height = this.chain.height() + 1;
|
||||||
|
var ts = this.lockTimeMedian
|
||||||
|
? this.chain.getTip().getMedianTime()
|
||||||
|
: utils.now();
|
||||||
|
return this._isFinalTx(height, ts);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used in the original bitcoind code for AcceptBlock
|
||||||
|
TX.prototype._isFinalOriginal = function _isFinalOriginal(block) {
|
||||||
|
var ts = block ? block.ts : utils.now();
|
||||||
|
var height = this.chain.height();
|
||||||
|
return this._isFinalTx(height, ts);
|
||||||
|
};
|
||||||
|
|
||||||
|
TX.prototype._isFinal = function _isFinal(height, ts) {
|
||||||
|
var threshold = constants.locktimeThreshold;
|
||||||
|
var i;
|
||||||
|
|
||||||
|
if (!this.chain)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (this.lock === 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (this.lock < (this.lock < threshold ? height : ts))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (i = 0; i < this.inputs.length; i++) {
|
||||||
|
if (this.inputs[i].seq !== 0xffffffff)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
TX.prototype.getHeight = function getHeight() {
|
||||||
|
if (!this.chain)
|
||||||
|
return -1;
|
||||||
|
return this.block ? this.chain.getHeight(this.block) : -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
TX.prototype.getConfirmations = function getConfirmations() {
|
||||||
var top, height;
|
var top, height;
|
||||||
|
|
||||||
chain = chain || bcoin.chain.global;
|
if (!this.chain)
|
||||||
|
|
||||||
if (!chain)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
top = chain.height();
|
top = this.chain.height();
|
||||||
height = this.getHeight(chain);
|
height = this.getHeight();
|
||||||
|
|
||||||
if (height === -1)
|
if (height === -1)
|
||||||
return 0;
|
return 0;
|
||||||
@ -860,6 +903,10 @@ TX.prototype.getConfirmations = function getConfirmations(chain) {
|
|||||||
return top - height + 1;
|
return top - height + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TX.prototype.__defineGetter__('chain', function() {
|
||||||
|
return this._chain || bcoin.chain.global;
|
||||||
|
});
|
||||||
|
|
||||||
TX.prototype.__defineGetter__('rblock', function() {
|
TX.prototype.__defineGetter__('rblock', function() {
|
||||||
return this.block
|
return this.block
|
||||||
? utils.revHex(this.block)
|
? utils.revHex(this.block)
|
||||||
@ -879,11 +926,11 @@ TX.prototype.__defineGetter__('value', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
TX.prototype.__defineGetter__('height', function() {
|
TX.prototype.__defineGetter__('height', function() {
|
||||||
return this.getHeight(bcoin.chain.global);
|
return this.getHeight();
|
||||||
});
|
});
|
||||||
|
|
||||||
TX.prototype.__defineGetter__('confirmations', function() {
|
TX.prototype.__defineGetter__('confirmations', function() {
|
||||||
return this.getConfirmations(bcoin.chain.global);
|
return this.getConfirmations();
|
||||||
});
|
});
|
||||||
|
|
||||||
TX.prototype.inspect = function inspect() {
|
TX.prototype.inspect = function inspect() {
|
||||||
@ -892,6 +939,7 @@ TX.prototype.inspect = function inspect() {
|
|||||||
if (this.block)
|
if (this.block)
|
||||||
copy.block = this.block;
|
copy.block = this.block;
|
||||||
delete copy._raw;
|
delete copy._raw;
|
||||||
|
delete copy._chain;
|
||||||
copy.hash = this.hash('hex');
|
copy.hash = this.hash('hex');
|
||||||
copy.rhash = this.rhash;
|
copy.rhash = this.rhash;
|
||||||
copy.rblock = this.rblock;
|
copy.rblock = this.rblock;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user