183 lines
4.0 KiB
JavaScript
183 lines
4.0 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
var Put = require('bufferput');
|
||
|
|
||
|
var Random = require('../crypto/random');
|
||
|
var BufferReader = require('../encoding/bufferreader');
|
||
|
var Block = require('../block');
|
||
|
|
||
|
var CONNECTION_NONCE = Random.getPseudoRandomBuffer(8);
|
||
|
var PROTOCOL_VERSION = 70000;
|
||
|
|
||
|
var MESSAGES = {
|
||
|
'version' : Version,
|
||
|
'verack': VerAck,
|
||
|
'inv': Inventory,
|
||
|
'ping': Ping,
|
||
|
'pong': Pong
|
||
|
}
|
||
|
|
||
|
module.exports.buildMessage = function(command, payload) {
|
||
|
var Message = MESSAGES[command];
|
||
|
try {
|
||
|
console.log('Message Class', Message);
|
||
|
return Message.fromBuffer(payload);
|
||
|
} catch (err) {
|
||
|
console.log('Error while parrsing message', command);
|
||
|
console.log(err);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ====== VERSION MESSAGE ======
|
||
|
function Version(subversion, nonce) {
|
||
|
this.command = 'version';
|
||
|
this.subversion = subversion || '/BitcoinX:0.1/';
|
||
|
this.nonce = nonce || CONNECTION_NONCE;
|
||
|
}
|
||
|
|
||
|
Version.fromBuffer = function(payload) {
|
||
|
var message = new Version();
|
||
|
|
||
|
var parser = new BufferReader(payload);
|
||
|
message.version = parser.readUInt32LE();
|
||
|
message.services = parser.readUInt64LEBN();
|
||
|
message.timestamp = parser.readUInt64LEBN();
|
||
|
message.addr_me = parser.read(26);
|
||
|
message.addr_you = parser.read(26);
|
||
|
message.nonce = parser.read(8);
|
||
|
message.subversion = parser.readVarintBuf();
|
||
|
message.start_height = parser.readUInt32LE();
|
||
|
|
||
|
return message;
|
||
|
}
|
||
|
|
||
|
Version.prototype.serialize = function() {
|
||
|
var put = new Put();
|
||
|
put.word32le(PROTOCOL_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 = Version;
|
||
|
|
||
|
// ====== INV MESSAGE ======
|
||
|
function Inventory(inventory) {
|
||
|
this.command = 'inv';
|
||
|
this.inventory = inventory || [];
|
||
|
}
|
||
|
|
||
|
Inventory.fromBuffer = function(payload) {
|
||
|
var message = new Inventory();
|
||
|
|
||
|
var parser = new BufferReader(payload);
|
||
|
var count = parser.readVarintNum();
|
||
|
for (var i = 0; i < count; i++) {
|
||
|
message.inventory.push({
|
||
|
type: parser.readUInt32LE(),
|
||
|
hash: parser.read(32)
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return message;
|
||
|
}
|
||
|
|
||
|
Inventory.prototype.serialize = function() {
|
||
|
var put = new Put();
|
||
|
|
||
|
put.varint(this.inventory.length);
|
||
|
this.inventory.forEach(function(value) {
|
||
|
value instanceof Block ? put.word32le(2) : put.word32le(1);
|
||
|
put.put(value.getHash());
|
||
|
});
|
||
|
|
||
|
return put.buffer();
|
||
|
}
|
||
|
|
||
|
|
||
|
// ====== PING/PONG MESSAGE ======
|
||
|
function Ping(nonce) {
|
||
|
this.command = 'ping';
|
||
|
this.nonce = nonce || CONNECTION_NONCE;
|
||
|
}
|
||
|
|
||
|
Ping.fromBuffer = function(payload) {
|
||
|
var nonce = new BufferReader(payload).read(8);
|
||
|
return new Ping(nonce);
|
||
|
}
|
||
|
|
||
|
Ping.prototype.serialize = function() {
|
||
|
return this.nonce;
|
||
|
}
|
||
|
|
||
|
function Pong(nonce) {
|
||
|
this.command = 'pong';
|
||
|
this.nonce = nonce || CONNECTION_NONCE;
|
||
|
}
|
||
|
|
||
|
Pong.fromBuffer = Ping.fromBuffer;
|
||
|
Pong.prototype.serialize = Ping.prototype.serialize;
|
||
|
|
||
|
|
||
|
// ====== VARIOUS MESSAGE ======
|
||
|
|
||
|
|
||
|
|
||
|
function GetAddr() {};
|
||
|
|
||
|
function VerAck() {};
|
||
|
VerAck.fromBuffer = function() {
|
||
|
return new VerAck();
|
||
|
}
|
||
|
|
||
|
function Reject() {};
|
||
|
|
||
|
function Ping(payload) {
|
||
|
var parser = new BufferReader(payload);
|
||
|
|
||
|
this.nonce = parser.read(8);
|
||
|
};
|
||
|
|
||
|
// ====== PING MESSAGE ======
|
||
|
function Address(payload) {
|
||
|
var parser = new BufferReader(payload);
|
||
|
|
||
|
var addrCount = parser.readVarintNum();
|
||
|
addrCount = Math.min(addrCount, 1000);
|
||
|
|
||
|
this.addresses = [];
|
||
|
for (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), // TODO: Parse IP Address
|
||
|
port: parser.readUInt16BE()
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
function GetHeaders(payload) {
|
||
|
var parser = new BufferReader(payload);
|
||
|
|
||
|
this.version = parser.readUInt32LE();
|
||
|
|
||
|
var startCount = parser.readVarintNum();
|
||
|
startCount = Math.min(startCount, 500);
|
||
|
|
||
|
this.starts = [];
|
||
|
for (i = 0; i < startCount; i++) {
|
||
|
this.starts.push(parser.read(32));
|
||
|
}
|
||
|
|
||
|
this.stop = parser.read(32);
|
||
|
}
|
||
|
|