more pool work. wallet.fill().

This commit is contained in:
Christopher Jeffrey 2016-02-01 10:54:11 -08:00
parent 1e027220c3
commit 999cfefe54
4 changed files with 75 additions and 103 deletions

View File

@ -45,6 +45,10 @@ function Peer(pool, createConnection, options) {
this.challenge = null;
this.lastPong = 0;
this.banscore = 0;
this.orphans = 0;
this.orphanTime = 0;
this.socket = createConnection.call(pool, this, options);
if (!this.socket)
throw new Error('No socket');
@ -103,7 +107,7 @@ Peer.prototype._init = function init() {
this.socket.once('error', function(err) {
self._error(err);
self.pool.misbehaving(self, 100);
self.pool.setMisbehavior(self, 100);
});
this.socket.once('close', function() {
@ -123,7 +127,7 @@ Peer.prototype._init = function init() {
self._error(err);
// Something is wrong here.
// Ignore this peer.
self.pool.misbehaving(self, 100);
self.pool.setMisbehavior(self, 100);
});
if (this.pool.options.fullNode) {

View File

@ -194,7 +194,7 @@ Pool.prototype._init = function _init() {
// If we failed a checkpoint, peer is misbehaving.
if (data.checkpoint) {
self.misbehaving(peer, 100);
self.setMisbehavior(peer, 100);
return;
}
@ -215,7 +215,7 @@ Pool.prototype._init = function _init() {
if (!peer)
return;
self.misbehaving(peer, 100);
self.setMisbehavior(peer, 100);
});
this.options.wallets.forEach(function(w) {
@ -292,7 +292,7 @@ Pool.prototype._stopInterval = function _stopInterval() {
Pool.prototype.createConnection = function createConnection(peer, options) {
var addr, net, socket;
addr = this.getSeed(options.priority, true);
addr = this.getSeed(options.priority);
assert(addr);
assert(addr.host);
@ -441,7 +441,7 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) {
peer.host);
if (headers.length > 2000) {
this.misbehaving(peer, 100);
this.setMisbehavior(peer, 100);
return;
}
@ -479,7 +479,7 @@ Pool.prototype._handleHeaders = function _handleHeaders(headers, peer) {
// simply tries to find the latest block in
// the peer's chain.
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
this._startInterval();
@ -499,7 +499,7 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
peer.host);
if (hashes.length > 500) {
this.misbehaving(peer, 100);
this.setMisbehavior(peer, 100);
return;
}
@ -511,15 +511,15 @@ Pool.prototype._handleBlocks = function _handleBlocks(hashes, peer) {
if (this.chain.hasOrphan(hash)) {
// Make sure the peer doesn't send us
// more than 200 orphans every 3 minutes.
if (this.orphaning(peer)) {
if (this.isOrphaning(peer)) {
utils.debug('Peer is orphaning (%s)', peer.host);
this.misbehaving(peer, 100);
this.setMisbehavior(peer, 100);
return;
}
// Resolve orphan chain.
peer.loadBlocks(
this.chain.locatorHashes(),
this.chain.getLocator(),
this.chain.getOrphanRoot(hash)
);
continue;
@ -553,7 +553,7 @@ Pool.prototype._handleInv = function _handleInv(hashes, peer) {
hash = utils.toHex(hashes[i]);
if (!this.chain.has(hash)) {
if (this.options.headers)
this.peers.load.loadHeaders(this.chain.locatorHashes(), hash);
this.peers.load.loadHeaders(this.chain.getLocator(), hash);
else
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.
if (this.block.invalid[block.hash('hex')]) {
utils.debug('Peer is sending an invalid chain (%s)', peer.host);
this.misbehaving(peer, 100);
this.setMisbehavior(peer, 100);
return false;
}
@ -589,14 +589,14 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
utils.debug(
'Peer is sending an invalid continuation chain (%s)',
peer.host);
this.misbehaving(peer, 100);
this.setMisbehavior(peer, 100);
return false;
}
// Ignore if we already have.
if (this.chain.has(block)) {
utils.debug('Already have block %s (%s)', block.height, peer.host);
this.misbehaving(peer, 1);
this.setMisbehavior(peer, 1);
return false;
}
@ -606,7 +606,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
'Block verification failed for %s (%s)',
block.rhash, peer.host);
this.block.invalid[block.hash('hex')] = true;
this.misbehaving(peer, 100);
this.setMisbehavior(peer, 100);
return false;
}
@ -627,9 +627,9 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
// Make sure the peer doesn't send us
// more than 200 orphans every 3 minutes.
if (this.orphaning(peer)) {
if (this.isOrphaning(peer)) {
utils.debug('Peer is orphaning (%s)', peer.host);
this.misbehaving(peer, 100);
this.setMisbehavior(peer, 100);
return false;
}
@ -642,7 +642,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
// Resolve orphan chain.
this.peers.load.loadBlocks(
this.chain.locatorHashes(),
this.chain.getLocator(),
this.chain.getOrphanRoot(block)
);
@ -658,7 +658,7 @@ Pool.prototype._handleBlock = function _handleBlock(block, peer) {
// Increase banscore by 10 if we're using getheaders.
if (!this.options.multiplePeers) {
if (this.misbehaving(peer, 10))
if (this.setMisbehavior(peer, 10))
return false;
}
}
@ -699,12 +699,15 @@ Pool.prototype._load = function _load() {
}
if (this.options.headers)
this.peers.load.loadHeaders(this.chain.locatorHashes(), null);
this.peers.load.loadHeaders(this.chain.getLocator(), null);
else
this.peers.load.loadBlocks(this.chain.locatorHashes(), null);
this.peers.load.loadBlocks(this.chain.getLocator(), null);
};
Pool.prototype.loadMempool = function loadMempool() {
if (this.peers.load)
this.peers.load.loadMempool();
this.peers.block.forEach(function(peer) {
peer.loadMempool();
});
@ -719,8 +722,6 @@ Pool.prototype._createPeer = function _createPeer(priority) {
priority: priority
});
peer._retry = 0;
peer.on('error', function(err) {
self.emit('error', err, peer);
});
@ -747,12 +748,10 @@ Pool.prototype._createPeer = function _createPeer(priority) {
});
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);
self._addTX(tx, 1);
if (state !== 1 || tx.block)
if (added || tx.block)
self.emit('tx', tx, peer);
if (!self.options.fullNode && tx.block)
@ -760,6 +759,9 @@ Pool.prototype._createPeer = function _createPeer(priority) {
});
peer.on('addr', function(data) {
if (self.options.discoverPeers === false)
return;
if (self.seeds.length > 1000)
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 original = this.originalSeeds;
var seeds = this.seeds;
var all = original.concat(seeds);
// Hang back if we don't have a loader peer yet.
if (!connecting && !priority && !this.peers.load)
if (!priority && !this.peers.load)
return;
// Randomize the non-original peers.
@ -1551,7 +1553,7 @@ Pool.prototype.getSeed = function getSeed(priority, connecting) {
// If we have no block peers, always return
// an address.
if (!priority) {
if (all.length === 1 || connecting)
if (all.length === 1)
return all[Math.random() * (all.length - 1) | 0];
}
@ -1561,22 +1563,13 @@ Pool.prototype.getSeed = function getSeed(priority, connecting) {
utils.debug(
'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) {
this.seeds = [];
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) {
this.addSeed(seed);
}, this);
@ -1593,7 +1586,7 @@ Pool.prototype.addSeed = function addSeed(seed) {
port: seed.port
});
this.hosts[seed.host] = this.seeds.length - 1;
this.hosts[seed.host] = true;
return true;
};
@ -1604,40 +1597,36 @@ Pool.prototype.removeSeed = function removeSeed(seed) {
if (this.hosts[seed.host] == null)
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];
return true;
};
Pool.prototype.orphaning = function orphaning(peer) {
if (!peer._orphanTime)
peer._orphanTime = utils.now();
if (!peer._orphans)
peer._orphans = 0;
if (utils.now() > peer._orphanTime + 3 * 60) {
peer._orphans = 0;
peer._orphanTime = utils.now();
Pool.prototype.isOrphaning = function isOrphaning(peer) {
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 false;
};
Pool.prototype.misbehaving = function misbehaving(peer, dos) {
if (!peer._banscore)
peer._banscore = 0;
Pool.prototype.setMisbehavior = function setMisbehavior(peer, dos) {
peer.banscore += dos;
peer._banscore += dos;
if (peer._banscore >= constants.banScore) {
if (peer.banscore >= constants.banScore) {
this.peers.misbehaving[peer.host] = utils.now();
utils.debug('Ban threshold exceeded for %s', peer.host);
peer.destroy();
@ -1660,7 +1649,7 @@ Pool.prototype.isMisbehaving = function isMisbehaving(host) {
delete this.peers.misbehaving[host];
peer = this.getPeer(host);
if (peer)
peer._banscore = 0;
peer.banscore = 0;
return false;
}
return true;

View File

@ -594,30 +594,11 @@ Wallet.prototype.balance = function balance() {
return this.tx.balance();
};
Wallet.prototype.fill = function fill(tx, changeAddress, cb) {
var result, err;
if (typeof changeAddress === 'function') {
cb = changeAddress;
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.fill = function fill(tx, changeAddress, fee) {
var result = this.fillUnspent(tx, changeAddress, fee);
if (!result.inputs)
return false;
return true;
};
Wallet.prototype.toAddress = function toAddress() {

View File

@ -181,25 +181,22 @@ describe('Wallet', function() {
// Create new transaction
var t2 = bcoin.tx().out(w2, 5460);
w1.fill(t2, function(err) {
assert(!err);
assert(t2.verify());
assert(w1.fill(t2));
w1.sign(t2);
assert(t2.verify());
assert.equal(t2.funds('in').toString(10), 16380);
// If change < dust and is added to outputs:
// assert.equal(t2.funds('out').toString(10), 6380);
// If change < dust and is added to fee:
assert.equal(t2.funds('out').toString(10), 5460);
assert.equal(t2.funds('in').toString(10), 16380);
// If change < dust and is added to outputs:
// assert.equal(t2.funds('out').toString(10), 6380);
// If change < dust and is added to fee:
assert.equal(t2.funds('out').toString(10), 5460);
// Create new transaction
var t3 = bcoin.tx().out(w2, 15000);
w1.fill(t3, function(err) {
assert(err);
assert.equal(err.minBalance.toString(10), 25000);
// Create new transaction
var t3 = bcoin.tx().out(w2, 15000);
assert(!w1.fill(t3));
assert.equal(t3.total.toString(10), 25000);
cb();
});
});
cb();
});
it('should sign multiple inputs using different keys', function(cb) {
@ -335,6 +332,7 @@ describe('Wallet', function() {
assert(!send.verify());
var result = w1.fill(send);
assert(result);
w1.sign(send);
// printScript(send.inputs[0]);