more pool work. wallet.fill().
This commit is contained in:
parent
1e027220c3
commit
999cfefe54
@ -45,6 +45,10 @@ function Peer(pool, createConnection, options) {
|
|||||||
this.challenge = null;
|
this.challenge = null;
|
||||||
this.lastPong = 0;
|
this.lastPong = 0;
|
||||||
|
|
||||||
|
this.banscore = 0;
|
||||||
|
this.orphans = 0;
|
||||||
|
this.orphanTime = 0;
|
||||||
|
|
||||||
this.socket = createConnection.call(pool, this, options);
|
this.socket = createConnection.call(pool, this, options);
|
||||||
if (!this.socket)
|
if (!this.socket)
|
||||||
throw new Error('No socket');
|
throw new Error('No socket');
|
||||||
@ -103,7 +107,7 @@ Peer.prototype._init = function init() {
|
|||||||
|
|
||||||
this.socket.once('error', function(err) {
|
this.socket.once('error', function(err) {
|
||||||
self._error(err);
|
self._error(err);
|
||||||
self.pool.misbehaving(self, 100);
|
self.pool.setMisbehavior(self, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.once('close', function() {
|
this.socket.once('close', function() {
|
||||||
@ -123,7 +127,7 @@ Peer.prototype._init = function init() {
|
|||||||
self._error(err);
|
self._error(err);
|
||||||
// Something is wrong here.
|
// Something is wrong here.
|
||||||
// Ignore this peer.
|
// Ignore this peer.
|
||||||
self.pool.misbehaving(self, 100);
|
self.pool.setMisbehavior(self, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.pool.options.fullNode) {
|
if (this.pool.options.fullNode) {
|
||||||
|
|||||||
@ -194,7 +194,7 @@ Pool.prototype._init = function _init() {
|
|||||||
|
|
||||||
// If we failed a checkpoint, peer is misbehaving.
|
// If we failed a checkpoint, peer is misbehaving.
|
||||||
if (data.checkpoint) {
|
if (data.checkpoint) {
|
||||||
self.misbehaving(peer, 100);
|
self.setMisbehavior(peer, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ Pool.prototype._init = function _init() {
|
|||||||
if (!peer)
|
if (!peer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self.misbehaving(peer, 100);
|
self.setMisbehavior(peer, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.options.wallets.forEach(function(w) {
|
this.options.wallets.forEach(function(w) {
|
||||||
@ -292,7 +292,7 @@ Pool.prototype._stopInterval = function _stopInterval() {
|
|||||||
Pool.prototype.createConnection = function createConnection(peer, options) {
|
Pool.prototype.createConnection = function createConnection(peer, options) {
|
||||||
var addr, net, socket;
|
var addr, net, socket;
|
||||||
|
|
||||||
addr = this.getSeed(options.priority, true);
|
addr = this.getSeed(options.priority);
|
||||||
|
|
||||||
assert(addr);
|
assert(addr);
|
||||||
assert(addr.host);
|
assert(addr.host);
|
||||||
@ -441,7 +441,7 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) {
|
|||||||
peer.host);
|
peer.host);
|
||||||
|
|
||||||
if (headers.length > 2000) {
|
if (headers.length > 2000) {
|
||||||
this.misbehaving(peer, 100);
|
this.setMisbehavior(peer, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +479,7 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) {
|
|||||||
// simply tries to find the latest block in
|
// simply tries to find the latest block in
|
||||||
// the peer's chain.
|
// the peer's chain.
|
||||||
if (last && headers.length === 2000)
|
if (last && headers.length === 2000)
|
||||||
peer.loadHeaders(this.chain.locatorHashes(last), null);
|
peer.loadHeaders(this.chain.getLocator(last), null);
|
||||||
|
|
||||||
// Reset interval to avoid calling getheaders unnecessarily
|
// Reset interval to avoid calling getheaders unnecessarily
|
||||||
this._startInterval();
|
this._startInterval();
|
||||||
@ -499,7 +499,7 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
|
|||||||
peer.host);
|
peer.host);
|
||||||
|
|
||||||
if (hashes.length > 500) {
|
if (hashes.length > 500) {
|
||||||
this.misbehaving(peer, 100);
|
this.setMisbehavior(peer, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,15 +511,15 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
|
|||||||
if (this.chain.hasOrphan(hash)) {
|
if (this.chain.hasOrphan(hash)) {
|
||||||
// Make sure the peer doesn't send us
|
// Make sure the peer doesn't send us
|
||||||
// more than 200 orphans every 3 minutes.
|
// more than 200 orphans every 3 minutes.
|
||||||
if (this.orphaning(peer)) {
|
if (this.isOrphaning(peer)) {
|
||||||
utils.debug('Peer is orphaning (%s)', peer.host);
|
utils.debug('Peer is orphaning (%s)', peer.host);
|
||||||
this.misbehaving(peer, 100);
|
this.setMisbehavior(peer, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve orphan chain.
|
// Resolve orphan chain.
|
||||||
peer.loadBlocks(
|
peer.loadBlocks(
|
||||||
this.chain.locatorHashes(),
|
this.chain.getLocator(),
|
||||||
this.chain.getOrphanRoot(hash)
|
this.chain.getOrphanRoot(hash)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
@ -553,7 +553,7 @@ Pool.prototype._handleInv = function _handleInv(hashes, peer) {
|
|||||||
hash = utils.toHex(hashes[i]);
|
hash = utils.toHex(hashes[i]);
|
||||||
if (!this.chain.has(hash)) {
|
if (!this.chain.has(hash)) {
|
||||||
if (this.options.headers)
|
if (this.options.headers)
|
||||||
this.peers.load.loadHeaders(this.chain.locatorHashes(), hash);
|
this.peers.load.loadHeaders(this.chain.getLocator(), hash);
|
||||||
else
|
else
|
||||||
this._request(peer, this.block.type, hash);
|
this._request(peer, this.block.type, hash);
|
||||||
}
|
}
|
||||||
@ -579,7 +579,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
|||||||
// Someone might be sending us bad blocks to DoS us.
|
// Someone might be sending us bad blocks to DoS us.
|
||||||
if (this.block.invalid[block.hash('hex')]) {
|
if (this.block.invalid[block.hash('hex')]) {
|
||||||
utils.debug('Peer is sending an invalid chain (%s)', peer.host);
|
utils.debug('Peer is sending an invalid chain (%s)', peer.host);
|
||||||
this.misbehaving(peer, 100);
|
this.setMisbehavior(peer, 100);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,14 +589,14 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
|||||||
utils.debug(
|
utils.debug(
|
||||||
'Peer is sending an invalid continuation chain (%s)',
|
'Peer is sending an invalid continuation chain (%s)',
|
||||||
peer.host);
|
peer.host);
|
||||||
this.misbehaving(peer, 100);
|
this.setMisbehavior(peer, 100);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore if we already have.
|
// Ignore if we already have.
|
||||||
if (this.chain.has(block)) {
|
if (this.chain.has(block)) {
|
||||||
utils.debug('Already have block %s (%s)', block.height, peer.host);
|
utils.debug('Already have block %s (%s)', block.height, peer.host);
|
||||||
this.misbehaving(peer, 1);
|
this.setMisbehavior(peer, 1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,7 +606,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
|||||||
'Block verification failed for %s (%s)',
|
'Block verification failed for %s (%s)',
|
||||||
block.rhash, peer.host);
|
block.rhash, peer.host);
|
||||||
this.block.invalid[block.hash('hex')] = true;
|
this.block.invalid[block.hash('hex')] = true;
|
||||||
this.misbehaving(peer, 100);
|
this.setMisbehavior(peer, 100);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -627,9 +627,9 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
|||||||
|
|
||||||
// Make sure the peer doesn't send us
|
// Make sure the peer doesn't send us
|
||||||
// more than 200 orphans every 3 minutes.
|
// more than 200 orphans every 3 minutes.
|
||||||
if (this.orphaning(peer)) {
|
if (this.isOrphaning(peer)) {
|
||||||
utils.debug('Peer is orphaning (%s)', peer.host);
|
utils.debug('Peer is orphaning (%s)', peer.host);
|
||||||
this.misbehaving(peer, 100);
|
this.setMisbehavior(peer, 100);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -642,7 +642,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
|||||||
|
|
||||||
// Resolve orphan chain.
|
// Resolve orphan chain.
|
||||||
this.peers.load.loadBlocks(
|
this.peers.load.loadBlocks(
|
||||||
this.chain.locatorHashes(),
|
this.chain.getLocator(),
|
||||||
this.chain.getOrphanRoot(block)
|
this.chain.getOrphanRoot(block)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -658,7 +658,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
|
|||||||
|
|
||||||
// Increase banscore by 10 if we're using getheaders.
|
// Increase banscore by 10 if we're using getheaders.
|
||||||
if (!this.options.multiplePeers) {
|
if (!this.options.multiplePeers) {
|
||||||
if (this.misbehaving(peer, 10))
|
if (this.setMisbehavior(peer, 10))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -699,12 +699,15 @@ Pool.prototype._load = function _load() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.headers)
|
if (this.options.headers)
|
||||||
this.peers.load.loadHeaders(this.chain.locatorHashes(), null);
|
this.peers.load.loadHeaders(this.chain.getLocator(), null);
|
||||||
else
|
else
|
||||||
this.peers.load.loadBlocks(this.chain.locatorHashes(), null);
|
this.peers.load.loadBlocks(this.chain.getLocator(), null);
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.loadMempool = function loadMempool() {
|
Pool.prototype.loadMempool = function loadMempool() {
|
||||||
|
if (this.peers.load)
|
||||||
|
this.peers.load.loadMempool();
|
||||||
|
|
||||||
this.peers.block.forEach(function(peer) {
|
this.peers.block.forEach(function(peer) {
|
||||||
peer.loadMempool();
|
peer.loadMempool();
|
||||||
});
|
});
|
||||||
@ -719,8 +722,6 @@ Pool.prototype._createPeer = function _createPeer(priority) {
|
|||||||
priority: priority
|
priority: priority
|
||||||
});
|
});
|
||||||
|
|
||||||
peer._retry = 0;
|
|
||||||
|
|
||||||
peer.on('error', function(err) {
|
peer.on('error', function(err) {
|
||||||
self.emit('error', err, peer);
|
self.emit('error', err, peer);
|
||||||
});
|
});
|
||||||
@ -747,12 +748,10 @@ Pool.prototype._createPeer = function _createPeer(priority) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
peer.on('tx', function(tx) {
|
peer.on('tx', function(tx) {
|
||||||
var state = self.tx.state[tx.hash('hex')];
|
var requested = self._response(tx);
|
||||||
|
var added = self._addTX(tx, 1);
|
||||||
|
|
||||||
self._response(tx);
|
if (added || tx.block)
|
||||||
self._addTX(tx, 1);
|
|
||||||
|
|
||||||
if (state !== 1 || tx.block)
|
|
||||||
self.emit('tx', tx, peer);
|
self.emit('tx', tx, peer);
|
||||||
|
|
||||||
if (!self.options.fullNode && tx.block)
|
if (!self.options.fullNode && tx.block)
|
||||||
@ -760,6 +759,9 @@ Pool.prototype._createPeer = function _createPeer(priority) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
peer.on('addr', function(data) {
|
peer.on('addr', function(data) {
|
||||||
|
if (self.options.discoverPeers === false)
|
||||||
|
return;
|
||||||
|
|
||||||
if (self.seeds.length > 1000)
|
if (self.seeds.length > 1000)
|
||||||
self.setSeeds(self.seeds.slice(-500));
|
self.setSeeds(self.seeds.slice(-500));
|
||||||
|
|
||||||
@ -1482,14 +1484,14 @@ Pool.prototype.getPeer = function getPeer(addr) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.getSeed = function getSeed(priority, connecting) {
|
Pool.prototype.getSeed = function getSeed(priority) {
|
||||||
var i, addr;
|
var i, addr;
|
||||||
var original = this.originalSeeds;
|
var original = this.originalSeeds;
|
||||||
var seeds = this.seeds;
|
var seeds = this.seeds;
|
||||||
var all = original.concat(seeds);
|
var all = original.concat(seeds);
|
||||||
|
|
||||||
// Hang back if we don't have a loader peer yet.
|
// Hang back if we don't have a loader peer yet.
|
||||||
if (!connecting && !priority && !this.peers.load)
|
if (!priority && !this.peers.load)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Randomize the non-original peers.
|
// Randomize the non-original peers.
|
||||||
@ -1551,7 +1553,7 @@ Pool.prototype.getSeed = function getSeed(priority, connecting) {
|
|||||||
// If we have no block peers, always return
|
// If we have no block peers, always return
|
||||||
// an address.
|
// an address.
|
||||||
if (!priority) {
|
if (!priority) {
|
||||||
if (all.length === 1 || connecting)
|
if (all.length === 1)
|
||||||
return all[Math.random() * (all.length - 1) | 0];
|
return all[Math.random() * (all.length - 1) | 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1561,22 +1563,13 @@ Pool.prototype.getSeed = function getSeed(priority, connecting) {
|
|||||||
utils.debug(
|
utils.debug(
|
||||||
'We had to connect to a random peer. Something is not right.');
|
'We had to connect to a random peer. Something is not right.');
|
||||||
|
|
||||||
return original[Math.random() * (original.length - 1) | 0];
|
return all[Math.random() * (all.length - 1) | 0];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.setSeeds = function setSeeds(seeds) {
|
Pool.prototype.setSeeds = function setSeeds(seeds) {
|
||||||
this.seeds = [];
|
this.seeds = [];
|
||||||
this.hosts = {};
|
this.hosts = {};
|
||||||
|
|
||||||
// Remove all seeds from misbehaving aside
|
|
||||||
// from original seeds that may be in it.
|
|
||||||
// this.peers.misbehaving = this.originalSeeds.reduce(function(out, addr) {
|
|
||||||
// if (this.peers.misbehaving[addr.host])
|
|
||||||
// out[addr.host] = this.peers.misbehaving[addr.host];
|
|
||||||
// return out;
|
|
||||||
// }, {}, this);
|
|
||||||
|
|
||||||
seeds.forEach(function(seed) {
|
seeds.forEach(function(seed) {
|
||||||
this.addSeed(seed);
|
this.addSeed(seed);
|
||||||
}, this);
|
}, this);
|
||||||
@ -1593,7 +1586,7 @@ Pool.prototype.addSeed = function addSeed(seed) {
|
|||||||
port: seed.port
|
port: seed.port
|
||||||
});
|
});
|
||||||
|
|
||||||
this.hosts[seed.host] = this.seeds.length - 1;
|
this.hosts[seed.host] = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@ -1604,40 +1597,36 @@ Pool.prototype.removeSeed = function removeSeed(seed) {
|
|||||||
if (this.hosts[seed.host] == null)
|
if (this.hosts[seed.host] == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
this.seeds.splice(this.hosts[seed.host], 1);
|
for (i = 0; i < this.seeds.length; i++) {
|
||||||
|
if (this.seeds[i].host === seed.host) {
|
||||||
|
this.seeds.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete this.hosts[seed.host];
|
delete this.hosts[seed.host];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.orphaning = function orphaning(peer) {
|
Pool.prototype.isOrphaning = function isOrphaning(peer) {
|
||||||
if (!peer._orphanTime)
|
if (utils.now() > peer.orphanTime + 3 * 60) {
|
||||||
peer._orphanTime = utils.now();
|
peer.orphans = 0;
|
||||||
|
peer.orphanTime = utils.now();
|
||||||
if (!peer._orphans)
|
|
||||||
peer._orphans = 0;
|
|
||||||
|
|
||||||
if (utils.now() > peer._orphanTime + 3 * 60) {
|
|
||||||
peer._orphans = 0;
|
|
||||||
peer._orphanTime = utils.now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
peer._orphans += 1;
|
peer.orphans += 1;
|
||||||
|
|
||||||
if (peer._orphans > 200)
|
if (peer.orphans > 200)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Pool.prototype.misbehaving = function misbehaving(peer, dos) {
|
Pool.prototype.setMisbehavior = function setMisbehavior(peer, dos) {
|
||||||
if (!peer._banscore)
|
peer.banscore += dos;
|
||||||
peer._banscore = 0;
|
|
||||||
|
|
||||||
peer._banscore += dos;
|
if (peer.banscore >= constants.banScore) {
|
||||||
|
|
||||||
if (peer._banscore >= constants.banScore) {
|
|
||||||
this.peers.misbehaving[peer.host] = utils.now();
|
this.peers.misbehaving[peer.host] = utils.now();
|
||||||
utils.debug('Ban threshold exceeded for %s', peer.host);
|
utils.debug('Ban threshold exceeded for %s', peer.host);
|
||||||
peer.destroy();
|
peer.destroy();
|
||||||
@ -1660,7 +1649,7 @@ Pool.prototype.isMisbehaving = function isMisbehaving(host) {
|
|||||||
delete this.peers.misbehaving[host];
|
delete this.peers.misbehaving[host];
|
||||||
peer = this.getPeer(host);
|
peer = this.getPeer(host);
|
||||||
if (peer)
|
if (peer)
|
||||||
peer._banscore = 0;
|
peer.banscore = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -594,30 +594,11 @@ Wallet.prototype.balance = function balance() {
|
|||||||
return this.tx.balance();
|
return this.tx.balance();
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.fill = function fill(tx, changeAddress, cb) {
|
Wallet.prototype.fill = function fill(tx, changeAddress, fee) {
|
||||||
var result, err;
|
var result = this.fillUnspent(tx, changeAddress, fee);
|
||||||
|
if (!result.inputs)
|
||||||
if (typeof changeAddress === 'function') {
|
return false;
|
||||||
cb = changeAddress;
|
return true;
|
||||||
changeAddress = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
cb = utils.asyncify(cb);
|
|
||||||
|
|
||||||
result = this.fillUnspent(tx, changeAddress);
|
|
||||||
|
|
||||||
if (!result.inputs) {
|
|
||||||
err = new Error('Not enough funds');
|
|
||||||
err.minBalance = result.total;
|
|
||||||
cb(err);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sign(tx);
|
|
||||||
|
|
||||||
cb(null, tx);
|
|
||||||
|
|
||||||
return tx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.toAddress = function toAddress() {
|
Wallet.prototype.toAddress = function toAddress() {
|
||||||
|
|||||||
@ -181,25 +181,22 @@ describe('Wallet', function() {
|
|||||||
|
|
||||||
// Create new transaction
|
// Create new transaction
|
||||||
var t2 = bcoin.tx().out(w2, 5460);
|
var t2 = bcoin.tx().out(w2, 5460);
|
||||||
w1.fill(t2, function(err) {
|
assert(w1.fill(t2));
|
||||||
assert(!err);
|
w1.sign(t2);
|
||||||
assert(t2.verify());
|
assert(t2.verify());
|
||||||
|
|
||||||
assert.equal(t2.funds('in').toString(10), 16380);
|
assert.equal(t2.funds('in').toString(10), 16380);
|
||||||
// If change < dust and is added to outputs:
|
// If change < dust and is added to outputs:
|
||||||
// assert.equal(t2.funds('out').toString(10), 6380);
|
// assert.equal(t2.funds('out').toString(10), 6380);
|
||||||
// If change < dust and is added to fee:
|
// If change < dust and is added to fee:
|
||||||
assert.equal(t2.funds('out').toString(10), 5460);
|
assert.equal(t2.funds('out').toString(10), 5460);
|
||||||
|
|
||||||
// Create new transaction
|
// Create new transaction
|
||||||
var t3 = bcoin.tx().out(w2, 15000);
|
var t3 = bcoin.tx().out(w2, 15000);
|
||||||
w1.fill(t3, function(err) {
|
assert(!w1.fill(t3));
|
||||||
assert(err);
|
assert.equal(t3.total.toString(10), 25000);
|
||||||
assert.equal(err.minBalance.toString(10), 25000);
|
|
||||||
|
|
||||||
cb();
|
cb();
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should sign multiple inputs using different keys', function(cb) {
|
it('should sign multiple inputs using different keys', function(cb) {
|
||||||
@ -335,6 +332,7 @@ describe('Wallet', function() {
|
|||||||
assert(!send.verify());
|
assert(!send.verify());
|
||||||
var result = w1.fill(send);
|
var result = w1.fill(send);
|
||||||
assert(result);
|
assert(result);
|
||||||
|
w1.sign(send);
|
||||||
|
|
||||||
// printScript(send.inputs[0]);
|
// printScript(send.inputs[0]);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user