Esteban Ordano
10 years ago
11 changed files with 1353 additions and 8 deletions
@ -0,0 +1,92 @@ |
|||||
|
# Peer |
||||
|
|
||||
|
Represents a node from the p2p bitcoin network. The Peer class supports connecting directly to other nodes or through a socks5 proxy like Tor. |
||||
|
|
||||
|
The code to create a new peer looks like this: |
||||
|
|
||||
|
```javascript |
||||
|
var bitcore = require('bitcore'); |
||||
|
var Peer = bitcore.transport.Peer; |
||||
|
|
||||
|
// default port |
||||
|
var livenetPeer = new Peer('5.9.85.34'); |
||||
|
var testnetPeer = new Peer('5.9.85.34', bitcore.testnet); |
||||
|
|
||||
|
// custom port |
||||
|
var livenetPeer = new Peer('5.9.85.34', 8334); |
||||
|
var testnetPeer = new Peer('5.9.85.34', 18334, bitcore.testnet); |
||||
|
|
||||
|
// use sock5 proxy (Tor) |
||||
|
var peer = new Peer('5.9.85.34').setProxy('localhost', 9050); |
||||
|
``` |
||||
|
|
||||
|
A peer instance is always in one of the following states: |
||||
|
|
||||
|
* `disconnected`: No connection with the remote node. |
||||
|
* `connecting`: While establishing the connection. |
||||
|
* `connected`: Exchanging version packages. |
||||
|
* `ready`: Connection ready for sending and receiving messages. |
||||
|
|
||||
|
You can subscribe to the change of those states as follows: |
||||
|
|
||||
|
```javascript |
||||
|
var bitcore = require('bitcore'); |
||||
|
var Peer = bitcore.transport.Peer; |
||||
|
|
||||
|
var peer = new Peer('5.9.85.34'); |
||||
|
|
||||
|
peer.on('ready', function() { |
||||
|
// peer info |
||||
|
console.log(peer.version, peer.subversion, peer.bestHeight); |
||||
|
}); |
||||
|
|
||||
|
peer.on('disconnect', function() { |
||||
|
console.log('connection closed'); |
||||
|
}); |
||||
|
|
||||
|
peer.connect(); |
||||
|
``` |
||||
|
|
||||
|
Once connected, a peer instance can send and receive messages. Every time a message arrives it's emitted as a new event. Let's see an example of this: |
||||
|
|
||||
|
```javascript |
||||
|
var bitcore = require('bitcore'); |
||||
|
var peer = new bitcore.transport.Peer('5.9.85.34'); |
||||
|
|
||||
|
// handle events |
||||
|
peer.on('inv', function(message) { |
||||
|
// message.inventory[] |
||||
|
}); |
||||
|
|
||||
|
peer.on('tx', function(message) { |
||||
|
// message.transaction |
||||
|
}); |
||||
|
|
||||
|
peer.on('addr', function(message) { |
||||
|
// message.addresses[] |
||||
|
}); |
||||
|
|
||||
|
peer.connect(); |
||||
|
``` |
||||
|
|
||||
|
In order to send messages the Peer class offers the `sendMessage(message)` method, which receives an instance of a message. All supported messages can be found on the `bitcore.transport.Messages` module. For more information about messages refer to the [protocol specification](https://en.bitcoin.it/wiki/Protocol_specification). |
||||
|
|
||||
|
An example for requesting other connected nodes to a peers looks like this: |
||||
|
|
||||
|
```javascript |
||||
|
var bitcore = require('bitcore'); |
||||
|
var peer = new bitcore.transport.Peer('5.9.85.34'); |
||||
|
|
||||
|
peer.on('ready', function() { |
||||
|
var message = new bitcore.transport.Messages.GetAddresses(); |
||||
|
peer.sendMessage(message); |
||||
|
}); |
||||
|
|
||||
|
peer.on('addr', function(message) { |
||||
|
message.addresses.forEach(function(address) { |
||||
|
// do something |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
peer.connect(); |
||||
|
``` |
@ -0,0 +1,554 @@ |
|||||
|
'use strict'; |
||||
|
/* jshint curly: false */ |
||||
|
|
||||
|
var Buffers = require('buffers'); |
||||
|
var Put = require('bufferput'); |
||||
|
var util = require('util'); |
||||
|
|
||||
|
var BlockHeaderModel = require('../blockheader'); |
||||
|
var BlockModel = require('../block'); |
||||
|
var BufferReader = require('../encoding/bufferreader'); |
||||
|
var BufferUtil = require('../util/buffer'); |
||||
|
var Hash = require('../crypto/hash'); |
||||
|
var Random = require('../crypto/random'); |
||||
|
var TransactionModel = require('../transaction'); |
||||
|
|
||||
|
var CONNECTION_NONCE = Random.getPseudoRandomBuffer(8); |
||||
|
var PROTOCOL_VERSION = 70000; |
||||
|
|
||||
|
/** |
||||
|
* Static helper for consuming a data buffer until the next message. |
||||
|
* |
||||
|
* @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; |
||||
|
} |
||||
|
|
||||
|
console.log(command, 'FULL MESSAGE', dataBuffer.slice(0, messageLength).toString('hex')); |
||||
|
console.log(command, 'PAYLOAD MESSAGE', payload.toString('hex')); |
||||
|
|
||||
|
dataBuffer.skip(messageLength); |
||||
|
return Message.buildMessage(command, payload); |
||||
|
}; |
||||
|
|
||||
|
module.exports.parseMessage = parseMessage; |
||||
|
|
||||
|
/** |
||||
|
* Internal function that discards data until founds the next message. |
||||
|
*/ |
||||
|
function discardUntilNextMessage(network, dataBuffer) { |
||||
|
var magicNumber = network.networkMagic; |
||||
|
|
||||
|
var i = 0; |
||||
|
for (;;) { |
||||
|
// check if it's the beginning of a new message
|
||||
|
var packageNumber = dataBuffer.slice(0, 4); |
||||
|
if (BufferUtil.equals(packageNumber, magicNumber)) { |
||||
|
dataBuffer.skip(i); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
// did we reach the end of the buffer?
|
||||
|
if (i > (dataBuffer.length - 4)) { |
||||
|
dataBuffer.skip(i); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
i++; // continue scanning
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Abstract Message that knows how to parse and serialize itself. |
||||
|
* Concret subclases should implement {fromBuffer} and {getPayload} methods. |
||||
|
*/ |
||||
|
function Message() {} |
||||
|
|
||||
|
Message.COMMANDS = {}; |
||||
|
|
||||
|
Message.buildMessage = function(command, payload) { |
||||
|
try { |
||||
|
var CommandClass = Message.COMMANDS[command]; |
||||
|
return new CommandClass().fromBuffer(payload); |
||||
|
} catch (err) { |
||||
|
console.log('Error while parsing message', err); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Parse instance state from buffer. |
||||
|
* |
||||
|
* @param{Buffer} payload - the buffer to read from |
||||
|
* @returns{Message} The same message instance |
||||
|
*/ |
||||
|
Message.prototype.fromBuffer = function(payload) { |
||||
|
/* jshint unused: false */ |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Serialize the payload into a buffer. |
||||
|
* |
||||
|
* @returns{Buffer} the serialized payload |
||||
|
*/ |
||||
|
Message.prototype.getPayload = function() { |
||||
|
return BufferUtil.EMPTY_BUFFER; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Serialize the message into a buffer. |
||||
|
* |
||||
|
* @returns{Buffer} the serialized message |
||||
|
*/ |
||||
|
Message.prototype.serialize = function(network) { |
||||
|
var magic = network.networkMagic; |
||||
|
var commandBuf = new Buffer(this.command, 'ascii'); |
||||
|
if (commandBuf.length > 12) throw 'Command name too long'; |
||||
|
|
||||
|
var payload = this.getPayload(); |
||||
|
var checksum = Hash.sha256sha256(payload).slice(0, 4); |
||||
|
|
||||
|
// -- HEADER --
|
||||
|
var message = new Put(); |
||||
|
message.put(magic); |
||||
|
message.put(commandBuf); |
||||
|
message.pad(12 - commandBuf.length); // zero-padded
|
||||
|
message.word32le(payload.length); |
||||
|
message.put(checksum); |
||||
|
|
||||
|
// -- BODY --
|
||||
|
message.put(payload); |
||||
|
|
||||
|
return message.buffer(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Version Message |
||||
|
* |
||||
|
* @param{string} subversion - version of the client |
||||
|
* @param{Buffer} nonce - a random 8 bytes buffer |
||||
|
*/ |
||||
|
function Version(subversion, nonce) { |
||||
|
this.command = 'version'; |
||||
|
this.version = PROTOCOL_VERSION; |
||||
|
this.subversion = subversion || '/BitcoinX:0.1/'; |
||||
|
this.nonce = nonce || CONNECTION_NONCE; |
||||
|
} |
||||
|
util.inherits(Version, Message); |
||||
|
|
||||
|
Version.prototype.fromBuffer = function(payload) { |
||||
|
var parser = new BufferReader(payload); |
||||
|
this.version = parser.readUInt32LE(); |
||||
|
this.services = parser.readUInt64LEBN(); |
||||
|
this.timestamp = parser.readUInt64LEBN(); |
||||
|
this.addr_me = parser.read(26); |
||||
|
this.addr_you = parser.read(26); |
||||
|
this.nonce = parser.read(8); |
||||
|
this.subversion = parser.readVarintBuf().toString(); |
||||
|
this.start_height = parser.readUInt32LE(); |
||||
|
|
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
Version.prototype.getPayload = function() { |
||||
|
var put = new Put(); |
||||
|
put.word32le(this.version); // version
|
||||
|
put.word64le(1); // services
|
||||
|
put.word64le(Math.round(new Date().getTime() / 1000)); // timestamp
|
||||
|
put.pad(26); // addr_me
|
||||
|
put.pad(26); // addr_you
|
||||
|
put.put(this.nonce); |
||||
|
put.varint(this.subversion.length); |
||||
|
put.put(new Buffer(this.subversion, 'ascii')); |
||||
|
put.word32le(0); |
||||
|
|
||||
|
return put.buffer(); |
||||
|
}; |
||||
|
|
||||
|
module.exports.Version = Message.COMMANDS.version = Version; |
||||
|
|
||||
|
/** |
||||
|
* Inv Message |
||||
|
* |
||||
|
* @param{Array} inventory - reported elements |
||||
|
*/ |
||||
|
function Inventory(inventory) { |
||||
|
this.command = 'inv'; |
||||
|
this.inventory = inventory || []; |
||||
|
} |
||||
|
util.inherits(Inventory, Message); |
||||
|
|
||||
|
Inventory.prototype.fromBuffer = function(payload) { |
||||
|
var parser = new BufferReader(payload); |
||||
|
var count = parser.readVarintNum(); |
||||
|
for (var i = 0; i < count; i++) { |
||||
|
this.inventory.push({ |
||||
|
type: parser.readUInt32LE(), |
||||
|
hash: parser.read(32) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
Inventory.prototype.getPayload = function() { |
||||
|
var put = new Put(); |
||||
|
|
||||
|
put.varint(this.inventory.length); |
||||
|
this.inventory.forEach(function(value) { |
||||
|
put.word32le(value.type); |
||||
|
put.put(value.hash); |
||||
|
}); |
||||
|
|
||||
|
return put.buffer(); |
||||
|
}; |
||||
|
|
||||
|
module.exports.Inventory = Message.COMMANDS.inv = Inventory; |
||||
|
|
||||
|
/** |
||||
|
* Getdata Message |
||||
|
* |
||||
|
* @param{Array} inventory - requested elements |
||||
|
*/ |
||||
|
function GetData(inventory) { |
||||
|
this.command = 'getdata'; |
||||
|
this.inventory = inventory || []; |
||||
|
} |
||||
|
|
||||
|
util.inherits(GetData, Inventory); |
||||
|
module.exports.GetData = GetData; |
||||
|
|
||||
|
/** |
||||
|
* Ping Message |
||||
|
* |
||||
|
* @param{Buffer} nonce - a random 8 bytes buffer |
||||
|
*/ |
||||
|
function Ping(nonce) { |
||||
|
this.command = 'ping'; |
||||
|
this.nonce = nonce || CONNECTION_NONCE; |
||||
|
} |
||||
|
util.inherits(Ping, Message); |
||||
|
|
||||
|
Ping.prototype.fromBuffer = function(payload) { |
||||
|
this.nonce = new BufferReader(payload).read(8); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
Ping.prototype.getPayload = function() { |
||||
|
return this.nonce; |
||||
|
}; |
||||
|
|
||||
|
module.exports.Ping = Message.COMMANDS.ping = Ping; |
||||
|
|
||||
|
/** |
||||
|
* Pong Message |
||||
|
* |
||||
|
* @param{Buffer} nonce - a random 8 bytes buffer |
||||
|
*/ |
||||
|
function Pong(nonce) { |
||||
|
this.command = 'pong'; |
||||
|
this.nonce = nonce || CONNECTION_NONCE; |
||||
|
} |
||||
|
|
||||
|
util.inherits(Pong, Ping); |
||||
|
module.exports.Pong = Message.COMMANDS.pong = Pong; |
||||
|
|
||||
|
/** |
||||
|
* Addr Message |
||||
|
* |
||||
|
* @param{Array} addresses - array of know addresses |
||||
|
*/ |
||||
|
function Addresses(addresses) { |
||||
|
this.command = 'addr'; |
||||
|
this.addresses = addresses || []; |
||||
|
} |
||||
|
util.inherits(Addresses, Message); |
||||
|
|
||||
|
Addresses.prototype.fromBuffer = function(payload) { |
||||
|
var parser = new BufferReader(payload); |
||||
|
var addrCount = Math.min(parser.readVarintNum(), 1000); |
||||
|
|
||||
|
this.addresses = []; |
||||
|
for (var i = 0; i < addrCount; i++) { |
||||
|
// TODO: Time actually depends on the version of the other peer (>=31402)
|
||||
|
this.addresses.push({ |
||||
|
time: parser.readUInt32LE(), |
||||
|
services: parser.readUInt64LEBN(), |
||||
|
ip: parser.read(16), |
||||
|
port: parser.readUInt16BE() |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
Addresses.prototype.getPayload = function() { |
||||
|
var put = new Put(); |
||||
|
put.varint(this.addresses.length); |
||||
|
|
||||
|
for (var i = 0; i < this.addresses.length; i++) { |
||||
|
put.word32le(this.addresses[i].time); |
||||
|
put.word64le(this.addresses[i].services); |
||||
|
put.put(this.addresses[i].ip); |
||||
|
put.word16be(this.addresses[i].port); |
||||
|
} |
||||
|
|
||||
|
return put.buffer(); |
||||
|
}; |
||||
|
|
||||
|
module.exports.Addresses = Message.COMMANDS.addr = Addresses; |
||||
|
|
||||
|
/** |
||||
|
* GetAddr Message |
||||
|
* |
||||
|
*/ |
||||
|
function GetAddresses() { |
||||
|
this.command = 'getaddr'; |
||||
|
} |
||||
|
|
||||
|
util.inherits(GetAddresses, Message); |
||||
|
module.exports.GetAddresses = Message.COMMANDS.getaddr = GetAddresses; |
||||
|
|
||||
|
/** |
||||
|
* Verack Message |
||||
|
* |
||||
|
*/ |
||||
|
function VerAck() { |
||||
|
this.command = 'verack'; |
||||
|
} |
||||
|
|
||||
|
util.inherits(VerAck, Message); |
||||
|
module.exports.VerAck = Message.COMMANDS.verack = VerAck; |
||||
|
|
||||
|
/** |
||||
|
* Reject Message |
||||
|
* |
||||
|
*/ |
||||
|
function Reject() { |
||||
|
this.command = 'reject'; |
||||
|
} |
||||
|
util.inherits(Reject, Message); |
||||
|
|
||||
|
// TODO: Parse REJECT message
|
||||
|
|
||||
|
module.exports.Reject = Message.COMMANDS.reject = Reject; |
||||
|
|
||||
|
/** |
||||
|
* Alert Message |
||||
|
* |
||||
|
*/ |
||||
|
function Alert(payload, signature) { |
||||
|
this.command = 'alert'; |
||||
|
this.payload = payload || new Buffer(32); |
||||
|
this.signature = signature || new Buffer(32); |
||||
|
} |
||||
|
util.inherits(Alert, Message); |
||||
|
|
||||
|
Alert.prototype.fromBuffer = function(payload) { |
||||
|
var parser = new BufferReader(payload); |
||||
|
this.payload = parser.readVarintBuf(); // TODO: Use current format
|
||||
|
this.signature = parser.readVarintBuf(); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
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(); |
||||
|
}; |
||||
|
|
||||
|
module.exports.Alert = Message.COMMANDS.alert = Alert; |
||||
|
|
||||
|
/** |
||||
|
* Headers Message |
||||
|
* |
||||
|
* @param{Array} blockheaders - array of block headers |
||||
|
*/ |
||||
|
function Headers(blockheaders) { |
||||
|
this.command = 'headers'; |
||||
|
this.headers = blockheaders || []; |
||||
|
} |
||||
|
util.inherits(Headers, Message); |
||||
|
|
||||
|
Headers.prototype.fromBuffer = function(payload) { |
||||
|
var parser = new BufferReader(payload); |
||||
|
var count = parser.readVarintNum(); |
||||
|
|
||||
|
this.headers = []; |
||||
|
for (var i = 0; i < count; i++) { |
||||
|
var header = BlockHeaderModel._fromBufferReader(parser); |
||||
|
this.headers.push(header); |
||||
|
} |
||||
|
|
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
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); |
||||
|
} |
||||
|
|
||||
|
return put.buffer(); |
||||
|
}; |
||||
|
|
||||
|
module.exports.Headers = Message.COMMANDS.headers = Headers; |
||||
|
|
||||
|
/** |
||||
|
* Block Message |
||||
|
* |
||||
|
* @param{Block} block |
||||
|
*/ |
||||
|
function Block(block) { |
||||
|
this.command = 'block'; |
||||
|
this.block = block; |
||||
|
} |
||||
|
util.inherits(Block, Message); |
||||
|
|
||||
|
Block.prototype.fromBuffer = function(payload) { |
||||
|
this.block = BlockModel(payload); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
Block.prototype.getPayload = function() { |
||||
|
return this.block.toBuffer(); |
||||
|
}; |
||||
|
|
||||
|
module.exports.Block = Message.COMMANDS.block = Block; |
||||
|
|
||||
|
/** |
||||
|
* Tx Message |
||||
|
* |
||||
|
* @param{Transaction} transaction |
||||
|
*/ |
||||
|
function Transaction(transaction) { |
||||
|
this.command = 'tx'; |
||||
|
this.transaction = transaction; |
||||
|
} |
||||
|
util.inherits(Transaction, Message); |
||||
|
|
||||
|
Transaction.prototype.fromBuffer = function(payload) { |
||||
|
this.transaction = TransactionModel(payload); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
Transaction.prototype.getPayload = function() { |
||||
|
return this.transaction.toBuffer(); |
||||
|
}; |
||||
|
|
||||
|
module.exports.Transaction = Message.COMMANDS.tx = Transaction; |
||||
|
|
||||
|
/** |
||||
|
* Getblocks Message |
||||
|
* |
||||
|
* @param{Array} starts - array of buffers with the starting block hashes |
||||
|
* @param{Buffer} [stop] - hash of the last block |
||||
|
*/ |
||||
|
function GetBlocks(starts, stop) { |
||||
|
this.command = 'getblocks'; |
||||
|
this.version = PROTOCOL_VERSION; |
||||
|
this.starts = starts || []; |
||||
|
this.stop = stop || BufferUtil.NULL_HASH; |
||||
|
} |
||||
|
util.inherits(GetBlocks, Message); |
||||
|
|
||||
|
GetBlocks.prototype.fromBuffer = function(payload) { |
||||
|
var parser = new BufferReader(payload); |
||||
|
this.version = parser.readUInt32LE(); |
||||
|
|
||||
|
var startCount = Math.min(parser.readVarintNum(), 500); |
||||
|
this.starts = []; |
||||
|
for (var i = 0; i < startCount; i++) { |
||||
|
this.starts.push(parser.read(32)); |
||||
|
} |
||||
|
this.stop = parser.read(32); |
||||
|
|
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
GetBlocks.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++) { |
||||
|
if (this.starts[i].length !== 32) { |
||||
|
throw new Error('Invalid hash length'); |
||||
|
} |
||||
|
put.put(this.starts[i]); |
||||
|
} |
||||
|
|
||||
|
if (this.stop.length !== 32) { |
||||
|
throw new Error('Invalid hash length'); |
||||
|
} |
||||
|
put.put(this.stop); |
||||
|
|
||||
|
return put.buffer(); |
||||
|
}; |
||||
|
|
||||
|
module.exports.GetBlocks = Message.COMMANDS.getblocks = GetBlocks; |
||||
|
|
||||
|
/** |
||||
|
* Getheaders Message |
||||
|
* |
||||
|
* @param{Array} starts - array of buffers with the starting block hashes |
||||
|
* @param{Buffer} [stop] - hash of the last block |
||||
|
*/ |
||||
|
function GetHeaders(starts, stop) { |
||||
|
this.command = 'getheaders'; |
||||
|
this.version = PROTOCOL_VERSION; |
||||
|
this.starts = starts || []; |
||||
|
this.stop = stop || BufferUtil.NULL_HASH; |
||||
|
} |
||||
|
|
||||
|
util.inherits(GetHeaders, GetBlocks); |
||||
|
module.exports.GetHeaders = Message.COMMANDS.getheaders = GetHeaders; |
||||
|
|
||||
|
|
||||
|
// 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; |
||||
|
}; |
@ -0,0 +1,192 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
var Buffers = require('buffers'); |
||||
|
var EventEmitter = require('events').EventEmitter; |
||||
|
var Net = require('net'); |
||||
|
var Socks5Client = require('socks5-client'); |
||||
|
var util = require('util'); |
||||
|
|
||||
|
var Networks = require('../networks'); |
||||
|
var Messages = require('./messages'); |
||||
|
|
||||
|
var MAX_RECEIVE_BUFFER = 10000000; |
||||
|
|
||||
|
/** |
||||
|
* A Peer instance represents a remote bitcoin node and allows to communicate |
||||
|
* with it using the standar messages of the bitcoin p2p protocol. |
||||
|
* |
||||
|
* @example |
||||
|
* |
||||
|
* var peer = new Peer('127.0.0.1').setProxy('127.0.0.1', 9050); |
||||
|
* peer.on('tx', function(tx) { |
||||
|
* console.log('New transaction: ', tx.id); |
||||
|
* }); |
||||
|
* peer.connect(); |
||||
|
* |
||||
|
* @param {String} host - IP address of the remote host |
||||
|
* @param {Number} [port] - Port number of the remote host |
||||
|
* @param {Network} [network] - The context for this communication |
||||
|
* @returns {Peer} A new instance of Peer. |
||||
|
* @constructor |
||||
|
*/ |
||||
|
function Peer(host, port, network) { |
||||
|
if (!(this instanceof Peer)) { |
||||
|
return new Peer(host, port, network); |
||||
|
} |
||||
|
|
||||
|
// overloading stuff
|
||||
|
if (port instanceof Object && !network) { |
||||
|
network = port; |
||||
|
port = undefined; |
||||
|
} |
||||
|
|
||||
|
this.host = host; |
||||
|
this.status = Peer.STATUS.DISCONNECTED; |
||||
|
this.network = network || Networks.livenet; |
||||
|
this.port = port || this.network.port; |
||||
|
|
||||
|
this.dataBuffer = new Buffers(); |
||||
|
|
||||
|
this.version = 0; |
||||
|
this.bestHeight = 0; |
||||
|
this.subversion = null; |
||||
|
|
||||
|
// set message handlers
|
||||
|
var self = this; |
||||
|
this.on('verack', function() { |
||||
|
self.status = Peer.STATUS.READY; |
||||
|
self.emit('ready'); |
||||
|
}); |
||||
|
|
||||
|
this.on('version', function(message) { |
||||
|
self.version = message.version; |
||||
|
self.subversion = message.subversion; |
||||
|
self.bestHeight = message.start_height |
||||
|
}); |
||||
|
|
||||
|
this.on('ping', function(message) { |
||||
|
self.sendPong(message.nonce); |
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
util.inherits(Peer, EventEmitter); |
||||
|
|
||||
|
Peer.STATUS = { |
||||
|
DISCONNECTED: 'disconnected', |
||||
|
CONNECTING: 'connecting', |
||||
|
CONNECTED: 'connected', |
||||
|
READY: 'ready' |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Set a socks5 proxy for the connection. Enables the use of the TOR network. |
||||
|
* |
||||
|
* @param {String} host - IP address of the proxy |
||||
|
* @param {Number} port - Port number of the proxy |
||||
|
* @returns {Peer} The same Peer instance. |
||||
|
*/ |
||||
|
Peer.prototype.setProxy = function(host, port) { |
||||
|
if (this.status != Peer.STATUS.DISCONNECTED) { |
||||
|
throw Error('Invalid State'); |
||||
|
} |
||||
|
|
||||
|
this.proxy = { |
||||
|
host: host, |
||||
|
port: port |
||||
|
}; |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Init the connection with the remote peer. |
||||
|
* |
||||
|
* @returns {Socket} The same peer instance. |
||||
|
*/ |
||||
|
Peer.prototype.connect = function() { |
||||
|
this.socket = this._getSocket(); |
||||
|
this.status = Peer.STATUS.CONNECTING; |
||||
|
|
||||
|
var self = this; |
||||
|
this.socket.on('connect', function(ev) { |
||||
|
self.status = Peer.STATUS.CONNECTED; |
||||
|
self.emit('connect'); |
||||
|
self._sendVersion(); |
||||
|
}); |
||||
|
|
||||
|
this.socket.on('error', self.disconnect.bind(this)); |
||||
|
this.socket.on('end', self.disconnect.bind(this)); |
||||
|
|
||||
|
this.socket.on('data', function(data) { |
||||
|
self.dataBuffer.push(data); |
||||
|
|
||||
|
if (self.dataBuffer.length > MAX_RECEIVE_BUFFER) return self.disconnect(); |
||||
|
self._readMessage(); |
||||
|
}); |
||||
|
|
||||
|
this.socket.connect(this.port, this.host); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Disconnects the remote connection. |
||||
|
* |
||||
|
* @returns {Socket} The same peer instance. |
||||
|
*/ |
||||
|
Peer.prototype.disconnect = function() { |
||||
|
this.status = Peer.STATUS.DISCONNECTED; |
||||
|
this.socket.destroy(); |
||||
|
this.emit('disconnect'); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Send a Message to the remote peer. |
||||
|
* |
||||
|
* @param {Message} message - A message instance |
||||
|
*/ |
||||
|
Peer.prototype.sendMessage = function(message) { |
||||
|
this.socket.write(message.serialize(this.network)); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Internal function that sends VERSION message to the remote peer. |
||||
|
*/ |
||||
|
Peer.prototype._sendVersion = function() { |
||||
|
var message = new Messages.Version(); |
||||
|
this.sendMessage(message); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Send a PONG message to the remote peer. |
||||
|
*/ |
||||
|
Peer.prototype._sendPong = function(nonce) { |
||||
|
var message = new Messages.Pong(nonce); |
||||
|
this.sendMessage(message); |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Internal function that tries to read a message from the data buffer |
||||
|
*/ |
||||
|
Peer.prototype._readMessage = function() { |
||||
|
var message = Messages.parseMessage(this.network, this.dataBuffer); |
||||
|
|
||||
|
if (message) { |
||||
|
this.emit(message.command, message); |
||||
|
this._readMessage(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Internal function that creates a socket using a proxy if neccesary. |
||||
|
* |
||||
|
* @returns {Socket} A Socket instance not yet connected. |
||||
|
*/ |
||||
|
Peer.prototype._getSocket = function() { |
||||
|
if (this.proxy) { |
||||
|
return new Socks5Client(this.proxy.host, this.proxy.port); |
||||
|
} |
||||
|
|
||||
|
return new Net.Socket(); |
||||
|
}; |
||||
|
|
||||
|
module.exports = Peer; |
File diff suppressed because one or more lines are too long
@ -0,0 +1,353 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
var chai = require('chai'); |
||||
|
|
||||
|
var should = chai.should(); |
||||
|
|
||||
|
var bitcore = require('../..'); |
||||
|
var Data = require('../data/messages'); |
||||
|
var Messages = bitcore.transport.Messages; |
||||
|
var Networks = bitcore.Networks; |
||||
|
|
||||
|
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); |
||||
|
message.subversion.should.equal('/BitcoinX:0.1/'); |
||||
|
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'); |
||||
|
new Messages.Version().fromBuffer(payload); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('VerAck', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.VerAck(); |
||||
|
message.command.should.equal('verack'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.VerAck(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.VerAck(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to parse payload', function() { |
||||
|
var payload = new Buffer(Data.VERACK.payload, 'hex'); |
||||
|
new Messages.VerAck().fromBuffer(payload); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('Inventory', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.Inventory(); |
||||
|
message.command.should.equal('inv'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.Inventory(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.Inventory(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to parse payload', function() { |
||||
|
var payload = new Buffer(Data.INV.payload, 'hex'); |
||||
|
new Messages.Inventory().fromBuffer(payload); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('Addresses', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.Addresses(); |
||||
|
message.command.should.equal('addr'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.Addresses(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.Addresses(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to parse payload', function() { |
||||
|
var payload = new Buffer(Data.ADDR.payload, 'hex'); |
||||
|
new Messages.Addresses().fromBuffer(payload); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('Ping', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.Ping(); |
||||
|
message.command.should.equal('ping'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.Ping(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.Ping(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to parse payload', function() { |
||||
|
var payload = new Buffer(Data.PING.payload, 'hex'); |
||||
|
new Messages.Ping().fromBuffer(payload); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('Pong', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.Pong(); |
||||
|
message.command.should.equal('pong'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.Pong(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.Pong(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to parse payload', function() { |
||||
|
var payload = new Buffer(Data.PING.payload, 'hex'); |
||||
|
new Messages.Pong().fromBuffer(payload); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('Alert', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.Alert(); |
||||
|
message.command.should.equal('alert'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.Alert(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.Alert(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('Reject', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.Reject(); |
||||
|
message.command.should.equal('reject'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.Reject(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.Reject(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('Block', function() { |
||||
|
var blockHex = 'f9beb4d91d0100000100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; |
||||
|
var block = new bitcore.Block(new Buffer(blockHex, 'hex')); |
||||
|
|
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.Block(block); |
||||
|
message.command.should.equal('block'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.Block(block); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.Block(block); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('GetBlocks', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.GetBlocks(); |
||||
|
message.command.should.equal('getblocks'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.GetBlocks(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.GetBlocks(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('GetHeaders', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.GetHeaders(); |
||||
|
message.command.should.equal('getheaders'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.GetHeaders(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.GetHeaders(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('GetData', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.GetData(); |
||||
|
message.command.should.equal('getdata'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.GetData(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.GetData(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('GetData', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.GetData(); |
||||
|
message.command.should.equal('getdata'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.GetData(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.GetData(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('GetAddresses', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.GetAddresses(); |
||||
|
message.command.should.equal('getaddr'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.GetAddresses(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.GetAddresses(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('Headers', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.Headers(); |
||||
|
message.command.should.equal('headers'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.Headers(); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.Headers(); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
describe('Transaction', function() { |
||||
|
it('should be able to create instance', function() { |
||||
|
var message = new Messages.Transaction(new bitcore.Transaction()); |
||||
|
message.command.should.equal('tx'); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the payload', function() { |
||||
|
var message = new Messages.Transaction(new bitcore.Transaction()); |
||||
|
var payload = message.getPayload(); |
||||
|
should.exist(payload); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to serialize the message', function() { |
||||
|
var message = new Messages.Transaction(new bitcore.Transaction()); |
||||
|
var buffer = message.serialize(Networks.livenet); |
||||
|
should.exist(buffer); |
||||
|
}); |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,69 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
var chai = require('chai'); |
||||
|
var Net = require('net'); |
||||
|
var Socks5Client = require('socks5-client'); |
||||
|
|
||||
|
/* jshint unused: false */ |
||||
|
var should = chai.should(); |
||||
|
var expect = chai.expect; |
||||
|
|
||||
|
var bitcore = require('../..'); |
||||
|
var Peer = bitcore.transport.Peer; |
||||
|
var Networks = bitcore.Networks; |
||||
|
|
||||
|
describe('Peer', function() { |
||||
|
|
||||
|
it('should be able to create instance', function() { |
||||
|
var peer = new Peer('localhost'); |
||||
|
peer.host.should.equal('localhost'); |
||||
|
peer.network.should.equal(Networks.livenet); |
||||
|
peer.port.should.equal(Networks.livenet.port); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to create instance setting a port', function() { |
||||
|
var peer = new Peer('localhost', 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); |
||||
|
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); |
||||
|
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); |
||||
|
peer.host.should.equal('localhost'); |
||||
|
peer.network.should.equal(Networks.testnet); |
||||
|
peer.port.should.equal(8111); |
||||
|
}); |
||||
|
|
||||
|
// only for node TODO: (yemel)
|
||||
|
it.skip('should be able to set a proxy', function() { |
||||
|
var peer, peer2, socket; |
||||
|
|
||||
|
peer = new Peer('localhost'); |
||||
|
expect(peer.proxy).to.be.undefined(); |
||||
|
socket = peer._getSocket(); |
||||
|
socket.should.be.instanceof(Net.Socket); |
||||
|
|
||||
|
peer2 = peer.setProxy('127.0.0.1', 9050); |
||||
|
peer2.proxy.host.should.equal('127.0.0.1'); |
||||
|
peer2.proxy.port.should.equal(9050); |
||||
|
socket = peer2._getSocket(); |
||||
|
socket.should.be.instanceof(Socks5Client); |
||||
|
|
||||
|
peer.should.equal(peer2); |
||||
|
}); |
||||
|
}); |
Loading…
Reference in new issue