new bitcoind integration tests

This commit is contained in:
Manuel Araoz 2015-01-30 16:37:14 -03:00
parent 77e399cf1a
commit 98990dbc82
6 changed files with 307 additions and 162 deletions

View File

@ -24,50 +24,11 @@ var errors = bitcore.Errors;
var CONNECTION_NONCE = Random.getPseudoRandomBuffer(8); var CONNECTION_NONCE = Random.getPseudoRandomBuffer(8);
var PROTOCOL_VERSION = 70000; var PROTOCOL_VERSION = 70000;
/**
* Static helper for consuming a data buffer until the next message.
*
* @name P2P.Message#parseMessage
* @param{Network} network - the network object
* @param{Buffer} dataBuffer - the buffer to read from
* @returns{Message|undefined} A message or undefined if there is nothing to read.
*/
var parseMessage = function(network, dataBuffer) {
if (dataBuffer.length < 20) return;
// Search the next magic number
if (!discardUntilNextMessage(network, dataBuffer)) return;
var PAYLOAD_START = 16;
var payloadLen = (dataBuffer.get(PAYLOAD_START)) +
(dataBuffer.get(PAYLOAD_START + 1) << 8) +
(dataBuffer.get(PAYLOAD_START + 2) << 16) +
(dataBuffer.get(PAYLOAD_START + 3) << 24);
var messageLength = 24 + payloadLen;
if (dataBuffer.length < messageLength) return;
var command = dataBuffer.slice(4, 16).toString('ascii').replace(/\0+$/, '');
var payload = dataBuffer.slice(24, messageLength);
var checksum = dataBuffer.slice(20, 24);
var checksumConfirm = Hash.sha256sha256(payload).slice(0, 4);
if (!BufferUtil.equals(checksumConfirm, checksum)) {
dataBuffer.skip(messageLength);
return;
}
dataBuffer.skip(messageLength);
return Message.buildMessage(command, payload);
};
module.exports.parseMessage = parseMessage;
/** /**
* @desc Internal function that discards data until another message is found. * @desc Internal function that discards data until another message is found.
* @name P2P.Message#discardUntilNextMessage * @name P2P.Message#discardUntilNextMessage
*/ */
function discardUntilNextMessage(network, dataBuffer) { var discardUntilNextMessage = function(network, dataBuffer) {
var magicNumber = network.networkMagic; var magicNumber = network.networkMagic;
var i = 0; var i = 0;
@ -87,10 +48,10 @@ function discardUntilNextMessage(network, dataBuffer) {
i++; // continue scanning i++; // continue scanning
} }
} };
/** /**
* Abstract Message that knows how to parse and serialize itself. * Abstract Message this knows how to parse and serialize itself.
* Concrete subclasses should implement {fromBuffer} and {getPayload} methods. * Concrete subclasses should implement {fromBuffer} and {getPayload} methods.
* @name P2P.Message * @name P2P.Message
*/ */
@ -102,6 +63,51 @@ function Message() {}
*/ */
Message.COMMANDS = {}; Message.COMMANDS = {};
var PAYLOAD_START = 16;
/**
* Static helper for consuming a data buffer until the next message.
*
* @name P2P.Message#parseMessage
* @param{Network} network - the network object
* @param{Buffer} dataBuffer - the buffer to read from
* @returns{Message|undefined} A message or undefined if there is nothing to read.
*/
var parseMessage = function(network, dataBuffer) {
/* jshint maxstatements: 18 */
if (dataBuffer.length < 20) {
return;
}
// Search the next magic number
if (!discardUntilNextMessage(network, dataBuffer)) return;
var payloadLen = (dataBuffer.get(PAYLOAD_START)) +
(dataBuffer.get(PAYLOAD_START + 1) << 8) +
(dataBuffer.get(PAYLOAD_START + 2) << 16) +
(dataBuffer.get(PAYLOAD_START + 3) << 24);
var messageLength = 24 + payloadLen;
if (dataBuffer.length < messageLength) {
return;
}
var command = dataBuffer.slice(4, 16).toString('ascii').replace(/\0+$/, '');
var payload = dataBuffer.slice(24, messageLength);
var checksum = dataBuffer.slice(20, 24);
var checksumConfirm = Hash.sha256sha256(payload).slice(0, 4);
if (!BufferUtil.equals(checksumConfirm, checksum)) {
dataBuffer.skip(messageLength);
return;
}
dataBuffer.skip(messageLength);
return Message.buildMessage(command, payload);
};
module.exports.parseMessage = parseMessage;
/** /**
* Look up a message type by command name and instantiate the correct Message * Look up a message type by command name and instantiate the correct Message
* @name P2P.Message#buildMessage * @name P2P.Message#buildMessage
@ -109,9 +115,10 @@ Message.COMMANDS = {};
Message.buildMessage = function(command, payload) { Message.buildMessage = function(command, payload) {
try { try {
var CommandClass = Message.COMMANDS[command]; var CommandClass = Message.COMMANDS[command];
return new CommandClass.fromBuffer(payload); return new CommandClass().fromBuffer(payload);
} catch (err) { } catch (err) {
console.log('Error while parsing message', err); console.log('Error while parsing message', err);
throw err;
} }
}; };
@ -121,7 +128,7 @@ Message.buildMessage = function(command, payload) {
* @param{Buffer} payload - the buffer to read from * @param{Buffer} payload - the buffer to read from
* @returns{Message} The same message instance * @returns{Message} The same message instance
*/ */
Message.fromBuffer = function(payload) { Message.prototype.fromBuffer = function(payload) {
/* jshint unused: false */ /* jshint unused: false */
throw new errors.NotImplemented(); throw new errors.NotImplemented();
}; };
@ -141,9 +148,10 @@ Message.prototype.getPayload = function() {
* @returns{Buffer} the serialized message * @returns{Buffer} the serialized message
*/ */
Message.prototype.serialize = function(network) { Message.prototype.serialize = function(network) {
var magic = network.networkMagic; $.checkArgument(network);
var commandBuf = new Buffer(this.command, 'ascii'); var commandBuf = new Buffer(this.command, 'ascii');
if (commandBuf.length > 12) throw 'Command name too long'; $.checkState(commandBuf.length <= 12, 'Command name too long');
var magic = network.networkMagic;
var payload = this.getPayload(); var payload = this.getPayload();
var checksum = Hash.sha256sha256(payload).slice(0, 4); var checksum = Hash.sha256sha256(payload).slice(0, 4);
@ -183,52 +191,51 @@ function Version(subversion, nonce) {
} }
util.inherits(Version, Message); util.inherits(Version, Message);
Version.fromBuffer = function(payload) { Version.prototype.fromBuffer = function(payload) {
var that = new Version();
var parser = new BufferReader(payload); var parser = new BufferReader(payload);
/** /**
* @type {number} * @type {number}
* @desc The version of the bitcoin protocol * @desc The version of the bitcoin protocol
*/ */
that.version = parser.readUInt32LE(); this.version = parser.readUInt32LE();
/** /**
* @type {BN} * @type {BN}
* @desc A mapbit with service bits: what features are supported by the peer * @desc A mapbit with service bits: what features are supported by the peer
*/ */
that.services = parser.readUInt64LEBN(); this.services = parser.readUInt64LEBN();
/** /**
* @type {BN} * @type {BN}
* @desc The time this message was sent * @desc The time this message was sent
*/ */
that.timestamp = parser.readUInt64LEBN(); this.timestamp = new Date(parser.readUInt64LEBN().toNumber() * 1000);
/** /**
* @type {Buffer} * @type {Buffer}
* @desc IPv4/6 address of the interface used to connect to this peer * @desc IPv4/6 address of the interface used to connect to this peer
*/ */
that.addr_me = parser.read(26); this.addr_me = parser.read(26);
/** /**
* @type {Buffer} * @type {Buffer}
* @desc IPv4/6 address of the peer * @desc IPv4/6 address of the peer
*/ */
that.addr_you = parser.read(26); this.addr_you = parser.read(26);
/** /**
* @type {Buffer} * @type {Buffer}
* @desc A random number * @desc A random number
*/ */
that.nonce = parser.read(8); this.nonce = parser.read(8);
/** /**
* @desc A random number * @desc The node's user agent / subversion
* @type {string} * @type {string}
*/ */
that.subversion = parser.readVarintBuf().toString(); this.subversion = parser.readVarintBuf().toString();
/** /**
* @desc The height of the last block accepted in the blockchain by this peer * @desc The height of the last block accepted in the blockchain by this peer
* @type {number} * @type {number}
*/ */
that.start_height = parser.readUInt32LE(); this.start_height = parser.readUInt32LE();
return that; return this;
}; };
Version.prototype.getPayload = function() { Version.prototype.getPayload = function() {
@ -241,7 +248,7 @@ Version.prototype.getPayload = function() {
put.put(this.nonce); put.put(this.nonce);
put.varint(this.subversion.length); put.varint(this.subversion.length);
put.put(new Buffer(this.subversion, 'ascii')); put.put(new Buffer(this.subversion, 'ascii'));
put.word32le(0); put.word32le(this.start_height);
return put.buffer(); return put.buffer();
}; };
@ -260,25 +267,39 @@ function Inventory(inventory) {
this.command = 'inv'; this.command = 'inv';
/** /**
* @name P2P.Message.Inventory.inventory * @name P2P.Message.Inventory.inventory
* @desc An array of objects with `{type: int, hash: buffer}` signature * @desc An array of objects with `{type: int, hash: Buffer}` signature
* @type {Array.Buffer} * @type {Array.Buffer}
*/ */
this.inventory = inventory || []; this.inventory = inventory || [];
} }
util.inherits(Inventory, Message); util.inherits(Inventory, Message);
Inventory.fromBuffer = function(payload) { // https://en.bitcoin.it/wiki/Protocol_specification#Inventory_Vectors
var that = new Inventory(); Inventory.TYPE = {};
Inventory.TYPE.ERROR = 0;
Inventory.TYPE.TX = 1;
Inventory.TYPE.BLOCK = 2;
Inventory.TYPE.FILTERED_BLOCK = 3;
Inventory.TYPE_NAME = [
'ERROR',
'TX',
'BLOCK',
'FILTERED_BLOCK'
];
Inventory.prototype.fromBuffer = function(payload) {
var parser = new BufferReader(payload); var parser = new BufferReader(payload);
var count = parser.readVarintNum(); var count = parser.readVarintNum();
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
that.inventory.push({ var type = parser.readUInt32LE();
type: parser.readUInt32LE(), this.inventory.push({
type: type,
typeName: Inventory.TYPE_NAME[type],
hash: parser.read(32) hash: parser.read(32)
}); });
} }
return that; return this;
}; };
Inventory.prototype.getPayload = function() { Inventory.prototype.getPayload = function() {
@ -309,12 +330,18 @@ module.exports.Inventory = Message.COMMANDS.inv = Inventory;
* @param{Array} inventory - requested elements * @param{Array} inventory - requested elements
*/ */
function GetData(inventory) { function GetData(inventory) {
$.checkArgument(_.isUndefined(inventory) ||
_.isArray(inventory), 'Inventory for GetData must be an array of objects');
$.checkArgument(_.isUndefined(inventory) ||
inventory.length === 0 ||
(inventory[0] && !_.isUndefined(inventory[0].type) && !_.isUndefined(inventory[0].hash)),
'Inventory for GetData must be an array of objects');
this.command = 'getdata'; this.command = 'getdata';
this.inventory = inventory || []; this.inventory = inventory || [];
} }
util.inherits(GetData, Inventory); util.inherits(GetData, Inventory);
module.exports.GetData = GetData; module.exports.GetData = Message.COMMANDS.getdata = GetData;
/** /**
* Sent to another peer mainly to check the connection is still alive. * Sent to another peer mainly to check the connection is still alive.
@ -332,10 +359,9 @@ function Ping(nonce) {
} }
util.inherits(Ping, Message); util.inherits(Ping, Message);
Ping.fromBuffer = function(payload) { Ping.prototype.fromBuffer = function(payload) {
var that = new Ping(); this.nonce = new BufferReader(payload).read(8);
that.nonce = new BufferReader(payload).read(8); return this;
return that;
}; };
Ping.prototype.getPayload = function() { Ping.prototype.getPayload = function() {
@ -360,7 +386,7 @@ function Pong(nonce) {
} }
util.inherits(Pong, Ping); util.inherits(Pong, Ping);
Pong.fromBuffer = function() { Pong.prototype.fromBuffer = function() {
return new Pong(); return new Pong();
}; };
module.exports.Pong = Message.COMMANDS.pong = Pong; module.exports.Pong = Message.COMMANDS.pong = Pong;
@ -381,46 +407,51 @@ function Addresses(addresses) {
} }
util.inherits(Addresses, Message); util.inherits(Addresses, Message);
Addresses.fromBuffer = function(payload) { Addresses.parseIP = function(parser) {
var that = new Addresses(); // 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('.');
return {
v6: ipv6,
v4: ipv4
};
};
Addresses.prototype.fromBuffer = function(payload) {
var parser = new BufferReader(payload); var parser = new BufferReader(payload);
var addrCount = Math.min(parser.readVarintNum(), 1000); var addrCount = Math.min(parser.readVarintNum(), 1000);
that.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 time = new Date(parser.readUInt32LE() * 1000);
var services = parser.readUInt64LEBN(); var services = parser.readUInt64LEBN();
// parse the ipv6 to a string var ip = Addresses.parseIP(parser);
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(); var port = parser.readUInt16BE();
that.addresses.push({ this.addresses.push({
time: time, time: time,
services: services, services: services,
ip: { ip: ip,
v6: ipv6,
v4: ipv4
},
port: port port: port
}); });
} }
return that; return this;
}; };
Addresses.prototype.getPayload = function() { Addresses.prototype.getPayload = function() {
@ -449,7 +480,7 @@ function GetAddresses() {
} }
util.inherits(GetAddresses, Message); util.inherits(GetAddresses, Message);
GetAddresses.fromBuffer = function() { GetAddresses.prototype.fromBuffer = function() {
return new GetAddresses(); return new GetAddresses();
}; };
module.exports.GetAddresses = Message.COMMANDS.getaddr = GetAddresses; module.exports.GetAddresses = Message.COMMANDS.getaddr = GetAddresses;
@ -464,7 +495,7 @@ function VerAck() {
} }
util.inherits(VerAck, Message); util.inherits(VerAck, Message);
VerAck.fromBuffer = function() { VerAck.prototype.fromBuffer = function() {
return new VerAck(); return new VerAck();
}; };
module.exports.VerAck = Message.COMMANDS.verack = VerAck; module.exports.VerAck = Message.COMMANDS.verack = VerAck;
@ -496,12 +527,11 @@ function Alert(payload, signature) {
} }
util.inherits(Alert, Message); util.inherits(Alert, Message);
Alert.fromBuffer = function(payload) { Alert.prototype.fromBuffer = function(payload) {
var that = new Alert();
var parser = new BufferReader(payload); var parser = new BufferReader(payload);
that.payload = parser.readVarintBuf(); // TODO: Use current format this.payload = parser.readVarintBuf(); // TODO: Use current format
that.signature = parser.readVarintBuf(); this.signature = parser.readVarintBuf();
return that; return this;
}; };
Alert.prototype.getPayload = function() { Alert.prototype.getPayload = function() {
@ -534,19 +564,18 @@ function Headers(blockheaders) {
} }
util.inherits(Headers, Message); util.inherits(Headers, Message);
Headers.fromBuffer = function(payload) { Headers.prototype.fromBuffer = function(payload) {
$.checkArgument(payload && payload.length > 0, 'No data found to create Headers message'); $.checkArgument(payload && payload.length > 0, 'No data found to create Headers message');
var that = new Headers();
var parser = new BufferReader(payload); var parser = new BufferReader(payload);
var count = parser.readVarintNum(); var count = parser.readVarintNum();
that.headers = []; this.headers = [];
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
var header = BlockHeaderModel._fromBufferReader(parser); var header = BlockHeaderModel._fromBufferReader(parser);
that.headers.push(header); this.headers.push(header);
} }
return that; return this;
}; };
Headers.prototype.getPayload = function() { Headers.prototype.getPayload = function() {
@ -581,7 +610,7 @@ function Block(block) {
} }
util.inherits(Block, Message); util.inherits(Block, Message);
Block.fromBuffer = function(payload) { Block.prototype.fromBuffer = function(payload) {
$.checkArgument(BufferUtil.isBuffer(payload)); $.checkArgument(BufferUtil.isBuffer(payload));
var block = BlockModel(payload); var block = BlockModel(payload);
return new Block(block); return new Block(block);
@ -609,10 +638,9 @@ function Transaction(transaction) {
} }
util.inherits(Transaction, Message); util.inherits(Transaction, Message);
Transaction.fromBuffer = function(payload) { Transaction.prototype.fromBuffer = function(payload) {
var that = new Transaction(); this.transaction = TransactionModel(payload);
that.transaction = TransactionModel(payload); return this;
return that;
}; };
Transaction.prototype.getPayload = function() { Transaction.prototype.getPayload = function() {
@ -648,20 +676,19 @@ function GetBlocks(starts, stop) {
} }
util.inherits(GetBlocks, Message); util.inherits(GetBlocks, Message);
GetBlocks.fromBuffer = function(payload) { GetBlocks.prototype.fromBuffer = function(payload) {
var that = new GetBlocks();
var parser = new BufferReader(payload); var parser = new BufferReader(payload);
$.checkArgument(!parser.finished(), 'No data received in payload'); $.checkArgument(!parser.finished(), 'No data received in payload');
that.version = parser.readUInt32LE(); this.version = parser.readUInt32LE();
var startCount = Math.min(parser.readVarintNum(), 500); var startCount = Math.min(parser.readVarintNum(), 500);
that.starts = []; this.starts = [];
for (var i = 0; i < startCount; i++) { for (var i = 0; i < startCount; i++) {
that.starts.push(parser.read(32)); this.starts.push(parser.read(32));
} }
that.stop = parser.read(32); this.stop = parser.read(32);
return that; return this;
}; };
GetBlocks.prototype.getPayload = function() { GetBlocks.prototype.getPayload = function() {
@ -710,7 +737,7 @@ function GetHeaders(starts, stop) {
} }
util.inherits(GetHeaders, GetBlocks); util.inherits(GetHeaders, GetBlocks);
GetHeaders.fromBuffer = function() { GetHeaders.prototype.fromBuffer = function() {
return new GetHeaders(); return new GetHeaders();
}; };
module.exports.GetHeaders = Message.COMMANDS.getheaders = GetHeaders; module.exports.GetHeaders = Message.COMMANDS.getheaders = GetHeaders;

View File

@ -7,6 +7,7 @@ var Socks5Client = require('socks5-client');
var util = require('util'); var util = require('util');
var bitcore = require('bitcore'); var bitcore = require('bitcore');
var $ = bitcore.util.preconditions;
var Networks = bitcore.Networks; var Networks = bitcore.Networks;
var Messages = require('./messages'); var Messages = require('./messages');
@ -18,7 +19,7 @@ var MAX_RECEIVE_BUFFER = 10000000;
* *
* @example * @example
* ```javascript * ```javascript
* *
* var peer = new Peer('127.0.0.1').setProxy('127.0.0.1', 9050); * var peer = new Peer('127.0.0.1').setProxy('127.0.0.1', 9050);
* peer.on('tx', function(tx) { * peer.on('tx', function(tx) {
* console.log('New transaction: ', tx.id); * console.log('New transaction: ', tx.id);
@ -42,10 +43,10 @@ function Peer(host, port, network) {
network = port; network = port;
port = undefined; port = undefined;
} }
this.host = host; this.host = host || 'localhost';
this.status = Peer.STATUS.DISCONNECTED; this.status = Peer.STATUS.DISCONNECTED;
this.network = network || Networks.livenet; this.network = network || Networks.defaultNetwork;
this.port = port || this.network.port; this.port = port || this.network.port;
this.dataBuffer = new Buffers(); this.dataBuffer = new Buffers();
@ -64,7 +65,7 @@ function Peer(host, port, network) {
this.on('version', function(message) { this.on('version', function(message) {
self.version = message.version; self.version = message.version;
self.subversion = message.subversion; self.subversion = message.subversion;
self.bestHeight = message.start_height self.bestHeight = message.start_height;
}); });
this.on('ping', function(message) { this.on('ping', function(message) {
@ -89,9 +90,7 @@ Peer.STATUS = {
* @returns {Peer} The same Peer instance. * @returns {Peer} The same Peer instance.
*/ */
Peer.prototype.setProxy = function(host, port) { Peer.prototype.setProxy = function(host, port) {
if (this.status != Peer.STATUS.DISCONNECTED) { $.checkState(this.status === Peer.STATUS.DISCONNECTED);
throw Error('Invalid State');
}
this.proxy = { this.proxy = {
host: host, host: host,
@ -116,13 +115,16 @@ Peer.prototype.connect = function() {
self._sendVersion(); self._sendVersion();
}); });
this.socket.on('error', self.disconnect.bind(this)); this.socket.on('error', self._onError.bind(this));
this.socket.on('end', self.disconnect.bind(this)); this.socket.on('end', self.disconnect.bind(this));
this.socket.on('data', function(data) { this.socket.on('data', function(data) {
self.dataBuffer.push(data); self.dataBuffer.push(data);
if (self.dataBuffer.length > MAX_RECEIVE_BUFFER) return self.disconnect(); if (self.dataBuffer.length > MAX_RECEIVE_BUFFER) {
// TODO: handle this case better
return self.disconnect();
}
self._readMessage(); self._readMessage();
}); });
@ -130,6 +132,10 @@ Peer.prototype.connect = function() {
return this; return this;
}; };
Peer.prototype._onError = function(e) {
this.emit('error', e);
};
/** /**
* Disconnects the remote connection. * Disconnects the remote connection.
* *

View File

@ -0,0 +1,141 @@
'use strict';
var _ = require('lodash');
var chai = require('chai');
/* jshint unused: false */
var should = chai.should();
var sinon = require('sinon');
var _ = require('lodash');
var bitcore = require('bitcore');
var Random = bitcore.crypto.Random;
var BN = bitcore.crypto.BN;
var BufferUtil = bitcore.util.buffer;
var p2p = require('../../');
var Peer = p2p.Peer;
var Pool = p2p.Pool;
var Networks = bitcore.Networks;
var Messages = p2p.Messages;
var Block = bitcore.Block;
// config
var network = Networks.livenet;
var blockHash = {
'livenet': '000000000000000013413cf2536b491bf0988f52e90c476ffeb701c8bfdb1db9',
'testnet': '0000000058cc069d964711cd25083c0a709f4df2b34c8ff9302ce71fe5b45786'
};
// These tests require a running bitcoind instance
describe('Integration with ' + network.name + ' bitcoind', function() {
this.timeout(5000);
it('handshakes', function(cb) {
var peer = new Peer('localhost', network);
peer.once('version', function(m) {
m.version.should.be.above(70000);
m.services.toString().should.equal('1');
Math.abs(new Date() - m.timestamp).should.be.below(10000); // less than 10 seconds of time difference
m.nonce.length.should.equal(8);
m.start_height.should.be.above(300000);
cb();
});
peer.once('verack', function(m) {
should.exist(m);
m.command.should.equal('verack');
});
peer.connect();
});
var connect = function(cb) {
var peer = new Peer('localhost', network);
peer.once('ready', function() {
cb(peer);
});
peer.once('error', function(err) {
should.not.exist(err);
});
peer.connect();
};
it('connects', function(cb) {
connect(function(peer) {
peer.version.should.be.above(70000);
_.isString(peer.subversion).should.equal(true);
_.isNumber(peer.bestHeight).should.equal(true);
cb();
});
});
it('handles inv', function(cb) {
// assumes there will be at least one transaction/block
// in the next few seconds
connect(function(peer) {
peer.once('inv', function(message) {
message.inventory[0].hash.length.should.equal(32);
cb();
});
});
});
it('handles addr', function(cb) {
connect(function(peer) {
peer.once('addr', function(message) {
message.addresses.forEach(function(address) {
// console.log(address.ip.v4 + ':' + address.port);
(address.time instanceof Date).should.equal(true);
should.exist(address.ip);
(address.services instanceof BN).should.equal(true);
});
cb();
});
var message = new Messages.GetAddresses();
peer.sendMessage(message);
});
});
it('can request inv detailed info', function(cb) {
connect(function(peer) {
peer.once('block', function(message) {
//console.log(message.block.toJSON());
should.exist(message.block);
cb();
});
peer.once('tx', function(message) {
//console.log(message.transaction.toJSON());
should.exist(message.transaction);
cb();
});
peer.once('inv', function(m) {
var message = new Messages.GetData(m.inventory);
peer.sendMessage(message);
});
});
});
it('can send tx inv and receive getdata for that tx', function(cb) {
connect(function(peer) {
var type = Messages.Inventory.TYPE.TX;
var inv = [{
type: type,
typeName: Messages.Inventory.TYPE_NAME[type],
hash: Random.getRandomBuffer(32) // needs to be random for repeatability
}];
peer.once('getdata', function(message) {
message.inventory.should.deep.equal(inv);
cb();
});
var message = new Messages.Inventory(inv);
message.inventory[0].hash.length.should.equal(32);
peer.sendMessage(message);
});
});
it('can request block data', function(cb) {
connect(function(peer) {
peer.on('block', function(message) {
(message.block instanceof Block).should.equal(true);
cb();
});
// TODO: replace this for a new Messages.GetData.forTransaction(hash)
var message = new Messages.GetData([{
type: Messages.Inventory.TYPE.BLOCK,
hash: BufferUtil.reverse(new Buffer(blockHash[network.name], 'hex'))
}]);
peer.sendMessage(message);
});
});
});

View File

@ -12,36 +12,8 @@ var Networks = bitcore.Networks;
describe('Messages', function() { describe('Messages', function() {
describe('Version', function() {
it('should be able to create instance', function() {
var message = new Messages.Version();
message.command.should.equal('version');
message.version.should.equal(70000);
var version = require('../package.json').version;
message.subversion.should.equal('/bitcore:' + version + '/');
should.exist(message.nonce);
});
it('should be able to serialize the payload', function() {
var message = new Messages.Version();
var payload = message.getPayload();
should.exist(payload);
});
it('should be able to serialize the message', function() {
var message = new Messages.Version();
var buffer = message.serialize(Networks.livenet);
should.exist(buffer);
});
it('should be able to parse payload', function() {
var payload = new Buffer(Data.VERSION.payload, 'hex');
var m = Messages.Version.fromBuffer(payload);
should.exist(m);
});
});
var commands = { var commands = {
Version: 'version',
VerAck: 'verack', VerAck: 'verack',
Inventory: 'inv', Inventory: 'inv',
Addresses: 'addr', Addresses: 'addr',
@ -86,7 +58,7 @@ describe('Messages', function() {
if (noPayload.indexOf(name) === -1) { if (noPayload.indexOf(name) === -1) {
it('should be able to parse payload', function() { it('should be able to parse payload', function() {
var payload = new Buffer(data.payload, 'hex'); var payload = new Buffer(data.payload, 'hex');
var m = Messages[name].fromBuffer(payload); var m = new Messages[name]().fromBuffer(payload);
should.exist(m); should.exist(m);
}); });
} }

View File

@ -1 +0,0 @@
--recursive

View File

@ -66,7 +66,7 @@ describe('Pool', function() {
// mock a addr peer event // mock a addr peer event
var peerMessageStub = sinon.stub(Peer.prototype, '_readMessage', function() { var peerMessageStub = sinon.stub(Peer.prototype, '_readMessage', function() {
var payload = new Buffer(MessagesData.ADDR.payload, 'hex'); var payload = new Buffer(MessagesData.ADDR.payload, 'hex');
var message = Messages.Addresses.fromBuffer(payload); var message = new Messages.Addresses().fromBuffer(payload);
this.emit(message.command, message); this.emit(message.command, message);
}); });