Extensibility
- changed options in constructors - define block and transaction constructors for block and tx messages
This commit is contained in:
parent
ae93c147b7
commit
9a813bad96
@ -6,31 +6,19 @@ var BufferReader = bitcore.encoding.BufferReader;
|
||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||
var $ = bitcore.util.preconditions;
|
||||
|
||||
|
||||
BloomFilter.fromBuffer = function fromBuffer(payload) {
|
||||
var obj = {};
|
||||
var parser = new BufferReader(payload);
|
||||
var data = parser.readVarLengthBuffer();
|
||||
$.checkState(data.length <= BloomFilter.MAX_BLOOM_FILTER_SIZE,
|
||||
'Filter data must be <= MAX_BLOOM_FILTER_SIZE bytes');
|
||||
var nHashFuncs = parser.readUInt32LE();
|
||||
$.checkState(nHashFuncs <= BloomFilter.MAX_HASH_FUNCS,
|
||||
'Filter nHashFuncs must be <= MAX_HASH_FUNCS');
|
||||
var nTweak = parser.readUInt32LE();
|
||||
var nFlags = parser.readUInt8();
|
||||
|
||||
var vData = [];
|
||||
var dataParser = new BufferReader(data);
|
||||
for(var i = 0; i < data.length; i++) {
|
||||
vData.push(dataParser.readUInt8());
|
||||
var length = parser.readUInt8();
|
||||
obj.vData = [];
|
||||
for(var i = 0; i < length; i++) {
|
||||
obj.vData.push(parser.readUInt8());
|
||||
}
|
||||
|
||||
return new BloomFilter({
|
||||
vData: vData,
|
||||
nHashFuncs: nHashFuncs,
|
||||
nTweak: nTweak,
|
||||
nFlags: nFlags
|
||||
});
|
||||
}
|
||||
obj.nHashFuncs = parser.readUInt32LE();
|
||||
obj.nTweak = parser.readUInt32LE();
|
||||
obj.nFlags = parser.readUInt8();
|
||||
return new BloomFilter(obj);
|
||||
};
|
||||
|
||||
BloomFilter.prototype.toBuffer = function toBuffer() {
|
||||
var bw = new BufferWriter();
|
||||
|
||||
897
lib/commands.js
Normal file
897
lib/commands.js
Normal file
@ -0,0 +1,897 @@
|
||||
'use strict';
|
||||
|
||||
var Message = require('./message');
|
||||
var inherits = require('util').inherits;
|
||||
var packageInfo = require('../package.json');
|
||||
var bitcore = require('bitcore');
|
||||
var BN = bitcore.crypto.BN;
|
||||
var BufferReader = bitcore.encoding.BufferReader;
|
||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||
var BufferUtil = bitcore.util.buffer;
|
||||
var BloomFilter = require('./bloomfilter');
|
||||
var Put = require('bufferput'); //todo remove
|
||||
var $ = bitcore.util.preconditions;
|
||||
var _ = bitcore.deps._;
|
||||
|
||||
function Commands(options) {
|
||||
/* jshint maxstatements: 150 */
|
||||
/* jshint maxcomplexity: 10 */
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
var magicNumber = options.magicNumber;
|
||||
if (!magicNumber) {
|
||||
magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0);
|
||||
}
|
||||
var Block = options.Block || bitcore.Block;
|
||||
var BlockHeader = options.BlockHeader || bitcore.BlockHeader;
|
||||
var Transaction = options.Transaction || bitcore.Transaction;
|
||||
var MerkleBlock = options.MerkleBlock || bitcore.MerkleBlock;
|
||||
var protocolVersion = options.protocolVersion || 70000;
|
||||
|
||||
var commands = {};
|
||||
|
||||
/* shared */
|
||||
|
||||
function checkFinished(parser) {
|
||||
if(!parser.finished()) {
|
||||
throw new Error('Data still available after parsing');
|
||||
}
|
||||
}
|
||||
|
||||
function getNonce() {
|
||||
return bitcore.crypto.Random.getRandomBuffer(8);
|
||||
}
|
||||
|
||||
function writeIP(ip, bw) {
|
||||
var words = ip.v6.split(':').map(function(s) {
|
||||
return new Buffer(s, 'hex');
|
||||
});
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
var word = words[i];
|
||||
bw.write(word);
|
||||
}
|
||||
}
|
||||
|
||||
function writeAddr(addr, bw) {
|
||||
if (_.isUndefined(addr)) {
|
||||
var pad = new Buffer(Array(26));
|
||||
bw.write(pad);
|
||||
return;
|
||||
}
|
||||
|
||||
bw.writeUInt64LEBN(addr.services);
|
||||
writeIP(addr.ip, bw);
|
||||
bw.writeUInt16BE(addr.port);
|
||||
}
|
||||
|
||||
function writeInventory(inventory, bw) {
|
||||
bw.writeVarintNum(inventory.length);
|
||||
inventory.forEach(function(value) {
|
||||
bw.writeUInt32LE(value.type);
|
||||
bw.write(value.hash);
|
||||
});
|
||||
}
|
||||
|
||||
function parseIP(parser) {
|
||||
var ipv6 = [];
|
||||
var ipv4 = [];
|
||||
for (var a = 0; a < 8; a++) {
|
||||
var word = parser.read(2);
|
||||
ipv6.push(word.toString('hex'));
|
||||
if (a >= 6) {
|
||||
ipv4.push(word[0]);
|
||||
ipv4.push(word[1]);
|
||||
}
|
||||
}
|
||||
ipv6 = ipv6.join(':');
|
||||
ipv4 = ipv4.join('.');
|
||||
return {
|
||||
v6: ipv6,
|
||||
v4: ipv4
|
||||
};
|
||||
}
|
||||
|
||||
function parseAddr(parser) {
|
||||
var services = parser.readUInt64LEBN();
|
||||
var ip = parseIP(parser);
|
||||
var port = parser.readUInt16BE();
|
||||
return {
|
||||
services: services,
|
||||
ip: ip,
|
||||
port: port
|
||||
};
|
||||
}
|
||||
|
||||
function sanitizeStartStop(obj) {
|
||||
/* jshint maxcomplexity: 10 */
|
||||
$.checkArgument(_.isUndefined(options.starts) || _.isArray(options.starts));
|
||||
var starts = obj.starts;
|
||||
var stop = obj.stop;
|
||||
if (starts) {
|
||||
starts = starts.map(function(hash) {
|
||||
if (_.isString(hash)) {
|
||||
return BufferUtil.reverse(new Buffer(hash, 'hex'));
|
||||
} else {
|
||||
return hash;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
starts = [];
|
||||
}
|
||||
|
||||
for (var i = 0; i < starts.length; i++) {
|
||||
if (starts[i].length !== 32) {
|
||||
throw new Error('Invalid hash ' + i + ' length: ' + starts[i].length);
|
||||
}
|
||||
}
|
||||
|
||||
stop = obj.stop;
|
||||
if (_.isString(stop)) {
|
||||
stop = BufferUtil.reverse(new Buffer(stop, 'hex'));
|
||||
}
|
||||
if (!stop) {
|
||||
stop = BufferUtil.NULL_HASH;
|
||||
}
|
||||
obj.starts = starts;
|
||||
obj.stop = stop;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version message is used on connection creation to advertise
|
||||
* the type of node. The remote node will respond with its version, and no
|
||||
* communication is possible until both peers have exchanged their versions.
|
||||
* By default, bitcore advertises itself as named `bitcore:0.8`.
|
||||
*
|
||||
* @param{Object} obj - properties for the version
|
||||
* @param{String} obj.subversion - version of the client
|
||||
* @param{Buffer} obj.nonce - a random 8 byte buffer
|
||||
*/
|
||||
commands.version = function(obj) {
|
||||
Message.call(this, obj);
|
||||
this.command = 'version';
|
||||
_.assign(this, obj);
|
||||
this.magicNumber = magicNumber;
|
||||
this.nonce = this.nonce || getNonce();
|
||||
this.services = this.services || new BN(1, 10);
|
||||
this.timestamp = this.timestamp || new Date();
|
||||
this.version = this.version || protocolVersion;
|
||||
this.subversion = this.subversion || '/bitcore:' + packageInfo.version + '/';
|
||||
this.startHeight = this.startHeight || 0;
|
||||
};
|
||||
inherits(commands.version, Message);
|
||||
|
||||
commands.version.fromObject = function(obj) {
|
||||
return new commands.version(obj);
|
||||
};
|
||||
|
||||
commands.version.fromBuffer = function(payload) {
|
||||
var parser = new BufferReader(payload);
|
||||
var obj = {};
|
||||
obj.version = parser.readUInt32LE();
|
||||
obj.services = parser.readUInt64LEBN();
|
||||
obj.timestamp = new Date(parser.readUInt64LEBN().toNumber() * 1000);
|
||||
|
||||
obj.addrMe = {
|
||||
services: parser.readUInt64LEBN(),
|
||||
ip: parseIP(parser),
|
||||
port: parser.readUInt16BE()
|
||||
};
|
||||
obj.addrYou = {
|
||||
services: parser.readUInt64LEBN(),
|
||||
ip: parseIP(parser),
|
||||
port: parser.readUInt16BE()
|
||||
};
|
||||
obj.nonce = parser.read(8);
|
||||
obj.subversion = parser.readVarLengthBuffer().toString();
|
||||
obj.startHeight = parser.readUInt32LE();
|
||||
|
||||
if(parser.finished()) {
|
||||
obj.relay = true;
|
||||
} else {
|
||||
obj.relay = !!parser.readUInt8();
|
||||
}
|
||||
checkFinished(parser);
|
||||
|
||||
return commands.version.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.version.prototype.getPayload = function() {
|
||||
var bw = new BufferWriter();
|
||||
bw.writeUInt32LE(this.version);
|
||||
bw.writeUInt64LEBN(this.services);
|
||||
|
||||
var timestampBuffer = new Buffer(Array(8));
|
||||
timestampBuffer.writeUInt32LE(Math.round(this.timestamp.getTime() / 1000), 0);
|
||||
bw.write(timestampBuffer);
|
||||
|
||||
writeAddr(this.addrMe, bw);
|
||||
writeAddr(this.addrYou, bw);
|
||||
bw.write(this.nonce);
|
||||
bw.writeVarintNum(this.subversion.length);
|
||||
bw.write(new Buffer(this.subversion, 'ascii'));
|
||||
bw.writeUInt32LE(this.startHeight);
|
||||
bw.writeUInt8(this.relay);
|
||||
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
/* verack */
|
||||
|
||||
commands.verack = function(options) {
|
||||
Message.call(this, options);
|
||||
this.magicNumber = magicNumber;
|
||||
this.command = 'verack';
|
||||
};
|
||||
inherits(commands.verack, Message);
|
||||
|
||||
commands.verack.fromObject = function(obj) {
|
||||
return new commands.verack(obj);
|
||||
};
|
||||
|
||||
commands.verack.fromBuffer = function(payload) {
|
||||
return commands.verack.fromObject({});
|
||||
};
|
||||
|
||||
commands.verack.prototype.getPayload = function() {
|
||||
return BufferUtil.EMPTY_BUFFER;
|
||||
};
|
||||
|
||||
/* ping */
|
||||
|
||||
commands.ping = function(options) {
|
||||
Message.call(this, options);
|
||||
this.command = 'ping';
|
||||
this.magicNumber = magicNumber;
|
||||
this.nonce = options.nonce || getNonce();
|
||||
};
|
||||
inherits(commands.ping, Message);
|
||||
|
||||
commands.ping.prototype.getPayload = function() {
|
||||
return this.nonce;
|
||||
};
|
||||
|
||||
commands.ping.fromObject = function(obj) {
|
||||
return new commands.ping(obj);
|
||||
};
|
||||
|
||||
commands.ping.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
var parser = new BufferReader(payload);
|
||||
obj.nonce = parser.read(8);
|
||||
|
||||
checkFinished(parser);
|
||||
return commands.ping.fromObject(obj);
|
||||
};
|
||||
|
||||
/* pong */
|
||||
|
||||
commands.pong = function(options) {
|
||||
Message.call(this, options);
|
||||
this.command = 'pong';
|
||||
this.magicNumber = magicNumber;
|
||||
this.nonce = options.nonce;
|
||||
};
|
||||
inherits(commands.pong, Message);
|
||||
|
||||
commands.pong.fromObject = function(obj) {
|
||||
return new commands.pong(obj);
|
||||
};
|
||||
|
||||
commands.pong.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
var parser = new BufferReader(payload);
|
||||
obj.nonce = parser.read(8);
|
||||
|
||||
checkFinished(parser);
|
||||
return commands.pong.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.pong.prototype.getPayload = function() {
|
||||
return this.nonce;
|
||||
};
|
||||
|
||||
/* block */
|
||||
|
||||
commands.block = function(options) {
|
||||
Message.call(this, options);
|
||||
this.command = 'block';
|
||||
this.magicNumber = magicNumber;
|
||||
this.block = options.block;
|
||||
};
|
||||
inherits(commands.block, Message);
|
||||
|
||||
commands.block.fromObject = function(options) {
|
||||
return new commands.block(options);
|
||||
};
|
||||
|
||||
commands.block.fromBuffer = function(payload) {
|
||||
var block = Block.fromBuffer(payload);
|
||||
return commands.block.fromObject({block: block});
|
||||
};
|
||||
|
||||
commands.block.prototype.getPayload = function() {
|
||||
return this.block.toBuffer();
|
||||
};
|
||||
|
||||
/* tx */
|
||||
|
||||
commands.tx = function(options) {
|
||||
Message.call(this, options);
|
||||
this.command = 'tx';
|
||||
this.magicNumber = magicNumber;
|
||||
this.transaction = options.transaction;
|
||||
};
|
||||
inherits(commands.tx, Message);
|
||||
|
||||
commands.tx.fromObject = function(options) {
|
||||
return new commands.tx(options);
|
||||
};
|
||||
|
||||
commands.tx.fromBuffer = function(payload) {
|
||||
var transaction;
|
||||
if (Transaction.prototype.fromBuffer) {
|
||||
transaction = Transaction().fromBuffer(payload);
|
||||
} else {
|
||||
transaction = Transaction.fromBuffer(payload);
|
||||
}
|
||||
return commands.tx.fromObject({transaction: transaction});
|
||||
};
|
||||
|
||||
commands.tx.prototype.getPayload = function() {
|
||||
return this.transaction.toBuffer();
|
||||
};
|
||||
|
||||
/* getdata */
|
||||
|
||||
commands.getdata = function(options) {
|
||||
Message.call(this, options);
|
||||
this.command = 'getdata';
|
||||
this.magicNumber = magicNumber;
|
||||
this.inventory = options.inventory;
|
||||
};
|
||||
|
||||
inherits(commands.getdata, Message);
|
||||
|
||||
commands.getdata.fromObject = function(options) {
|
||||
return new commands.getdata(options);
|
||||
};
|
||||
|
||||
commands.getdata.fromBuffer = function(payload) {
|
||||
var obj = {
|
||||
inventory: []
|
||||
};
|
||||
|
||||
var parser = new BufferReader(payload);
|
||||
var count = parser.readVarintNum();
|
||||
for (var i = 0; i < count; i++) {
|
||||
var type = parser.readUInt32LE();
|
||||
var hash = parser.read(32);
|
||||
obj.inventory.push({type: type, hash: hash});
|
||||
}
|
||||
|
||||
checkFinished(parser);
|
||||
return commands.getdata.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.getdata.prototype.getPayload = function() {
|
||||
var bw = new BufferWriter();
|
||||
writeInventory(this.inventory, bw);
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sent in response to a `getheaders` message. It contains information about
|
||||
* block headers.
|
||||
*
|
||||
* @param{Array} blockheaders - array of block headers
|
||||
*/
|
||||
commands.headers = function(options) {
|
||||
Message.call(this, options);
|
||||
this.magicNumber = magicNumber;
|
||||
this.command = 'headers';
|
||||
this.headers = options.headers;
|
||||
};
|
||||
inherits(commands.headers, Message);
|
||||
|
||||
commands.headers.fromObject = function(options) {
|
||||
return new commands.headers(options);
|
||||
};
|
||||
|
||||
commands.headers.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
|
||||
$.checkArgument(payload && payload.length > 0, 'No data found to create Headers message');
|
||||
var parser = new BufferReader(payload);
|
||||
var count = parser.readVarintNum();
|
||||
|
||||
obj.headers = [];
|
||||
for (var i = 0; i < count; i++) {
|
||||
var header = BlockHeader.fromBufferReader(parser);
|
||||
obj.headers.push(header);
|
||||
var txn_count = parser.readUInt8();
|
||||
$.checkState(txn_count === 0, 'txn_count should always be 0');
|
||||
|
||||
}
|
||||
checkFinished(parser);
|
||||
|
||||
return commands.headers.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.headers.prototype.getPayload = function() {
|
||||
var put = new Put();
|
||||
put.varint(this.headers.length);
|
||||
|
||||
for (var i = 0; i < this.headers.length; i++) {
|
||||
var buffer = this
|
||||
.headers[i]
|
||||
.toBuffer();
|
||||
put.put(buffer);
|
||||
put.varint(0);
|
||||
}
|
||||
|
||||
return put.buffer();
|
||||
};
|
||||
|
||||
/* notfound */
|
||||
|
||||
commands.notfound = function(options) {
|
||||
Message.call(this, options);
|
||||
this.command = 'notfound';
|
||||
this.magicNumber = magicNumber;
|
||||
this.inventory = options.inventory;
|
||||
};
|
||||
inherits(commands.notfound, Message);
|
||||
|
||||
commands.notfound.fromObject = function(options) {
|
||||
return new commands.notfound(options);
|
||||
};
|
||||
|
||||
commands.notfound.fromBuffer = function(payload) {
|
||||
var obj = {
|
||||
inventory: []
|
||||
};
|
||||
|
||||
var parser = new BufferReader(payload);
|
||||
var count = parser.readVarintNum();
|
||||
for (var i = 0; i < count; i++) {
|
||||
var type = parser.readUInt32LE();
|
||||
var hash = parser.read(32);
|
||||
obj.inventory.push({type: type, hash: hash});
|
||||
}
|
||||
|
||||
checkFinished(parser);
|
||||
return commands.notfound.fromObject(obj);
|
||||
|
||||
};
|
||||
|
||||
commands.notfound.prototype.getPayload = function() {
|
||||
var bw = new BufferWriter();
|
||||
writeInventory(this.inventory, bw);
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
/* inv */
|
||||
|
||||
commands.inv = function(options) {
|
||||
Message.call(this, options);
|
||||
this.command = 'inv';
|
||||
this.magicNumber = magicNumber;
|
||||
this.inventory = options.inventory;
|
||||
};
|
||||
|
||||
inherits(commands.inv, Message);
|
||||
|
||||
commands.inv.fromObject = function(options) {
|
||||
return new commands.inv(options);
|
||||
};
|
||||
|
||||
commands.inv.prototype.getPayload = function() {
|
||||
var bw = new BufferWriter();
|
||||
writeInventory(this.inventory, bw);
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
commands.inv.fromBuffer = function(payload) {
|
||||
var obj = {
|
||||
inventory: []
|
||||
};
|
||||
|
||||
var parser = new BufferReader(payload);
|
||||
var count = parser.readVarintNum();
|
||||
for (var i = 0; i < count; i++) {
|
||||
var type = parser.readUInt32LE();
|
||||
var hash = parser.read(32);
|
||||
obj.inventory.push({type: type, hash: hash});
|
||||
}
|
||||
|
||||
checkFinished(parser);
|
||||
return commands.inv.fromObject(obj);
|
||||
};
|
||||
|
||||
/* addr */
|
||||
|
||||
commands.addr = function(options) {
|
||||
Message.call(this, options);
|
||||
this.command = 'addr';
|
||||
this.magicNumber = magicNumber;
|
||||
this.addresses = options.addresses;
|
||||
};
|
||||
inherits(commands.addr, Message);
|
||||
|
||||
commands.addr.fromObject = function(options) {
|
||||
return new commands.addr(options);
|
||||
};
|
||||
|
||||
commands.addr.fromBuffer = function(payload) {
|
||||
var parser = new BufferReader(payload);
|
||||
|
||||
var addrCount = parser.readVarintNum();
|
||||
|
||||
var obj = {};
|
||||
obj.addresses = [];
|
||||
for (var i = 0; i < addrCount; i++) {
|
||||
// todo: time only available on versions >=31402
|
||||
var time = new Date(parser.readUInt32LE() * 1000);
|
||||
|
||||
var addr = parseAddr(parser);
|
||||
addr.time = time;
|
||||
obj.addresses.push(addr);
|
||||
}
|
||||
|
||||
checkFinished(parser);
|
||||
return commands.addr.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.addr.prototype.getPayload = function() {
|
||||
var bw = new BufferWriter();
|
||||
bw.writeVarintNum(this.addresses.length);
|
||||
|
||||
for (var i = 0; i < this.addresses.length; i++) {
|
||||
var addr = this.addresses[i];
|
||||
bw.writeUInt32LE(addr.time.getTime() / 1000);
|
||||
writeAddr(addr, bw);
|
||||
}
|
||||
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
/* alert */
|
||||
|
||||
commands.alert = function(options) {
|
||||
Message.call(this, options);
|
||||
this.magicNumber = magicNumber;
|
||||
this.command = 'alert';
|
||||
|
||||
this.payload = options.payload || new Buffer(32);
|
||||
this.signature = options.signature || new Buffer(32);
|
||||
|
||||
};
|
||||
inherits(commands.alert, Message);
|
||||
|
||||
commands.alert.fromObject = function(options) {
|
||||
return new commands.alert(options);
|
||||
};
|
||||
|
||||
commands.alert.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
var parser = new BufferReader(payload);
|
||||
obj.payload = parser.readVarLengthBuffer();
|
||||
obj.signature = parser.readVarLengthBuffer();
|
||||
checkFinished(parser);
|
||||
return commands.alert.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.alert.prototype.getPayload = function() {
|
||||
var put = new Put();
|
||||
put.varint(this.payload.length);
|
||||
put.put(this.payload);
|
||||
|
||||
put.varint(this.signature.length);
|
||||
put.put(this.signature);
|
||||
|
||||
return put.buffer();
|
||||
};
|
||||
|
||||
/* reject */
|
||||
// todo: add payload: https://en.bitcoin.it/wiki/Protocol_documentation#reject
|
||||
commands.reject = function(options) {
|
||||
Message.call(this, options);
|
||||
this.magicNumber = magicNumber;
|
||||
this.command = 'reject';
|
||||
};
|
||||
inherits(commands.reject, Message);
|
||||
|
||||
commands.reject.fromObject = function(options) {
|
||||
return new commands.reject(options);
|
||||
};
|
||||
|
||||
commands.reject.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
return commands.reject.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.reject.prototype.getPayload = function() {
|
||||
return BufferUtil.EMPTY_BUFFER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains information about a MerkleBlock
|
||||
*
|
||||
* @name P2P.Message.MerkleBlock
|
||||
* @param {MerkleBlock} block
|
||||
*/
|
||||
commands.merkleblock = function(options) {
|
||||
Message.call(this, options);
|
||||
this.magicNumber = magicNumber;
|
||||
this.command = 'merkleblock';
|
||||
$.checkArgument(
|
||||
_.isUndefined(options.merkleBlock) ||
|
||||
options.merkleBlock instanceof MerkleBlock
|
||||
);
|
||||
this.merkleBlock = options.merkleBlock;
|
||||
};
|
||||
inherits(commands.merkleblock, Message);
|
||||
|
||||
commands.merkleblock.fromObject = function(options) {
|
||||
return new commands.merkleblock(options);
|
||||
};
|
||||
|
||||
commands.merkleblock.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
$.checkArgument(BufferUtil.isBuffer(payload));
|
||||
obj.merkleBlock = MerkleBlock.fromBuffer(payload);
|
||||
return commands.merkleblock.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.merkleblock.prototype.getPayload = function() {
|
||||
return this.merkleBlock ? this.merkleBlock.toBuffer() : BufferUtil.EMPTY_BUFFER;
|
||||
};
|
||||
|
||||
/* filterload */
|
||||
|
||||
commands.filterload = function(options) {
|
||||
Message.call(this, options);
|
||||
this.magicNumber = magicNumber;
|
||||
this.command = 'filterload';
|
||||
$.checkArgument(_.isUndefined(options.filter) || options.filter instanceof BloomFilter,
|
||||
'BloomFilter object or undefined required for FilterLoad');
|
||||
this.filter = options.filter;
|
||||
};
|
||||
inherits(commands.filterload, Message);
|
||||
|
||||
commands.filterload.fromObject = function(options) {
|
||||
return new commands.filterload(options);
|
||||
};
|
||||
|
||||
commands.filterload.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
obj.filter = BloomFilter.fromBuffer(payload);
|
||||
return commands.filterload.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.filterload.prototype.getPayload = function() {
|
||||
if(this.filter) {
|
||||
return this.filter.toBuffer();
|
||||
} else {
|
||||
return BufferUtil.EMPTY_BUFFER;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Request peer to add data to a bloom filter already set by 'filterload'
|
||||
*
|
||||
* @name P2P.Message.filteradd
|
||||
* @param{Buffer} data - Array of bytes representing bloom filter data
|
||||
*/
|
||||
commands.filteradd = function(options) {
|
||||
Message.call(this, options);
|
||||
this.magicNumber = magicNumber;
|
||||
this.command = 'filteradd';
|
||||
this.data = options.data || BufferUtil.EMPTY_BUFFER;
|
||||
};
|
||||
inherits(commands.filteradd, Message);
|
||||
|
||||
commands.filteradd.fromObject = function(options) {
|
||||
return new commands.filteradd(options);
|
||||
};
|
||||
|
||||
commands.filteradd.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
$.checkArgument(payload);
|
||||
var parser = new BufferReader(payload);
|
||||
obj.data = parser.readVarLengthBuffer();
|
||||
checkFinished(parser);
|
||||
return commands.filteradd.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.filteradd.prototype.getPayload = function() {
|
||||
var bw = new BufferWriter();
|
||||
bw.writeVarintNum(this.data.length);
|
||||
bw.write(this.data);
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
/* filterclear */
|
||||
|
||||
commands.filterclear = function(options) {
|
||||
Message.call(this, options);
|
||||
this.magicNumber = magicNumber;
|
||||
this.command = 'filterclear';
|
||||
};
|
||||
inherits(commands.filterclear, Message);
|
||||
|
||||
commands.filterclear.fromObject = function(options) {
|
||||
return new commands.filterclear(options);
|
||||
};
|
||||
|
||||
commands.filterclear.fromBuffer = function(payload) {
|
||||
return commands.filterclear.fromObject({});
|
||||
};
|
||||
|
||||
commands.filterclear.prototype.getPayload = function() {
|
||||
return BufferUtil.EMPTY_BUFFER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Query another peer about blocks. It can query for multiple block hashes,
|
||||
* and the response will contain all the chains of blocks starting from those
|
||||
* hashes.
|
||||
*
|
||||
* @param{Array} starts - array of buffers or strings with the starting block hashes
|
||||
* @param{Buffer} [stop] - hash of the last block
|
||||
*/
|
||||
commands.getblocks = function(options) {
|
||||
Message.call(this, options);
|
||||
this.command = 'getblocks';
|
||||
this.version = protocolVersion;
|
||||
this.magicNumber = magicNumber;
|
||||
|
||||
options = sanitizeStartStop(options);
|
||||
this.starts = options.starts;
|
||||
this.stop = options.stop;
|
||||
|
||||
};
|
||||
inherits(commands.getblocks, Message);
|
||||
|
||||
commands.getblocks.fromObject = function(obj) {
|
||||
return new commands.getblocks(obj);
|
||||
};
|
||||
|
||||
commands.getblocks.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
var parser = new BufferReader(payload);
|
||||
$.checkArgument(!parser.finished(), 'No data received in payload');
|
||||
|
||||
obj.version = parser.readUInt32LE();
|
||||
var startCount = parser.readVarintNum();
|
||||
|
||||
obj.starts = [];
|
||||
for (var i = 0; i < startCount; i++) {
|
||||
obj.starts.push(parser.read(32));
|
||||
}
|
||||
obj.stop = parser.read(32);
|
||||
checkFinished(parser);
|
||||
return commands.getblocks.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.getblocks.prototype.getPayload = function() {
|
||||
var bw = new BufferWriter();
|
||||
bw.writeUInt32LE(this.version);
|
||||
bw.writeVarintNum(this.starts.length);
|
||||
for (var i = 0; i < this.starts.length; i++) {
|
||||
bw.write(this.starts[i]);
|
||||
}
|
||||
if (this.stop.length !== 32) {
|
||||
throw new Error('Invalid hash length: ' + this.stop.length);
|
||||
}
|
||||
bw.write(this.stop);
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
/**
|
||||
* Request block headers starting from a hash
|
||||
*
|
||||
* @param{Array} starts - array of buffers with the starting block hashes
|
||||
* @param{Buffer} [stop] - hash of the last block
|
||||
*/
|
||||
//todo: need test data
|
||||
commands.getheaders = function(options) {
|
||||
Message.call(this, options);
|
||||
this.command = 'getheaders';
|
||||
this.version = protocolVersion;
|
||||
this.magicNumber = magicNumber;
|
||||
|
||||
options = sanitizeStartStop(options);
|
||||
this.starts = options.starts;
|
||||
this.stop = options.stop;
|
||||
|
||||
};
|
||||
inherits(commands.getheaders, Message);
|
||||
|
||||
commands.getheaders.fromObject = function(obj) {
|
||||
return new commands.getheaders(obj);
|
||||
};
|
||||
|
||||
commands.getheaders.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
var parser = new BufferReader(payload);
|
||||
$.checkArgument(!parser.finished(), 'No data received in payload');
|
||||
|
||||
obj.version = parser.readUInt32LE();
|
||||
var startCount = Math.min(parser.readVarintNum(), 500);
|
||||
|
||||
obj.starts = [];
|
||||
for (var i = 0; i < startCount; i++) {
|
||||
obj.starts.push(parser.read(32));
|
||||
}
|
||||
obj.stop = parser.read(32);
|
||||
checkFinished(parser);
|
||||
return commands.getheaders.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.getheaders.prototype.getPayload = function() {
|
||||
var put = new Put();
|
||||
put.word32le(this.version);
|
||||
put.varint(this.starts.length);
|
||||
for (var i = 0; i < this.starts.length; i++) {
|
||||
put.put(this.starts[i]);
|
||||
}
|
||||
if (this.stop.length !== 32) {
|
||||
throw new Error('Invalid hash length: ' + this.stop.length);
|
||||
}
|
||||
put.put(this.stop);
|
||||
return put.buffer();
|
||||
};
|
||||
|
||||
/* mempool */
|
||||
commands.mempool = function(options) {
|
||||
Message.call(this, options);
|
||||
this.magicNumber = magicNumber;
|
||||
this.command = 'mempool';
|
||||
};
|
||||
inherits(commands.mempool, Message);
|
||||
|
||||
commands.mempool.fromObject = function(options) {
|
||||
return new commands.mempool(options);
|
||||
};
|
||||
|
||||
commands.mempool.fromBuffer = function(payload) {
|
||||
return commands.mempool.fromObject({});
|
||||
};
|
||||
|
||||
commands.mempool.prototype.getPayload = function() {
|
||||
return BufferUtil.EMPTY_BUFFER;
|
||||
};
|
||||
|
||||
/* getaddr */
|
||||
//todo: need test data
|
||||
commands.getaddr = function(options) {
|
||||
Message.call(this, options);
|
||||
this.magicNumber = magicNumber;
|
||||
this.command = 'getaddr';
|
||||
};
|
||||
inherits(commands.getaddr, Message);
|
||||
|
||||
commands.getaddr.fromObject = function(options) {
|
||||
return new commands.getaddr(options);
|
||||
};
|
||||
|
||||
commands.getaddr.fromBuffer = function(payload) {
|
||||
var obj = {};
|
||||
return commands.getaddr.fromObject(obj);
|
||||
};
|
||||
|
||||
commands.getaddr.prototype.getPayload = function() {
|
||||
return BufferUtil.EMPTY_BUFFER;
|
||||
};
|
||||
|
||||
return commands;
|
||||
|
||||
}
|
||||
|
||||
module.exports = Commands;
|
||||
13
lib/index.js
13
lib/index.js
@ -1,9 +1,16 @@
|
||||
/**
|
||||
* @namespace P2P
|
||||
*/
|
||||
|
||||
var Messages = require('./messages');
|
||||
|
||||
module.exports = {
|
||||
Messages: require('./messages'),
|
||||
Message: require('./message'),
|
||||
Commands: require('./commands'),
|
||||
Inventory: require('./inventory'),
|
||||
BloomFilter: require('./bloomfilter'),
|
||||
Messages: Messages,
|
||||
messages: new Messages(),
|
||||
Peer: require('./peer'),
|
||||
Pool: require('./pool'),
|
||||
BloomFilter: require('./bloomfilter')
|
||||
Pool: require('./pool')
|
||||
};
|
||||
|
||||
82
lib/inventory.js
Normal file
82
lib/inventory.js
Normal file
@ -0,0 +1,82 @@
|
||||
'use strict';
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var $ = bitcore.util.preconditions;
|
||||
var BufferUtil = bitcore.util.buffer;
|
||||
var BufferReader = bitcore.encoding.BufferReader;
|
||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||
var _ = bitcore.deps._;
|
||||
|
||||
function Inventory(obj) {
|
||||
this.type = obj.type;
|
||||
if (!BufferUtil.isBuffer(obj.hash)) {
|
||||
throw new TypeError('Unexpected hash, expected to be a buffer');
|
||||
}
|
||||
this.hash = obj.hash;
|
||||
|
||||
}
|
||||
|
||||
Inventory.forItem = function(type, hash) {
|
||||
$.checkArgument(hash);
|
||||
//todo: is reversing expected behavior?
|
||||
if (_.isString(hash)) {
|
||||
hash = new Buffer(hash, 'hex');
|
||||
hash = BufferUtil.reverse(hash);
|
||||
}
|
||||
return new Inventory({type: type, hash: hash});
|
||||
};
|
||||
|
||||
Inventory.forBlock = function(hash) {
|
||||
return Inventory.forItem(Inventory.TYPE.BLOCK, hash);
|
||||
};
|
||||
|
||||
Inventory.forFilteredBlock = function(hash) {
|
||||
return Inventory.forItem(Inventory.TYPE.FILTERED_BLOCK, hash);
|
||||
};
|
||||
|
||||
Inventory.forTransaction = function(hash) {
|
||||
return Inventory.forItem(Inventory.TYPE.TX, hash);
|
||||
};
|
||||
|
||||
Inventory.prototype.toBuffer = function() {
|
||||
var bw = new BufferWriter();
|
||||
bw.writeUInt32LE(this.type);
|
||||
bw.write(this.hash);
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
Inventory.prototype.toBufferWriter = function(bw) {
|
||||
bw.writeUInt32LE(this.type);
|
||||
bw.write(this.hash);
|
||||
return bw;
|
||||
};
|
||||
|
||||
Inventory.fromBuffer = function(payload) {
|
||||
var parser = new BufferReader(payload);
|
||||
var obj = {};
|
||||
obj.type = parser.readUInt32LE();
|
||||
obj.hash = parser.read(32);
|
||||
return new Inventory(obj);
|
||||
};
|
||||
|
||||
Inventory.fromBufferWriter = function(bw) {
|
||||
var obj = {};
|
||||
obj.type = bw.readUInt32LE();
|
||||
obj.hash = bw.read(32);
|
||||
return new Inventory(obj);
|
||||
};
|
||||
|
||||
// https://en.bitcoin.it/wiki/Protocol_specification#Inventory_Vectors
|
||||
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'
|
||||
];
|
||||
|
||||
module.exports = Inventory;
|
||||
34
lib/message.js
Normal file
34
lib/message.js
Normal file
@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||
var Hash = bitcore.crypto.Hash;
|
||||
|
||||
/**
|
||||
* Base message that can be inherited to add an additional
|
||||
* `getPayload` method to modify the message payload.
|
||||
*/
|
||||
function Message(options) {
|
||||
this.command = options.command;
|
||||
this.magicNumber = options.magicNumber;
|
||||
}
|
||||
|
||||
Message.prototype.toBuffer = Message.prototype.serialize = function() {
|
||||
|
||||
var commandBuf = new Buffer(Array(12));
|
||||
commandBuf.write(this.command, 'ascii');
|
||||
|
||||
var payload = this.getPayload();
|
||||
var checksum = Hash.sha256sha256(payload).slice(0, 4);
|
||||
|
||||
var bw = new BufferWriter();
|
||||
bw.writeUInt32LE(this.magicNumber);
|
||||
bw.write(commandBuf);
|
||||
bw.writeUInt32LE(payload.length);
|
||||
bw.write(checksum);
|
||||
bw.write(payload);
|
||||
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
module.exports = Message;
|
||||
979
lib/messages.js
979
lib/messages.js
File diff suppressed because it is too large
Load Diff
70
lib/peer.js
70
lib/peer.js
@ -4,14 +4,10 @@ var Buffers = require('buffers');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var Net = require('net');
|
||||
var Socks5Client = require('socks5-client');
|
||||
var util = require('util');
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var $ = bitcore.util.preconditions;
|
||||
var Networks = bitcore.Networks;
|
||||
var Messages = require('./messages');
|
||||
|
||||
var MAX_RECEIVE_BUFFER = 10000000;
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* A Peer instance represents a remote bitcoin node and allows to communicate
|
||||
@ -33,28 +29,33 @@ var MAX_RECEIVE_BUFFER = 10000000;
|
||||
* @returns {Peer} A new instance of Peer.
|
||||
* @constructor
|
||||
*/
|
||||
function Peer(host, port, network, relay) {
|
||||
function Peer(options) {
|
||||
if (!(this instanceof Peer)) {
|
||||
return new Peer(host, port, network);
|
||||
return new Peer(options);
|
||||
}
|
||||
|
||||
// overloading stuff
|
||||
if (port instanceof Object && !network) {
|
||||
network = port;
|
||||
port = undefined;
|
||||
}
|
||||
|
||||
this.host = host || 'localhost';
|
||||
this.host = options.host || 'localhost';
|
||||
this.status = Peer.STATUS.DISCONNECTED;
|
||||
this.network = network || Networks.defaultNetwork;
|
||||
this.port = port || this.network.port;
|
||||
this.relay = relay === false ? false : true;
|
||||
this.port = options.port;
|
||||
|
||||
|
||||
this.network = Networks.get(options.network) || Networks.defaultNetwork;
|
||||
if (!this.port) {
|
||||
this.port = this.network.port;
|
||||
}
|
||||
|
||||
this.messages = options.messages || new Messages({
|
||||
magicNumber: this.network.networkMagic.readUInt32LE(0),
|
||||
Block: bitcore.Block,
|
||||
Transaction: bitcore.Transaction
|
||||
});
|
||||
|
||||
this.dataBuffer = new Buffers();
|
||||
|
||||
this.version = 0;
|
||||
this.bestHeight = 0;
|
||||
this.subversion = null;
|
||||
this.relay = options.relay === false ? false : true;
|
||||
|
||||
// set message handlers
|
||||
var self = this;
|
||||
@ -76,6 +77,7 @@ function Peer(host, port, network, relay) {
|
||||
}
|
||||
util.inherits(Peer, EventEmitter);
|
||||
|
||||
Peer.MAX_RECEIVE_BUFFER = 10000000;
|
||||
Peer.STATUS = {
|
||||
DISCONNECTED: 'disconnected',
|
||||
CONNECTING: 'connecting',
|
||||
@ -91,8 +93,6 @@ Peer.STATUS = {
|
||||
* @returns {Peer} The same Peer instance.
|
||||
*/
|
||||
Peer.prototype.setProxy = function(host, port) {
|
||||
$.checkState(this.status === Peer.STATUS.DISCONNECTED);
|
||||
|
||||
this.proxy = {
|
||||
host: host,
|
||||
port: port
|
||||
@ -122,7 +122,7 @@ Peer.prototype.connect = function() {
|
||||
this.socket.on('data', function(data) {
|
||||
self.dataBuffer.push(data);
|
||||
|
||||
if (self.dataBuffer.length > MAX_RECEIVE_BUFFER) {
|
||||
if (self.dataBuffer.length > Peer.MAX_RECEIVE_BUFFER) {
|
||||
// TODO: handle this case better
|
||||
return self.disconnect();
|
||||
}
|
||||
@ -155,14 +155,17 @@ Peer.prototype.disconnect = function() {
|
||||
* @param {Message} message - A message instance
|
||||
*/
|
||||
Peer.prototype.sendMessage = function(message) {
|
||||
this.socket.write(message.serialize(this.network));
|
||||
this.socket.write(message.toBuffer());
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal function that sends VERSION message to the remote peer.
|
||||
*/
|
||||
Peer.prototype._sendVersion = function() {
|
||||
var message = new Messages.Version(null, null, this.relay);
|
||||
// todo: include sending ip address
|
||||
var message = this.messages.buildFromObject('version', {
|
||||
relay: this.relay
|
||||
});
|
||||
this.sendMessage(message);
|
||||
};
|
||||
|
||||
@ -170,7 +173,9 @@ Peer.prototype._sendVersion = function() {
|
||||
* Send a PONG message to the remote peer.
|
||||
*/
|
||||
Peer.prototype._sendPong = function(nonce) {
|
||||
var message = new Messages.Pong(nonce);
|
||||
var message = this.messages.buildFromObject('pong', {
|
||||
nonce: nonce
|
||||
});
|
||||
this.sendMessage(message);
|
||||
};
|
||||
|
||||
@ -178,8 +183,7 @@ Peer.prototype._sendPong = function(nonce) {
|
||||
* Internal function that tries to read a message from the data buffer
|
||||
*/
|
||||
Peer.prototype._readMessage = function() {
|
||||
var message = Messages.parseMessage(this.network, this.dataBuffer);
|
||||
|
||||
var message = this.messages.parseMessage(this.dataBuffer);
|
||||
if (message) {
|
||||
this.emit(message.command, message);
|
||||
this._readMessage();
|
||||
@ -199,4 +203,20 @@ Peer.prototype._getSocket = function() {
|
||||
return new Net.Socket();
|
||||
};
|
||||
|
||||
// TODO: Remove this PATCH (yemel)
|
||||
Buffers.prototype.skip = function(i) {
|
||||
if (i === 0) return;
|
||||
|
||||
if (i === this.length) {
|
||||
this.buffers = [];
|
||||
this.length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var pos = this.pos(i);
|
||||
this.buffers = this.buffers.slice(pos.buf);
|
||||
this.buffers[0] = new Buffer(this.buffers[0].slice(pos.offset));
|
||||
this.length -= i;
|
||||
};
|
||||
|
||||
module.exports = Peer;
|
||||
|
||||
23
lib/pool.js
23
lib/pool.js
@ -2,11 +2,10 @@
|
||||
|
||||
var dns = require('dns');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var Networks = bitcore.Networks;
|
||||
var sha256 = bitcore.crypto.Hash.sha256;
|
||||
var Peer = require('./peer');
|
||||
var Networks = bitcore.Networks;
|
||||
var util = require('util');
|
||||
|
||||
function now() {
|
||||
@ -43,7 +42,6 @@ function Pool(network, options) {
|
||||
var self = this;
|
||||
|
||||
options = options || {};
|
||||
this.network = Networks.get(network) || Networks.defaultNetwork;
|
||||
this.keepalive = false;
|
||||
|
||||
this._connectedPeers = {};
|
||||
@ -51,8 +49,10 @@ function Pool(network, options) {
|
||||
|
||||
this.listenAddr = options.listenAddr !== false;
|
||||
this.dnsSeed = options.dnsSeed !== false;
|
||||
this.relay = options.relay !== false;
|
||||
this.maxSize = options.maxSize || Pool.MaxConnectedPeers;
|
||||
this.messages = options.messages;
|
||||
this.network = Networks.get(network) || Networks.defaultNetwork;
|
||||
this.relay = options.relay === false ? false : true;
|
||||
|
||||
if (options.addrs) {
|
||||
for(var i = 0; i < options.addrs.length; i++) {
|
||||
@ -186,7 +186,12 @@ 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, self.relay);
|
||||
var peer = new Peer({
|
||||
ip: ip,
|
||||
port: port,
|
||||
messages: self.messages,
|
||||
relay: self.relay
|
||||
});
|
||||
peer.on('disconnect', function peerDisconnect() {
|
||||
self.emit('peerdisconnect', peer, addr);
|
||||
});
|
||||
@ -298,4 +303,12 @@ Pool.prototype.inspect = function inspect() {
|
||||
this._addrs.length + '>';
|
||||
};
|
||||
|
||||
Pool.prototype.sendMessage = function(message) {
|
||||
// broadcast to peers
|
||||
for(var key in this._connectedPeers) {
|
||||
var peer = this._connectedPeers[key];
|
||||
peer.sendMessage(message);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Pool;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var chai = require('chai');
|
||||
var should = chai.should();
|
||||
|
||||
var assert = require('assert');
|
||||
var bitcore = require('bitcore');
|
||||
@ -8,6 +9,10 @@ var Data = require('./data/messages');
|
||||
var P2P = require('../');
|
||||
var BloomFilter = P2P.BloomFilter;
|
||||
|
||||
function getPayloadBuffer(messageBuffer) {
|
||||
return new Buffer(messageBuffer.slice(48), 'hex');
|
||||
}
|
||||
|
||||
// convert a hex string to a bytes buffer
|
||||
function ParseHex(str) {
|
||||
var result = [];
|
||||
@ -22,9 +27,9 @@ function ParseHex(str) {
|
||||
describe('BloomFilter', function() {
|
||||
|
||||
it('BloomFilter#fromBuffer and toBuffer methods work', function() {
|
||||
var testPayload = Data.FILTERLOAD.payload;
|
||||
var filter = new BloomFilter.fromBuffer(new Buffer(testPayload, 'hex'));
|
||||
filter.toBuffer().toString('hex').should.equal(testPayload);
|
||||
var testPayloadBuffer = getPayloadBuffer(Data.filterload.message);
|
||||
var filter = new BloomFilter.fromBuffer(testPayloadBuffer);
|
||||
filter.toBuffer().should.deep.equal(testPayloadBuffer);
|
||||
});
|
||||
|
||||
// test data from: https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp
|
||||
|
||||
79
test/commands.js
Normal file
79
test/commands.js
Normal file
@ -0,0 +1,79 @@
|
||||
'use strict';
|
||||
|
||||
var should = require('chai').should();
|
||||
var P2P = require('../');
|
||||
var Commands = P2P.Commands;
|
||||
var commandData = require('./data/messages.json');
|
||||
var Data = require('./data/messages');//todo merge with commandData
|
||||
var bitcore = require('bitcore');
|
||||
|
||||
function getPayloadBuffer(messageBuffer) {
|
||||
return new Buffer(messageBuffer.slice(48), 'hex');
|
||||
}
|
||||
|
||||
describe('P2P Command Builder', function() {
|
||||
|
||||
describe('@constructor', function() {
|
||||
|
||||
it('should return commands based on default', function() {
|
||||
// instantiate
|
||||
var commands = new Commands();
|
||||
should.exist(commands);
|
||||
});
|
||||
|
||||
it('should return commands with customizations', function() {
|
||||
// instantiate
|
||||
var commands = new Commands({
|
||||
magicNumber: 0xd9b4bef9,
|
||||
Block: bitcore.Block,
|
||||
Transaction: bitcore.Transaction
|
||||
});
|
||||
should.exist(commands);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Commands', function() {
|
||||
|
||||
var commands = new Commands();
|
||||
|
||||
describe('#fromBuffer/#toBuffer round trip for all commands', function() {
|
||||
Object.keys(commands).forEach(function(command) {
|
||||
|
||||
it('should round trip buffers for command: ' + command, function(done) {
|
||||
var payloadBuffer = getPayloadBuffer(commandData[command].message);
|
||||
should.exist(commands[command]);
|
||||
var message = commands[command].fromBuffer(payloadBuffer);
|
||||
var outputBuffer = message.getPayload();
|
||||
outputBuffer.toString('hex').should.equal(payloadBuffer.toString('hex'));
|
||||
outputBuffer.should.deep.equal(payloadBuffer);
|
||||
var expectedBuffer = new Buffer(commandData[command].message, 'hex');
|
||||
message.toBuffer().should.deep.equal(expectedBuffer);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('version', function() {
|
||||
it('#fromBuffer works w/o fRelay arg', function() {
|
||||
var payloadBuffer = getPayloadBuffer(Data.version.messagenofrelay);
|
||||
var message = commands.version.fromBuffer(payloadBuffer);
|
||||
message.relay.should.equal(true);
|
||||
});
|
||||
|
||||
it('#relay setting works', function() {
|
||||
[true,false].forEach(function(relay) {
|
||||
var message = commands.version.fromObject({relay: relay});
|
||||
message.relay.should.equal(relay);
|
||||
var messageBuf = message.getPayload();
|
||||
var newMessage = commands.version.fromBuffer(messageBuf);
|
||||
newMessage.relay.should.equal(relay);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
96
test/inventory.js
Normal file
96
test/inventory.js
Normal file
@ -0,0 +1,96 @@
|
||||
'use strict';
|
||||
|
||||
/*jshint immed: false */
|
||||
|
||||
var should = require('chai').should();
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var P2P = require('../');
|
||||
var Inventory = P2P.Inventory;
|
||||
var BufferUtils = bitcore.util.buffer;
|
||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||
|
||||
describe('Inventory', function() {
|
||||
|
||||
var hash = new Buffer('eb951630aba498b9a0d10f72b5ea9e39d5ff04b03dc2231e662f52057f948aa1', 'hex');
|
||||
var hashedStr = BufferUtils.reverse(new Buffer(hash, 'hex')).toString('hex');
|
||||
var inventoryBuffer = new Buffer(
|
||||
'01000000eb951630aba498b9a0d10f72b5ea9e39d5ff04b03dc2231e662f52057f948aa1',
|
||||
'hex'
|
||||
);
|
||||
|
||||
describe('@constructor', function() {
|
||||
it('should create inventory', function() {
|
||||
var inventory = new Inventory({type: Inventory.TYPE.TX, hash: hash});
|
||||
should.exist(inventory);
|
||||
});
|
||||
|
||||
it('should error with string hash', function() {
|
||||
(function() {
|
||||
var inventory = new Inventory({type: Inventory.TYPE.TX, hash: hashedStr});
|
||||
should.not.exist(inventory);
|
||||
}).should.throw('Unexpected hash');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#forItem', function() {
|
||||
it('should handle a string hash (reversed)', function() {
|
||||
var inventory = Inventory.forItem(Inventory.TYPE.TX, hashedStr);
|
||||
should.exist(inventory);
|
||||
inventory.hash.should.deep.equal(new Buffer(hash, 'hex'));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#forBlock', function() {
|
||||
it('should use correct block type', function() {
|
||||
var inventory = Inventory.forBlock(hash);
|
||||
should.exist(inventory);
|
||||
inventory.type.should.equal(Inventory.TYPE.BLOCK);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#forFilteredBlock', function() {
|
||||
it('should use correct filtered block type', function() {
|
||||
var inventory = Inventory.forFilteredBlock(hash);
|
||||
should.exist(inventory);
|
||||
inventory.type.should.equal(Inventory.TYPE.FILTERED_BLOCK);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#forTransaction', function() {
|
||||
it('should use correct filtered tx type', function() {
|
||||
var inventory = Inventory.forTransaction(hash);
|
||||
should.exist(inventory);
|
||||
inventory.type.should.equal(Inventory.TYPE.TX);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#toBuffer', function() {
|
||||
it('should serialize correctly', function() {
|
||||
var inventory = Inventory.forTransaction(hash);
|
||||
var buffer = inventory.toBuffer();
|
||||
buffer.should.deep.equal(inventoryBuffer);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#toBufferWriter', function() {
|
||||
it('should write to a buffer writer', function() {
|
||||
var bw = new BufferWriter();
|
||||
var inventory = Inventory.forTransaction(hash);
|
||||
inventory.toBufferWriter(bw);
|
||||
bw.concat().should.deep.equal(inventoryBuffer);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#fromBuffer', function() {
|
||||
it('should deserialize a buffer', function() {
|
||||
var inventory = Inventory.fromBuffer(inventoryBuffer);
|
||||
should.exist(inventory);
|
||||
inventory.type.should.equal(Inventory.TYPE.TX);
|
||||
inventory.hash.should.deep.equal(hash);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
29
test/message.js
Normal file
29
test/message.js
Normal file
@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
var should = require('chai').should();
|
||||
var P2P = require('../');
|
||||
var Message = P2P.Message;
|
||||
|
||||
describe('P2P Message', function() {
|
||||
|
||||
describe('@constructor', function() {
|
||||
it('should construct with magic number and command', function() {
|
||||
var message = new Message({magicNumber: 0xd9b4bef9, command: 'command'});
|
||||
message.command.should.equal('command');
|
||||
message.magicNumber.should.equal(0xd9b4bef9);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#toBuffer', function() {
|
||||
it('should serialize to a buffer', function() {
|
||||
var message = new Message({magicNumber: 0xd9b4bef9, command: 'command'});
|
||||
message.getPayload = function() {
|
||||
return new Buffer(0);
|
||||
};
|
||||
var buffer = message.toBuffer();
|
||||
var expectedBuffer = new Buffer('f9beb4d9636f6d6d616e640000000000000000005df6e0e2', 'hex');
|
||||
buffer.should.deep.equal(expectedBuffer);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
179
test/messages.js
179
test/messages.js
@ -1,160 +1,79 @@
|
||||
'use strict';
|
||||
|
||||
var chai = require('chai');
|
||||
|
||||
var should = chai.should();
|
||||
|
||||
var Buffers = require('buffers');
|
||||
var bitcore = require('bitcore');
|
||||
var Data = require('./data/messages');
|
||||
var P2P = require('../');
|
||||
var BloomFilter = P2P.BloomFilter;
|
||||
var messages = P2P.messages;
|
||||
var Messages = P2P.Messages;
|
||||
var Networks = bitcore.Networks;
|
||||
var BufferUtils = bitcore.util.buffer;
|
||||
|
||||
var network = Networks.livenet;
|
||||
var bitcore = require('bitcore');
|
||||
|
||||
describe('Messages', function() {
|
||||
|
||||
var commands = {
|
||||
Version: 'version',
|
||||
VerAck: 'verack',
|
||||
Inventory: 'inv',
|
||||
Addresses: 'addr',
|
||||
Ping: 'ping',
|
||||
Pong: 'pong',
|
||||
Alert: 'alert',
|
||||
Reject: 'reject',
|
||||
Block: 'block',
|
||||
MerkleBlock: 'merkleblock',
|
||||
FilterLoad: 'filterload',
|
||||
FilterAdd: 'filteradd',
|
||||
FilterClear: 'filterclear',
|
||||
GetBlocks: 'getblocks',
|
||||
GetHeaders: 'getheaders',
|
||||
GetData: 'getdata',
|
||||
GetAddresses: 'getaddr',
|
||||
Headers: 'headers',
|
||||
Transaction: 'tx',
|
||||
NotFound: 'notfound'
|
||||
};
|
||||
// TODO: add data for these
|
||||
var noPayload = ['Reject', 'GetBlocks', 'GetHeaders'];
|
||||
var names = Object.keys(commands);
|
||||
describe('named', function() {
|
||||
names.forEach(function(name) {
|
||||
var command = commands[name];
|
||||
var data = Data[command.toUpperCase()];
|
||||
|
||||
it('should have data for ' + name, function() {
|
||||
should.exist(data);
|
||||
});
|
||||
|
||||
it('command for name ' + name, function() {
|
||||
Messages.Message.COMMANDS[command].should.equal(Messages[name]);
|
||||
});
|
||||
|
||||
describe(name, function() {
|
||||
var message = new Messages[name]();
|
||||
it('should be able to create instance', function() {
|
||||
message.command.should.equal(command);
|
||||
});
|
||||
|
||||
it('should be able to serialize the payload', function() {
|
||||
var payload = message.getPayload();
|
||||
should.exist(payload);
|
||||
});
|
||||
|
||||
it('should be able to serialize the message', function() {
|
||||
var buffer = message.serialize(Networks.livenet);
|
||||
should.exist(buffer);
|
||||
});
|
||||
|
||||
if (noPayload.indexOf(name) === -1) {
|
||||
it('should be able to parse payload', function() {
|
||||
var payload = new Buffer(data.payload, 'hex');
|
||||
var m = new Messages[name]().fromBuffer(payload);
|
||||
should.exist(m);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
var buildMessage = function(hex) {
|
||||
var m = Buffers();
|
||||
m.push(new Buffer(hex, 'hex'));
|
||||
return m;
|
||||
};
|
||||
it('fails with invalid command', function() {
|
||||
var invalidCommand = 'f9beb4d96d616c6963696f757300000025000000bd5e830c' +
|
||||
'0102000000ec3995c1bf7269ff728818a65e53af00cbbee6b6eca8ac9ce7bc79d87' +
|
||||
'7041ed8';
|
||||
var fails = function() {
|
||||
Messages.parseMessage(network, buildMessage(invalidCommand));
|
||||
};
|
||||
fails.should.throw('Unsupported message command: malicious');
|
||||
});
|
||||
|
||||
it('ignores malformed messages', function() {
|
||||
var malformed1 = 'd8c4c3d976657273696f6e000000000065000000fc970f1772110' +
|
||||
'1000100000000000000ba6288540000000001000000000000000000000000000000' +
|
||||
'0000ffffba8886dceab0010000000000000000000000000000000000ffff0509552' +
|
||||
'2208de7e1c1ef80a1cea70f2f5361746f7368693a302e392e312fa317050001';
|
||||
var malformed2 = 'f9beb4d967657464617461000000000089000000d88134740102' +
|
||||
'0000006308e4a380c949dbad182747b0f7b6a89e874328ca41f37287f74a81b8f84' +
|
||||
'86d';
|
||||
var malformed3 = 'f9beb4d967657464617461000000000025000000616263640102' +
|
||||
'00000069ebcbc34a4f9890da9aea0f773beba883a9afb1ab9ad7647dd4a1cd346c3' +
|
||||
'728';
|
||||
[malformed1, malformed2, malformed3].forEach(function(malformed) {
|
||||
var ret = Messages.parseMessage(network, buildMessage(malformed));
|
||||
should.not.exist(ret);
|
||||
describe('@constructor', function() {
|
||||
it('sets properties correctly', function() {
|
||||
var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0);
|
||||
var messages = new Messages({
|
||||
magicNumber: magicNumber,
|
||||
Block: bitcore.Block,
|
||||
Transaction: bitcore.Transaction
|
||||
});
|
||||
should.exist(messages.commands);
|
||||
messages.magicNumber.should.equal(magicNumber);
|
||||
|
||||
// check that commands are mapped as messages
|
||||
for(var key in messages.commands) {
|
||||
messages[key].should.equal(messages.commands[key]);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
it('Inventory#from family methods work', function() {
|
||||
var hash = 'eb951630aba498b9a0d10f72b5ea9e39d5ff04b03dc2231e662f52057f948aa1';
|
||||
[Messages.Inventory, Messages.GetData, Messages.NotFound].forEach(function(clazz) {
|
||||
var b = clazz.forBlock(hash);
|
||||
var mb = clazz.forMerkleBlock(hash);
|
||||
(b instanceof clazz).should.equal(true);
|
||||
var t = clazz.forTransaction(hash);
|
||||
(t instanceof clazz).should.equal(true);
|
||||
clazz.forBlock(BufferUtils.reverse(new Buffer(hash, 'hex'))).should.deep.equal(b);
|
||||
clazz.forMerkleBlock(BufferUtils.reverse(new Buffer(hash, 'hex'))).should.deep.equal(mb);
|
||||
clazz.forFilteredBlock(BufferUtils.reverse(new Buffer(hash, 'hex'))).should.deep.equal(mb);
|
||||
clazz.forTransaction(BufferUtils.reverse(new Buffer(hash, 'hex'))).should.deep.equal(t);
|
||||
describe('#parseMessage', function() {
|
||||
it('fails with invalid command', function() {
|
||||
var invalidCommand = 'f9beb4d96d616c6963696f757300000025000000bd5e830c' +
|
||||
'0102000000ec3995c1bf7269ff728818a65e53af00cbbee6b6eca8ac9ce7bc79d87' +
|
||||
'7041ed8';
|
||||
var fails = function() {
|
||||
messages.parseMessage(buildMessage(invalidCommand));
|
||||
};
|
||||
fails.should.throw('Unsupported message command: malicious');
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
it('ignores malformed messages', function() {
|
||||
var malformed1 = 'd8c4c3d976657273696f6e000000000065000000fc970f1772110' +
|
||||
'1000100000000000000ba6288540000000001000000000000000000000000000000' +
|
||||
'0000ffffba8886dceab0010000000000000000000000000000000000ffff0509552' +
|
||||
'2208de7e1c1ef80a1cea70f2f5361746f7368693a302e392e312fa317050001';
|
||||
var malformed2 = 'f9beb4d967657464617461000000000089000000d88134740102' +
|
||||
'0000006308e4a380c949dbad182747b0f7b6a89e874328ca41f37287f74a81b8f84' +
|
||||
'86d';
|
||||
var malformed3 = 'f9beb4d967657464617461000000000025000000616263640102' +
|
||||
'00000069ebcbc34a4f9890da9aea0f773beba883a9afb1ab9ad7647dd4a1cd346c3' +
|
||||
'728';
|
||||
[malformed1, malformed2, malformed3].forEach(function(malformed) {
|
||||
var ret = messages.parseMessage(buildMessage(malformed));
|
||||
should.not.exist(ret);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('FilterLoad#fromBuffer method works', function() {
|
||||
var testPayload = Data.FILTERLOAD.payload;
|
||||
var msg = new Messages.FilterLoad().fromBuffer(new Buffer(testPayload, 'hex'));
|
||||
msg.getPayload().toString('hex').should.equal(testPayload);
|
||||
describe('#discardUntilNextMessage', function() {
|
||||
});
|
||||
|
||||
it('MerkleBlock#fromBuffer method works', function() {
|
||||
var testPayload = Data.MERKLEBLOCK.payload;
|
||||
var msg = new Messages.MerkleBlock().fromBuffer(new Buffer(testPayload, 'hex'));
|
||||
msg.getPayload().toString('hex').should.equal(testPayload);
|
||||
describe('#buildFromBuffer', function() {
|
||||
});
|
||||
|
||||
describe('#build/#buildFromObject', function() {
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
22
test/peer.js
22
test/peer.js
@ -12,8 +12,8 @@ var fs = require('fs');
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var _ = bitcore.deps._;
|
||||
var p2p = require('../');
|
||||
var Peer = p2p.Peer;
|
||||
var P2P = require('../');
|
||||
var Peer = P2P.Peer;
|
||||
var Networks = bitcore.Networks;
|
||||
|
||||
describe('Peer', function() {
|
||||
@ -52,7 +52,7 @@ describe('Peer', function() {
|
||||
return stub;
|
||||
};
|
||||
peer.on('connect', function() {
|
||||
dataCallback(fs.readFileSync('./test/connection.log'));
|
||||
dataCallback(fs.readFileSync('./test/data/connection.log'));
|
||||
});
|
||||
var check = function(message) {
|
||||
received[message.command]++;
|
||||
@ -77,28 +77,28 @@ describe('Peer', function() {
|
||||
});
|
||||
|
||||
it('should be able to create instance setting a port', function() {
|
||||
var peer = new Peer('localhost', 8111);
|
||||
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('should be able to create instance setting a network', function() {
|
||||
var peer = new Peer('localhost', Networks.testnet);
|
||||
var peer = new Peer({host: 'localhost', network: Networks.testnet});
|
||||
peer.host.should.equal('localhost');
|
||||
peer.network.should.equal(Networks.testnet);
|
||||
peer.port.should.equal(Networks.testnet.port);
|
||||
});
|
||||
|
||||
it('should be able to create instance setting port and network', function() {
|
||||
var peer = new Peer('localhost', 8111, Networks.testnet);
|
||||
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('should support creating instance without new', function() {
|
||||
var peer = Peer('localhost', 8111, Networks.testnet);
|
||||
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);
|
||||
@ -122,17 +122,17 @@ describe('Peer', function() {
|
||||
});
|
||||
|
||||
it('Peer.relay setting set properly', function() {
|
||||
var peer = new Peer('localhost');
|
||||
var peer = new Peer({host: 'localhost'});
|
||||
peer.relay.should.equal(true);
|
||||
var peer2 = new Peer('localhost', null, null, false);
|
||||
var peer2 = new Peer({host: 'localhost', relay: false});
|
||||
peer2.relay.should.equal(false);
|
||||
var peer3 = new Peer('localhost', null, null, true);
|
||||
var peer3 = new Peer({host: 'localhost', relay: 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 peer = new Peer({host: 'localhost', relay: relay});
|
||||
var peerSendMessageStub = sinon.stub(Peer.prototype, 'sendMessage', function(message) {
|
||||
message.relay.should.equal(relay);
|
||||
});
|
||||
|
||||
14
test/pool.js
14
test/pool.js
@ -10,13 +10,17 @@ var bitcore = require('bitcore');
|
||||
var P2P = require('../');
|
||||
var Peer = P2P.Peer;
|
||||
var MessagesData = require('./data/messages');
|
||||
var Messages = P2P.Messages;
|
||||
var messages = P2P.messages;
|
||||
var Pool = P2P.Pool;
|
||||
var Networks = bitcore.Networks;
|
||||
|
||||
var dns = require('dns');
|
||||
var sinon = require('sinon');
|
||||
|
||||
function getPayloadBuffer(messageBuffer) {
|
||||
return new Buffer(messageBuffer.slice(48), 'hex');
|
||||
}
|
||||
|
||||
describe('Pool', function() {
|
||||
|
||||
it('should be able to create instance', function() {
|
||||
@ -95,8 +99,8 @@ describe('Pool', function() {
|
||||
|
||||
// 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);
|
||||
var payloadBuffer = getPayloadBuffer(MessagesData.addr.message);
|
||||
var message = messages.buildFromBuffer('addr', payloadBuffer);
|
||||
this.emit(message.command, message);
|
||||
});
|
||||
|
||||
@ -145,8 +149,8 @@ describe('Pool', function() {
|
||||
|
||||
// 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);
|
||||
var payloadBuffer = getPayloadBuffer(MessagesData.addr.message);
|
||||
var message = messages.buildFromBuffer('addr', payloadBuffer);
|
||||
this.emit(message.command, message);
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user