Merge remote-tracking branch 'gordonwritescode/feature/peer-discovery'
This commit is contained in:
commit
3267925ebf
|
@ -0,0 +1,4 @@
|
||||||
|
var PeerManager = require('../lib/PeerManager');
|
||||||
|
var peerman = new PeerManager();
|
||||||
|
|
||||||
|
peerman.discover({ limit: 12 }).start();
|
|
@ -34,8 +34,8 @@ function Peer(host, port, services) {
|
||||||
Peer.IPV6_IPV4_PADDING = new Buffer([0,0,0,0,0,0,0,0,0,0,255,255]);
|
Peer.IPV6_IPV4_PADDING = new Buffer([0,0,0,0,0,0,0,0,0,0,255,255]);
|
||||||
|
|
||||||
Peer.prototype.createConnection = function () {
|
Peer.prototype.createConnection = function () {
|
||||||
var c = Net.createConnection(this.port, this.host);
|
this.connection = Net.createConnection(this.port, this.host);
|
||||||
return c;
|
return this.connection;
|
||||||
};
|
};
|
||||||
|
|
||||||
Peer.prototype.getHostAsBuffer = function () {
|
Peer.prototype.getHostAsBuffer = function () {
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
|
|
||||||
|
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
|
var extend = imports.extend || require('extend');
|
||||||
var log = imports.log || require('../util/log');
|
var log = imports.log || require('../util/log');
|
||||||
var bitcoreDefaults = imports.config || require('../config');
|
var bitcoreDefaults = imports.config || require('../config');
|
||||||
var Connection = imports.Connection || require ('./Connection');
|
var Connection = imports.Connection || require ('./Connection');
|
||||||
|
|
||||||
var Peer = imports.Peer || require('./Peer');
|
var Peer = imports.Peer || require('./Peer');
|
||||||
|
|
||||||
GetAdjustedTime = imports.GetAdjustedTime || function () {
|
GetAdjustedTime = imports.GetAdjustedTime || function () {
|
||||||
|
@ -13,11 +11,13 @@ GetAdjustedTime = imports.GetAdjustedTime || function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
function PeerManager(config) {
|
function PeerManager(config) {
|
||||||
this.config = config || bitcoreDefaults;
|
// extend defaults with config
|
||||||
|
this.config = extend(true, config || {}, bitcoreDefaults);
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.timer = null;
|
this.timer = null;
|
||||||
|
|
||||||
this.peers = [];
|
this.peers = [];
|
||||||
|
this.pool = [];
|
||||||
this.connections = [];
|
this.connections = [];
|
||||||
this.isConnected = false;
|
this.isConnected = false;
|
||||||
this.peerDiscovery = false;
|
this.peerDiscovery = false;
|
||||||
|
@ -26,6 +26,12 @@ function PeerManager(config) {
|
||||||
this.interval = 5000;
|
this.interval = 5000;
|
||||||
this.minConnections = 8;
|
this.minConnections = 8;
|
||||||
this.minKnownPeers = 10;
|
this.minKnownPeers = 10;
|
||||||
|
|
||||||
|
// keep track of tried seeds and results
|
||||||
|
this.seeds = {
|
||||||
|
resolved: [],
|
||||||
|
failed: []
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerManager.parent = imports.parent || require('events').EventEmitter;
|
PeerManager.parent = imports.parent || require('events').EventEmitter;
|
||||||
|
@ -61,6 +67,13 @@ PeerManager.prototype.addPeer = function(peer, port) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PeerManager.prototype.removePeer = function(peer) {
|
||||||
|
var index = this.peers.indexOf(peer);
|
||||||
|
var exists = !!~index;
|
||||||
|
if (exists) this.peers.splice(index, 1);
|
||||||
|
return exists;
|
||||||
|
};
|
||||||
|
|
||||||
PeerManager.prototype.checkStatus = function checkStatus() {
|
PeerManager.prototype.checkStatus = function checkStatus() {
|
||||||
// Make sure we are connected to all forcePeers
|
// Make sure we are connected to all forcePeers
|
||||||
if(this.peers.length) {
|
if(this.peers.length) {
|
||||||
|
@ -77,6 +90,13 @@ PeerManager.prototype.checkStatus = function checkStatus() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// for debug purposes, print how many of our peers are actually connected
|
||||||
|
var connected = 0
|
||||||
|
this.peers.forEach(function(p) {
|
||||||
|
if (p.connection && !p.connection._connecting) connected++
|
||||||
|
});
|
||||||
|
log.info(connected + ' of ' + this.peers.length + ' peers connected');
|
||||||
|
|
||||||
Object.keys(peerIndex).forEach(function(i) {
|
Object.keys(peerIndex).forEach(function(i) {
|
||||||
this.connectTo(peerIndex[i]);
|
this.connectTo(peerIndex[i]);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
@ -178,6 +198,12 @@ PeerManager.prototype.handleDisconnect = function(e) {
|
||||||
var i = this.connections.indexOf(e.conn);
|
var i = this.connections.indexOf(e.conn);
|
||||||
if(i != -1) this.connections.splice(i, 1);
|
if(i != -1) this.connections.splice(i, 1);
|
||||||
|
|
||||||
|
this.removePeer(e.peer);
|
||||||
|
if (this.pool.length) {
|
||||||
|
log.info('replacing peer using the pool of ' + this.pool.length + ' seeds');
|
||||||
|
this.addPeer(this.pool.pop());
|
||||||
|
}
|
||||||
|
|
||||||
if(!this.connections.length) {
|
if(!this.connections.length) {
|
||||||
this.emit('netDisconnected');
|
this.emit('netDisconnected');
|
||||||
this.isConnected = false;
|
this.isConnected = false;
|
||||||
|
@ -212,4 +238,72 @@ PeerManager.prototype.getActiveConnections = function () {
|
||||||
return this.connections.slice(0);
|
return this.connections.slice(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PeerManager.prototype.discover = function(options, callback) {
|
||||||
|
var self = this;
|
||||||
|
var async = imports.async || require('async');
|
||||||
|
var dns = imports.dns || require('dns');
|
||||||
|
var networks = imports.networks || require('../networks');
|
||||||
|
var seeds = networks[self.config.network].dnsSeeds;
|
||||||
|
|
||||||
|
self.limit = options.limit || 12;
|
||||||
|
|
||||||
|
var dnsExecutor = seeds.map(function(seed) {
|
||||||
|
return function(done) {
|
||||||
|
// have we already resolved this seed?
|
||||||
|
if (~self.seeds.resolved.indexOf(seed)) {
|
||||||
|
// if so, just pass back cached peer list
|
||||||
|
return done(null, self.seeds.results[seed]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// has this seed failed to resolve?
|
||||||
|
if (~self.seeds.failed.indexOf(seed)) {
|
||||||
|
// if so, pass back empty results
|
||||||
|
return done(null, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info('resolving dns seed '+ seed);
|
||||||
|
|
||||||
|
dns.resolve(seed, function(err, peers) {
|
||||||
|
if (err) {
|
||||||
|
log.err('failed to resolve dns seed '+ seed, err);
|
||||||
|
self.seeds.failed.push(seed);
|
||||||
|
return done(null, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info('found '+ peers.length + ' peers from ' + seed);
|
||||||
|
self.seeds.resolved.push(seed);
|
||||||
|
|
||||||
|
// transform that list into a list of Peer instances
|
||||||
|
peers = peers.map(function(ip) {
|
||||||
|
return new Peer(ip, networks.defaultClientPort);
|
||||||
|
});
|
||||||
|
|
||||||
|
peers.forEach(function(p) {
|
||||||
|
if (self.peers.length < self.limit) self.addPeer(p);
|
||||||
|
else self.pool.push(p);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.emit('peers', peers);
|
||||||
|
|
||||||
|
return done(null, peers);
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// try resolving all seeds
|
||||||
|
async.parallel(dnsExecutor, function(err, results) {
|
||||||
|
var peers = [];
|
||||||
|
|
||||||
|
// consolidate all resolved peers into one list
|
||||||
|
results.forEach(function(peerlist) {
|
||||||
|
peers = peers.concat(peerlist);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof callback === 'function') callback(null, peers);
|
||||||
|
});
|
||||||
|
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = require('soop')(PeerManager);
|
module.exports = require('soop')(PeerManager);
|
||||||
|
|
18
networks.js
18
networks.js
|
@ -19,7 +19,16 @@ exports.livenet = {
|
||||||
prev_hash: buffertools.fill(new Buffer(32), 0),
|
prev_hash: buffertools.fill(new Buffer(32), 0),
|
||||||
timestamp: 1231006505,
|
timestamp: 1231006505,
|
||||||
bits: 486604799,
|
bits: 486604799,
|
||||||
}
|
},
|
||||||
|
dnsSeeds: [
|
||||||
|
'seed.bitcoin.sipa.be',
|
||||||
|
'dnsseed.bluematt.me',
|
||||||
|
'dnsseed.bitcoin.dashjr.org',
|
||||||
|
'seed.bitcoinstats.com',
|
||||||
|
'seed.bitnodes.io',
|
||||||
|
'bitseed.xf2.org'
|
||||||
|
],
|
||||||
|
defaultClientPort: 8333
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.testnet = {
|
exports.testnet = {
|
||||||
|
@ -39,5 +48,10 @@ exports.testnet = {
|
||||||
prev_hash: buffertools.fill(new Buffer(32), 0),
|
prev_hash: buffertools.fill(new Buffer(32), 0),
|
||||||
timestamp: 1296688602,
|
timestamp: 1296688602,
|
||||||
bits: 486604799,
|
bits: 486604799,
|
||||||
}
|
},
|
||||||
|
dnsSeeds: [
|
||||||
|
'testnet-seed.bitcoin.petertodd.org',
|
||||||
|
'testnet-seed.bluematt.me'
|
||||||
|
],
|
||||||
|
defaultClientPort: 18333
|
||||||
};
|
};
|
||||||
|
|
|
@ -70,7 +70,8 @@
|
||||||
"socks5-client": "~0.3.6",
|
"socks5-client": "~0.3.6",
|
||||||
"brfs": "=1.0.0",
|
"brfs": "=1.0.0",
|
||||||
"chai": "=1.9.1",
|
"chai": "=1.9.1",
|
||||||
"uglifyify": "=1.2.3"
|
"uglifyify": "=1.2.3",
|
||||||
|
"extend": "~1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"grunt-contrib-watch": "~0.5.3",
|
"grunt-contrib-watch": "~0.5.3",
|
||||||
|
|
Loading…
Reference in New Issue