bitcore-p2p
Version:
Interface to the bitcoin P2P network for bitcore
269 lines (241 loc) • 8.2 kB
JavaScript
;
var chai = require('chai');
var Net = require('net');
var Socks5Client = require('socks5-client');
/* jshint unused: false */
var should = chai.should();
var expect = chai.expect;
var sinon = require('sinon');
var fs = require('fs');
var bitcore = require('bitcore-lib');
var _ = bitcore.deps._;
var P2P = require('../');
var Peer = P2P.Peer;
var EventEmitter = require('events').EventEmitter;
var Messages = P2P.Messages;
var messages = new Messages();
var Networks = bitcore.Networks;
describe('Peer', function() {
describe('Integration test', function() {
it('parses this stream of data from a connection', function(callback) {
var peer = new Peer('');
var stub = sinon.stub();
var dataCallback;
var connectCallback;
var expected = {
version: 1,
verack: 1,
inv: 18,
addr: 4
};
var received = {
version: 0,
verack: 0,
inv: 0,
addr: 0
};
stub.on = function() {
if (arguments[0] === 'data') {
dataCallback = arguments[1];
}
if (arguments[0] === 'connect') {
connectCallback = arguments[1];
}
};
stub.write = function() {};
stub.connect = function() {
connectCallback();
};
peer._getSocket = function() {
return stub;
};
peer.on('connect', function() {
dataCallback(fs.readFileSync('./test/data/connection.log'));
});
var check = function(message) {
received[message.command]++;
if (_.isEqual(received, expected)) {
callback();
}
};
peer.on('version', check);
peer.on('verack', check);
peer.on('addr', check);
peer.on('inv', check);
peer.connect();
});
});
it('create instance', function() {
var peer = new Peer('localhost');
peer.host.should.equal('localhost');
peer.network.should.equal(Networks.livenet);
peer.port.should.equal(Networks.livenet.port);
});
it('create instance setting a port', function() {
var peer = new Peer({host: 'localhost', port: 8111});
peer.host.should.equal('localhost');
peer.network.should.equal(Networks.livenet);
peer.port.should.equal(8111);
});
it('create instance setting a network', function() {
var peer = new Peer({host: 'localhost', network: Networks.testnet});
peer.host.should.equal('localhost');
peer.network.should.equal(Networks.testnet);
// Default testnet doesn't have a port, it is contained in the variants properties
// peer.port.should.equal(Networks.testnet.port);
});
it('create instance setting a network from string', function() {
var peer = new Peer({host: 'localhost', network: 'testnet'});
peer.host.should.equal('localhost');
peer.network.should.equal(Networks.testnet);
// Default testnet doesn't have a port, it is contained in the variants properties
// peer.port.should.equal(Networks.testnet.port);
});
it('create instance setting a network from xpubkey', function() {
var peer = new Peer({host: 'localhost', network: 0x043587cf});
peer.host.should.equal('localhost');
peer.network.should.equal(Networks.testnet);
// Default testnet doesn't have a port, it is contained in the variants properties
// peer.port.should.equal(Networks.testnet.port);
});
it('create instance setting a custom network', function() {
const customNetwork = new class Network{ constructor(port, networkMagic) { this.port = port; this.networkMagic = networkMagic } }(1234, 0x1234567);
var peer = new Peer({host: 'localhost', network: customNetwork});
peer.host.should.equal('localhost');
peer.network.should.equal(customNetwork);
peer.port.should.equal(customNetwork.port);
});
it('create instance setting port and network', function() {
var peer = new Peer({host: 'localhost', port: 8111, network: Networks.testnet});
peer.host.should.equal('localhost');
peer.network.should.equal(Networks.testnet);
peer.port.should.equal(8111);
});
it('create instance without new', function() {
var peer = Peer({host: 'localhost', port: 8111, network: Networks.testnet});
peer.host.should.equal('localhost');
peer.network.should.equal(Networks.testnet);
peer.port.should.equal(8111);
});
it('set a proxy', function() {
var peer, peer2, socket;
peer = new Peer('localhost');
expect(peer.proxy).to.be.undefined();
socket = peer._getSocket();
socket.should.be.instanceof(Net.Socket);
peer2 = peer.setProxy('127.0.0.1', 9050);
peer2.proxy.host.should.equal('127.0.0.1');
peer2.proxy.port.should.equal(9050);
socket = peer2._getSocket();
socket.should.be.instanceof(Socks5Client);
peer.should.equal(peer2);
});
it('send pong on ping', function(done) {
var peer = new Peer({host: 'localhost'});
var pingMessage = messages.Ping();
peer.sendMessage = function(message) {
message.command.should.equal('pong');
message.nonce.should.equal(pingMessage.nonce);
done();
};
peer.emit('ping', pingMessage);
});
it('relay error from socket', function(done) {
var peer = new Peer({host: 'localhost'});
var socket = new EventEmitter();
socket.connect = sinon.spy();
socket.destroy = sinon.spy();
peer._getSocket = function() {
return socket;
};
var error = new Error('error');
peer.on('error', function(err) {
err.should.equal(error);
done();
});
peer.connect();
peer.socket.emit('error', error);
});
it('will not disconnect twice on disconnect and error', function(done) {
var peer = new Peer({host: 'localhost'});
var socket = new EventEmitter();
socket.connect = sinon.stub();
socket.destroy = sinon.stub();
peer._getSocket = function() {
return socket;
};
peer.on('error', sinon.stub());
peer.connect();
var called = 0;
peer.on('disconnect', function() {
called++;
called.should.not.be.above(1);
done();
});
peer.disconnect();
peer.socket.emit('error', new Error('fake error'));
});
it('disconnect with max buffer length', function(done) {
var peer = new Peer({host: 'localhost'});
var socket = new EventEmitter();
socket.connect = sinon.spy();
peer._getSocket = function() {
return socket;
};
peer.disconnect = function() {
done();
};
peer.connect();
var buffer = new Buffer(Array(Peer.MAX_RECEIVE_BUFFER + 1));
peer.socket.emit('data', buffer);
});
it('should send version on version if not already sent', function(done) {
var peer = new Peer({host:'localhost'});
var commands = {};
peer.sendMessage = function(message) {
commands[message.command] = true;
if (commands.verack && commands.version) {
done();
}
};
peer.socket = {};
peer.emit('version', {
version: 'version',
subversion: 'subversion',
startHeight: 'startHeight'
});
});
it('should not send version on version if already sent', function(done) {
var peer = new Peer({host:'localhost'});
peer.versionSent = true;
var commands = {};
peer.sendMessage = function(message) {
message.command.should.not.equal('version');
done();
};
peer.socket = {};
peer.emit('version', {
version: 'version',
subversion: 'subversion',
startHeight: 'startHeight'
});
});
it('relay set properly', function() {
var peer = new Peer({host: 'localhost'});
peer.relay.should.equal(true);
var peer2 = new Peer({host: 'localhost', relay: false});
peer2.relay.should.equal(false);
var peer3 = new Peer({host: 'localhost', relay: true});
peer3.relay.should.equal(true);
});
it('relay setting respected', function() {
[true,false].forEach(function(relay) {
var peer = new Peer({host: 'localhost', relay: relay});
var peerSendMessageStub = sinon.stub(Peer.prototype, 'sendMessage', function(message) {
message.relay.should.equal(relay);
});
peer._sendVersion();
peerSendMessageStub.restore();
});
});
});