Transport/Pool: Added tests to check that new addrs are added
This commit is contained in:
parent
e04cb76854
commit
b403cc3770
|
@ -292,11 +292,31 @@ Addresses.prototype.fromBuffer = function(payload) {
|
||||||
this.addresses = [];
|
this.addresses = [];
|
||||||
for (var i = 0; i < addrCount; i++) {
|
for (var i = 0; i < addrCount; i++) {
|
||||||
// TODO: Time actually depends on the version of the other peer (>=31402)
|
// TODO: Time actually depends on the version of the other peer (>=31402)
|
||||||
|
|
||||||
|
var time = parser.readUInt32LE();
|
||||||
|
var services = parser.readUInt64LEBN();
|
||||||
|
|
||||||
|
// parse the ipv6 to a string
|
||||||
|
var ipv6 = [];
|
||||||
|
for (var a = 0; a < 6; a++) {
|
||||||
|
ipv6.push(parser.read(2).toString('hex'));
|
||||||
|
}
|
||||||
|
ipv6 = ipv6.join(':');
|
||||||
|
|
||||||
|
// parse the ipv4 to a string
|
||||||
|
var ipv4 = [];
|
||||||
|
for (var b = 0; b < 4; b++) {
|
||||||
|
ipv4.push(parser.read(1)[0]);
|
||||||
|
}
|
||||||
|
ipv4 = ipv4.join('.');
|
||||||
|
|
||||||
|
var port = parser.readUInt16BE();
|
||||||
|
|
||||||
this.addresses.push({
|
this.addresses.push({
|
||||||
time: parser.readUInt32LE(),
|
time: time,
|
||||||
services: parser.readUInt64LEBN(),
|
services: services,
|
||||||
ip: parser.read(16),
|
ip: { v6: ipv6, v4: ipv4 },
|
||||||
port: parser.readUInt16BE()
|
port: port
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ function Peer(host, port, network) {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on('ping', function(message) {
|
this.on('ping', function(message) {
|
||||||
self.sendPong(message.nonce);
|
self._sendPong(message.nonce);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
var dns = require('dns');
|
var dns = require('dns');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var Networks = require('../networks');
|
var Networks = require('../networks');
|
||||||
|
var sha256 = require('../crypto/hash').sha256;
|
||||||
var Peer = require('./peer');
|
var Peer = require('./peer');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
|
||||||
function now(){
|
function now() {
|
||||||
return Math.floor(new Date().getTime() / 1000);
|
return Math.floor(new Date().getTime() / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,32 +34,42 @@ function Pool(network) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.network = Networks.get(network) || Networks.defaultNetwork;
|
this.network = Networks.get(network) || Networks.defaultNetwork;
|
||||||
this.connectedPeers = [];
|
this.connectedPeers = {};
|
||||||
this.addrs = [];
|
this.addrs = [];
|
||||||
this.keepalive = false;
|
this.keepalive = false;
|
||||||
|
|
||||||
this.on('peeraddr', function peerAddrEvent(peer, addr){
|
this.on('peeraddr', function peerAddrEvent(peer, message) {
|
||||||
// In case of an invalid time, assume "5 days ago"
|
var addrs = message.addresses;
|
||||||
if (addr.time <= 100000000 || addr.time > (now() + 10 * 60)) {
|
var length = addrs.length;
|
||||||
addr.time = now() - 5 * 24 * 60 * 60;
|
for (var i = 0; i < length; i++) {
|
||||||
|
var addr = addrs[i];
|
||||||
|
// In case of an invalid time, assume "5 days ago"
|
||||||
|
if (addr.time <= 100000000 || addr.time > (now() + 10 * 60)) {
|
||||||
|
addr.time = now() - 5 * 24 * 60 * 60;
|
||||||
|
}
|
||||||
|
this.addAddr(addr);
|
||||||
}
|
}
|
||||||
this.addAddr(addr);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on('peerdisconnect', function peerDisconnectEvent(peer, addr){
|
this.on('seed', function seedEvent(ips) {
|
||||||
self.deprioritizeAddr(addr);
|
ips.forEach(function(ip) {
|
||||||
self.removeConnectedPeer(addr);
|
self.addAddr({
|
||||||
|
ip: {
|
||||||
|
v4: ip
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
if (self.keepalive) {
|
if (self.keepalive) {
|
||||||
self.fillConnections();
|
self.fillConnections();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on('peerready', function peerReadyEvent(peer){
|
this.on('peerdisconnect', function peerDisconnectEvent(peer, addr) {
|
||||||
Pool.PeerEvents.forEach(function addPeerEvents(event) {
|
self.deprioritizeAddr(addr);
|
||||||
peer.on(event, function peerEvent(message) {
|
self.removeConnectedPeer(addr);
|
||||||
self.emit('peer' + event, peer, message);
|
if (self.keepalive) {
|
||||||
});
|
self.fillConnections();
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -70,8 +81,9 @@ util.inherits(Pool, EventEmitter);
|
||||||
Pool.MaxConnectedPeers = 8;
|
Pool.MaxConnectedPeers = 8;
|
||||||
Pool.RetrySeconds = 30;
|
Pool.RetrySeconds = 30;
|
||||||
Pool.PeerEvents = ['version', 'inv', 'getdata', 'ping', 'ping', 'addr',
|
Pool.PeerEvents = ['version', 'inv', 'getdata', 'ping', 'ping', 'addr',
|
||||||
'getaddr', 'verack', 'reject', 'alert', 'headers', 'block',
|
'getaddr', 'verack', 'reject', 'alert', 'headers', 'block',
|
||||||
'tx', 'getblocks', 'getheaders'];
|
'tx', 'getblocks', 'getheaders'
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,9 +95,7 @@ Pool.prototype.connect = function connect() {
|
||||||
this.keepalive = true;
|
this.keepalive = true;
|
||||||
var self = this;
|
var self = this;
|
||||||
if (self.addrs.length === 0) {
|
if (self.addrs.length === 0) {
|
||||||
self.addAddrsFromSeeds(function(){
|
self.addAddrsFromSeeds();
|
||||||
self.fillConnections();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
self.fillConnections();
|
self.fillConnections();
|
||||||
}
|
}
|
||||||
|
@ -98,8 +108,7 @@ Pool.prototype.connect = function connect() {
|
||||||
*/
|
*/
|
||||||
Pool.prototype.disconnect = function disconnect() {
|
Pool.prototype.disconnect = function disconnect() {
|
||||||
this.keepalive = false;
|
this.keepalive = false;
|
||||||
var length = this.connectedPeers.length;
|
for (var i in this.connectedPeers) {
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
this.connectedPeers[i].disconnect();
|
this.connectedPeers[i].disconnect();
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -119,7 +128,7 @@ Pool.prototype.isAvailable = function isAvailable() {
|
||||||
* @returns {Boolean} If there are peers connected.
|
* @returns {Boolean} If there are peers connected.
|
||||||
*/
|
*/
|
||||||
Pool.prototype.isConnected = function isConnected() {
|
Pool.prototype.isConnected = function isConnected() {
|
||||||
if (this.connectedPeers.length > 0){
|
if (this.numberConnected() > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -128,8 +137,8 @@ Pool.prototype.isConnected = function isConnected() {
|
||||||
/**
|
/**
|
||||||
* @returns {Number} The number of peers currently connected.
|
* @returns {Number} The number of peers currently connected.
|
||||||
*/
|
*/
|
||||||
Pool.prototype.numberConnected = function numberConnected(){
|
Pool.prototype.numberConnected = function numberConnected() {
|
||||||
return this.connectedPeers.length;
|
return Object.keys(this.connectedPeers).length;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,7 +147,7 @@ Pool.prototype.numberConnected = function numberConnected(){
|
||||||
Pool.prototype.fillConnections = function fillConnections() {
|
Pool.prototype.fillConnections = function fillConnections() {
|
||||||
var length = this.addrs.length;
|
var length = this.addrs.length;
|
||||||
for (var i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
if (this.connectedPeers.length >= Pool.MaxConnectedPeers ) {
|
if (this.numberConnected() >= Pool.MaxConnectedPeers) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var addr = this.addrs[i];
|
var addr = this.addrs[i];
|
||||||
|
@ -154,12 +163,10 @@ Pool.prototype.fillConnections = function fillConnections() {
|
||||||
* @param {Object} addr - An addr from the list of addrs
|
* @param {Object} addr - An addr from the list of addrs
|
||||||
*/
|
*/
|
||||||
Pool.prototype.removeConnectedPeer = function removeConnectedPeer(addr) {
|
Pool.prototype.removeConnectedPeer = function removeConnectedPeer(addr) {
|
||||||
for (var i = 0; i < this.connectedPeers.length; i++) {
|
if (this.connectedPeers[addr.hash].status !== Peer.STATUS.DISCONNECTED) {
|
||||||
if (this.connectedPeers[i].host === addr.ip) {
|
this.connectedPeers[addr.hash].disconnect();
|
||||||
var beginning = this.connectedPeers.splice(0, i);
|
} else {
|
||||||
var end = this.connectedPeers.splice(i + 1, this.connectedPeers.length);
|
delete this.connectedPeers[addr.hash];
|
||||||
this.connectedPeers = beginning.concat(end);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -172,28 +179,28 @@ Pool.prototype.connectPeer = function connectPeer(addr) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
function addConnectedPeer(addr) {
|
function addConnectedPeer(addr) {
|
||||||
var peer = new Peer(addr.ip, self.network.port, self.network);
|
var port = addr.port || self.network.port;
|
||||||
peer.on('disconnect', function peerDisconnect(){
|
var ip = addr.ip.v4 || addr.ip.v6;
|
||||||
|
var peer = new Peer(ip, port, self.network);
|
||||||
|
peer.on('disconnect', function peerDisconnect() {
|
||||||
self.emit('peerdisconnect', peer, addr);
|
self.emit('peerdisconnect', peer, addr);
|
||||||
});
|
});
|
||||||
peer.on('ready', function peerReady(){
|
peer.on('ready', function peerReady() {
|
||||||
self.emit('peerready', peer, addr);
|
self.emit('peerready', peer, addr);
|
||||||
});
|
});
|
||||||
|
Pool.PeerEvents.forEach(function addPeerEvents(event) {
|
||||||
|
peer.on(event, function peerEvent(message) {
|
||||||
|
self.emit('peer' + event, peer, message);
|
||||||
|
});
|
||||||
|
});
|
||||||
peer.connect();
|
peer.connect();
|
||||||
self.connectedPeers.push(peer);
|
self.connectedPeers[addr.hash] = peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
var exists = false;
|
if (!this.connectedPeers[addr.hash]) {
|
||||||
var length = this.connectedPeers.length;
|
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
if ( this.connectedPeers[i].host === addr.ip ) {
|
|
||||||
exists = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!exists){
|
|
||||||
addConnectedPeer(addr);
|
addConnectedPeer(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -204,7 +211,7 @@ Pool.prototype.connectPeer = function connectPeer(addr) {
|
||||||
*/
|
*/
|
||||||
Pool.prototype.deprioritizeAddr = function deprioritizeAddr(addr) {
|
Pool.prototype.deprioritizeAddr = function deprioritizeAddr(addr) {
|
||||||
for (var i = 0; i < this.addrs.length; i++) {
|
for (var i = 0; i < this.addrs.length; i++) {
|
||||||
if (this.addrs[i].ip === addr.ip) {
|
if (this.addrs[i].hash === addr.hash) {
|
||||||
var middle = this.addrs[i];
|
var middle = this.addrs[i];
|
||||||
middle.retryTime = now() + Pool.RetrySeconds;
|
middle.retryTime = now() + Pool.RetrySeconds;
|
||||||
var beginning = this.addrs.splice(0, i);
|
var beginning = this.addrs.splice(0, i);
|
||||||
|
@ -221,14 +228,18 @@ Pool.prototype.deprioritizeAddr = function deprioritizeAddr(addr) {
|
||||||
* @param {Object}
|
* @param {Object}
|
||||||
*/
|
*/
|
||||||
Pool.prototype.addAddr = function addAddr(addr) {
|
Pool.prototype.addAddr = function addAddr(addr) {
|
||||||
|
|
||||||
|
// make a unique key
|
||||||
|
addr.hash = sha256(new Buffer(addr.ip.v6 + addr.ip.v4 + addr.port)).toString('hex');
|
||||||
|
|
||||||
var length = this.addrs.length;
|
var length = this.addrs.length;
|
||||||
var exists = false;
|
var exists = false;
|
||||||
for (var i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
if (this.addrs[i].ip === addr.ip) {
|
if (this.addrs[i].hash === addr.hash) {
|
||||||
exists = true;
|
exists = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!exists){
|
if (!exists) {
|
||||||
this.addrs.unshift(addr);
|
this.addrs.unshift(addr);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -239,21 +250,19 @@ Pool.prototype.addAddr = function addAddr(addr) {
|
||||||
* @param {String} seed - A domain name to resolve known peers
|
* @param {String} seed - A domain name to resolve known peers
|
||||||
* @param {Function} done
|
* @param {Function} done
|
||||||
*/
|
*/
|
||||||
Pool.prototype.addAddrsFromSeed = function addAddrsFromSeed(seed, done) {
|
Pool.prototype.addAddrsFromSeed = function addAddrsFromSeed(seed) {
|
||||||
var self = this;
|
var self = this;
|
||||||
dns.resolve(seed, function(err, ips) {
|
dns.resolve(seed, function(err, ips) {
|
||||||
if (err) {
|
if (err) {
|
||||||
self.emit('error', err);
|
self.emit('seederror', err);
|
||||||
return done();
|
return;
|
||||||
}
|
}
|
||||||
if (!ips || !ips.length) {
|
if (!ips || !ips.length) {
|
||||||
self.emit('error', new Error('No IPs found from seed lookup.'));
|
self.emit('seederror', new Error('No IPs found from seed lookup.'));
|
||||||
return done();
|
return;
|
||||||
}
|
}
|
||||||
ips.forEach(function(ip){
|
// announce to pool
|
||||||
self.addAddr({ip: ip});
|
self.emit('seed', ips);
|
||||||
});
|
|
||||||
return done();
|
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -262,17 +271,11 @@ Pool.prototype.addAddrsFromSeed = function addAddrsFromSeed(seed, done) {
|
||||||
* Will add addrs to the list of addrs from network DNS seeds
|
* Will add addrs to the list of addrs from network DNS seeds
|
||||||
* @param {Function} done
|
* @param {Function} done
|
||||||
*/
|
*/
|
||||||
Pool.prototype.addAddrsFromSeeds = function addAddrsFromSeeds(done) {
|
Pool.prototype.addAddrsFromSeeds = function addAddrsFromSeeds() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var seeds = this.network.dnsSeeds;
|
var seeds = this.network.dnsSeeds;
|
||||||
var completed = [];
|
seeds.forEach(function(seed) {
|
||||||
seeds.forEach(function(seed){
|
self.addAddrsFromSeed(seed);
|
||||||
self.addAddrsFromSeed(seed, function(){
|
|
||||||
completed.push(seed);
|
|
||||||
if (completed.length === seeds.length && typeof(done) === 'function' ){
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -280,11 +283,11 @@ Pool.prototype.addAddrsFromSeeds = function addAddrsFromSeeds(done) {
|
||||||
/**
|
/**
|
||||||
* @returns {String} A string formatted for the console
|
* @returns {String} A string formatted for the console
|
||||||
*/
|
*/
|
||||||
Pool.prototype.inspect = function inspect(){
|
Pool.prototype.inspect = function inspect() {
|
||||||
return '<Pool network: ' +
|
return '<Pool network: ' +
|
||||||
this.network + ', connected: ' +
|
this.network + ', connected: ' +
|
||||||
this.numberConnected() + ', available: ' +
|
this.numberConnected() + ', available: ' +
|
||||||
this.addrs.length + '>';
|
this.addrs.length + '>';
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Pool;
|
module.exports = Pool;
|
|
@ -15,6 +15,8 @@ if (typeof(window) === 'undefined'){
|
||||||
|
|
||||||
var bitcore = require('../..');
|
var bitcore = require('../..');
|
||||||
var Peer = bitcore.transport.Peer;
|
var Peer = bitcore.transport.Peer;
|
||||||
|
var MessagesData = require('../data/messages');
|
||||||
|
var Messages = bitcore.transport.Messages;
|
||||||
var Pool = bitcore.transport.Pool;
|
var Pool = bitcore.transport.Pool;
|
||||||
var Networks = bitcore.Networks;
|
var Networks = bitcore.Networks;
|
||||||
|
|
||||||
|
@ -36,18 +38,61 @@ if (typeof(window) === 'undefined'){
|
||||||
});
|
});
|
||||||
var pool = new Pool(Networks.livenet);
|
var pool = new Pool(Networks.livenet);
|
||||||
pool.connect();
|
pool.connect();
|
||||||
|
pool.disconnect();
|
||||||
pool.addrs.length.should.equal(3);
|
pool.addrs.length.should.equal(3);
|
||||||
stub.restore();
|
stub.restore();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not discover peers via dns', function() {
|
it('should not discover peers via dns', function() {
|
||||||
var pool = new Pool();
|
var pool = new Pool();
|
||||||
pool.addAddr({ip: '10.10.10.1'});
|
pool.addAddr({ip: '10.10.10.1'});
|
||||||
pool.connect();
|
pool.connect();
|
||||||
|
pool.disconnect();
|
||||||
pool.addrs.length.should.equal(1);
|
pool.addrs.length.should.equal(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should add new addrs as they are announced over the network', function(done) {
|
||||||
|
|
||||||
|
// only emit an event, no need to connect
|
||||||
|
var peerConnectStub = sinon.stub(Peer.prototype, 'connect', function(){
|
||||||
|
this._readMessage();
|
||||||
|
this.emit('ready');
|
||||||
|
});
|
||||||
|
|
||||||
|
// mock a addr peer event
|
||||||
|
var peerMessageStub = sinon.stub(Peer.prototype, '_readMessage', function(){
|
||||||
|
var payload = new Buffer(MessagesData.ADDR.payload, 'hex');
|
||||||
|
var message = new Messages.Addresses().fromBuffer(payload);
|
||||||
|
this.emit(message.command, message);
|
||||||
|
});
|
||||||
|
|
||||||
|
var pool = new Pool();
|
||||||
|
|
||||||
|
pool.addAddr({ip: {v4: 'localhost'}});
|
||||||
|
|
||||||
|
// listen for the event
|
||||||
|
pool.on('peeraddr', function(peer, message) {
|
||||||
|
pool.addrs.length.should.equal(502);
|
||||||
|
|
||||||
|
// restore stubs
|
||||||
|
peerConnectStub.restore();
|
||||||
|
peerMessageStub.restore();
|
||||||
|
|
||||||
|
for (var i = 0; i < pool.addrs.length; i++) {
|
||||||
|
should.exist(pool.addrs[i].hash);
|
||||||
|
should.exist(pool.addrs[i].ip);
|
||||||
|
should.exist(pool.addrs[i].ip.v4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// done
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
pool.connect();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue