Merge pull request #40 from throughnothing/frelay-optional

The 'fRelay' param on Version requests is optional.
This commit is contained in:
Manuel Aráoz 2015-02-19 11:31:34 -03:00
commit a9b4c078ea
7 changed files with 141 additions and 38 deletions

View File

@ -186,12 +186,13 @@ module.exports.Message = Message;
* @param{string} subversion - version of the client
* @param{Buffer} nonce - a random 8 bytes buffer
*/
function Version(subversion, nonce) {
function Version(subversion, nonce, relay) {
var packageInfo = require('../package.json');
this.command = 'version';
this.version = PROTOCOL_VERSION;
this.subversion = subversion || '/bitcore:' + packageInfo.version + '/';
this.nonce = nonce || CONNECTION_NONCE;
this.relay = relay === false ? false : true;
}
util.inherits(Version, Message);
@ -257,7 +258,12 @@ Version.prototype.fromBuffer = function(payload) {
* @desc Whether the remote peer should announce relayed transactions or not, see BIP 0037
* @type {boolean}
*/
this.relay = !!parser.readUInt8();
// This field is optional, so should not always be read
if(parser.finished()) {
this.relay = true;
} else {
this.relay = !!parser.readUInt8();
}
this._checkFinished(parser);
return this;
@ -274,6 +280,7 @@ Version.prototype.getPayload = function() {
put.varint(this.subversion.length);
put.put(new Buffer(this.subversion, 'ascii'));
put.word32le(this.start_height);
put.word8(this.relay);
return put.buffer();
};

View File

@ -33,7 +33,7 @@ var MAX_RECEIVE_BUFFER = 10000000;
* @returns {Peer} A new instance of Peer.
* @constructor
*/
function Peer(host, port, network) {
function Peer(host, port, network, relay) {
if (!(this instanceof Peer)) {
return new Peer(host, port, network);
}
@ -48,6 +48,7 @@ function Peer(host, port, network) {
this.status = Peer.STATUS.DISCONNECTED;
this.network = network || Networks.defaultNetwork;
this.port = port || this.network.port;
this.relay = relay === false ? false : true;
this.dataBuffer = new Buffers();
@ -161,7 +162,7 @@ Peer.prototype.sendMessage = function(message) {
* Internal function that sends VERSION message to the remote peer.
*/
Peer.prototype._sendVersion = function() {
var message = new Messages.Version();
var message = new Messages.Version(null, null, this.relay);
this.sendMessage(message);
};

View File

@ -30,6 +30,11 @@ function now() {
* ```
*
* @param {Network|String} network - The network to connect
* @param {Object} [options] - Options object
* @param {Boolean} [options.listenAddr=true] - Prevent new peers being added from addr messages
* @param {Boolean} [options.dnsSeed=true] - Prevent seeding with DNS discovered known peers
* @param {Boolean} [options.relay=true] - Prevent inventory announcements until a filter is loaded
* @param {Number} [options.maxSize=Pool.MaxConnectedPeers] - The max number of peers
* @returns {Pool}
* @constructor
*/
@ -37,27 +42,21 @@ function Pool(network, options) {
var self = this;
options = options || {};
this.network = Networks.get(network) || Networks.defaultNetwork;
this.keepalive = false;
this._connectedPeers = {};
this._addrs = [];
this.listenAddr = true;
this.dnsSeed = true;
this.listenAddr = options.listenAddr !== false;
this.dnsSeed = options.dnsSeed !== false;
this.relay = options.relay !== false;
this.maxSize = options.maxSize || Pool.MaxConnectedPeers;
// define configuration options
if (options) {
if (options.listenAddr === false) {
this.listenAddr = false;
}
if (options.dnsSeed === false) {
this.dnsSeed = false;
}
if (options.addrs) {
for(var i = 0; i < options.addrs.length; i++) {
this._addAddr(options.addrs[i]);
}
if (options.addrs) {
for(var i = 0; i < options.addrs.length; i++) {
this._addAddr(options.addrs[i]);
}
}
@ -152,7 +151,7 @@ Pool.prototype.numberConnected = function numberConnected() {
Pool.prototype._fillConnections = function _fillConnections() {
var length = this._addrs.length;
for (var i = 0; i < length; i++) {
if (this.numberConnected() >= Pool.MaxConnectedPeers) {
if (this.numberConnected() >= this.maxSize) {
break;
}
var addr = this._addrs[i];
@ -186,7 +185,7 @@ Pool.prototype._connectPeer = function _connectPeer(addr) {
function addConnectedPeer(addr) {
var port = addr.port || self.network.port;
var ip = addr.ip.v4 || addr.ip.v6;
var peer = new Peer(ip, port, self.network);
var peer = new Peer(ip, port, self.network, self.relay);
peer.on('disconnect', function peerDisconnect() {
self.emit('peerdisconnect', peer, addr);
});

View File

@ -3,6 +3,9 @@
"message": "f9beb4d976657273696f6e000000000065000000fc970f17721101000100000000000000ba62885400000000010000000000000000000000000000000000ffffba8886dceab0010000000000000000000000000000000000ffff05095522208de7e1c1ef80a1cea70f2f5361746f7368693a302e392e312fa317050001",
"payload": "721101000100000000000000ba62885400000000010000000000000000000000000000000000ffffba8886dceab0010000000000000000000000000000000000ffff05095522208de7e1c1ef80a1cea70f2f5361746f7368693a302e392e312fa317050001"
},
"VERSION_NO_FRELAY": {
"payload": "701101000100000000000000d78be25400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008f7e557f1b892912102f626974636f72653a302e31302e302f00000000"
},
"ALERT": {
"message": "",
"payload": "73010000003766404f00000000b305434f00000000f2030000f1030000001027000048ee00000064000000004653656520626974636f696e2e6f72672f666562323020696620796f7520686176652074726f75626c6520636f6e6e656374696e67206166746572203230204665627275617279004730450221008389df45f0703f39ec8c1cc42c13810ffcae14995bb648340219e353b63b53eb022009ec65e1c1aaeec1fd334c6b684bde2b3f573060d5b70c3a46723326e4e8a4f1"

View File

@ -113,7 +113,22 @@ describe('Messages', function() {
clazz.forBlock(BufferUtils.reverse(new Buffer(hash, 'hex'))).should.deep.equal(b);
clazz.forTransaction(BufferUtils.reverse(new Buffer(hash, 'hex'))).should.deep.equal(t);
});
});
it('Version#fromBuffer works w/o fRelay arg', function() {
var messageHex = Data.VERSION_NO_FRELAY.payload;
var message = new Messages.Version()
.fromBuffer(new Buffer(messageHex, 'hex'));
});
it('Version#relay setting works', function() {
[true,false].forEach(function(relay) {
var message = new Messages.Version(null,null,relay);
message.relay.should.equal(relay);
var messageBuf = message.getPayload();
var newMessage = new Messages.Version().fromBuffer(messageBuf)
newMessage.relay.should.equal(relay);
});
});
});

View File

@ -20,7 +20,7 @@ describe('Peer', function() {
describe('Integration test', function() {
it('parses this stream of data from a connection', function(callback) {
var peer = new p2p.Peer('');
var peer = new Peer('');
var stub = sinon.stub();
var dataCallback;
var connectCallback;
@ -120,4 +120,25 @@ describe('Peer', function() {
peer.should.equal(peer2);
});
it('Peer.relay setting set properly', function() {
var peer = new Peer('localhost');
peer.relay.should.equal(true);
var peer2 = new Peer('localhost', null, null, false);
peer2.relay.should.equal(false);
var peer3 = new Peer('localhost', null, null, true);
peer3.relay.should.equal(true);
});
it('Peer.relay setting respected', function() {
[true,false].forEach(function(relay) {
var peer = new Peer('localhost', null, null, relay);
var peerSendMessageStub = sinon.stub(Peer.prototype, 'sendMessage', function(message) {
message.relay.should.equal(relay);
});
peer._sendVersion();
peerSendMessageStub.restore();
});
});
});

View File

@ -49,10 +49,16 @@ describe('Pool', function() {
});
var options = {
dnsSeed: false,
maxSize: 1,
addrs: [
{
ip: {
v4: '10.10.10.1'
v4: 'localhost'
}
},
{
ip: {
v4: 'localhost2'
}
}
]
@ -60,7 +66,7 @@ describe('Pool', function() {
var pool = new Pool(Networks.livenet, options);
pool.connect();
pool.disconnect();
pool._addrs.length.should.equal(1);
pool._addrs.length.should.equal(2);
stub.restore();
});
@ -70,18 +76,13 @@ describe('Pool', function() {
addrs: [
{
ip: {
v4: '10.10.10.1'
}
},
{
ip: {
v4: '10.10.10.245'
v4: 'localhost'
}
}
]
};
var pool = new Pool(Networks.livenet, options);
pool._addrs.length.should.equal(2);
pool._addrs.length.should.equal(1);
});
it('should add new addrs as they are announced over the network', function(done) {
@ -193,17 +194,19 @@ describe('Pool', function() {
var peerDisconnectStub = sinon.stub(Peer.prototype, 'disconnect', function() {
this.emit('disconnect', this, {});
});
var poolRemoveStub = sinon.stub(Pool.prototype, '_removeConnectedPeer', function() {});
var pool = new Pool();
pool._addAddr({
ip: {
v4: 'localhost'
}
var pool = new Pool(null, {
dnsSeed: false,
addrs: [
{
ip: {
v4: 'localhost'
}
}
]
});
// Not great, but needed so pool won't catch its on event and fail the test
pool.removeAllListeners('peerdisconnect');
var poolDisconnectStub;
pool.on('peerconnect', function(peer, addr) {
pool.on('peerready', function(peer, addr) {
@ -219,6 +222,7 @@ describe('Pool', function() {
peerConnectStub.restore();
peerDisconnectStub.restore();
poolDisconnectStub.restore();
poolRemoveStub.restore();
// done
done();
@ -227,4 +231,57 @@ describe('Pool', function() {
pool.connect();
});
it('should propagate Pool.relay property to peers', function(done) {
var count = 0;
var peerConnectStub = sinon.stub(Peer.prototype, 'connect', function() {
this.emit('connect', this, {});
});
[true, false].forEach(function(relay) {
var pool = new Pool(null,{ relay: relay, dnsSeed: false });
pool._addAddr({ ip: { v4: 'localhost' } });
pool.on('peerconnect', function(peer, addr) {
peer.relay.should.equal(relay);
pool.disconnect();
if(++count == 2) {
done();
}
});
pool.connect();
});
peerConnectStub.restore();
});
it('should output the console correctly', function() {
var pool = new Pool();
pool.inspect().should.equal('<Pool network: livenet, connected: 0, available: 0>');
});
it('should emit seederrors with error', function(done) {
var dnsStub = sinon.stub(dns, 'resolve', function(seed, callback) {
callback(new Error('A DNS error'));
});
var pool = new Pool(Networks.livenet, {maxSize: 1});
pool.once('seederror', function(error) {
should.exist(error);
pool.disconnect();
dnsStub.restore();
done();
});
pool.connect();
});
it('should emit seederrors with notfound', function(done) {
var dnsStub = sinon.stub(dns, 'resolve', function(seed, callback) {
callback(null, []);
});
var pool = new Pool(Networks.livenet, {maxSize: 1});
pool.once('seederror', function(error) {
should.exist(error);
pool.disconnect();
dnsStub.restore();
done();
});
pool.connect();
});
});