Add messages serialization
This commit is contained in:
parent
a9e54a7856
commit
68f50b2f61
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
var Put = require('bufferput');
|
var Put = require('bufferput');
|
||||||
|
|
||||||
var Random = require('../crypto/random');
|
|
||||||
var BufferReader = require('../encoding/bufferreader');
|
|
||||||
var Block = require('../block');
|
var Block = require('../block');
|
||||||
|
var BufferReader = require('../encoding/bufferreader');
|
||||||
|
var BufferUtil = require('../util/buffer');
|
||||||
|
var Random = require('../crypto/random');
|
||||||
|
|
||||||
var CONNECTION_NONCE = Random.getPseudoRandomBuffer(8);
|
var CONNECTION_NONCE = Random.getPseudoRandomBuffer(8);
|
||||||
var PROTOCOL_VERSION = 70000;
|
var PROTOCOL_VERSION = 70000;
|
||||||
|
@ -14,7 +15,10 @@ var MESSAGES = {
|
||||||
'verack': VerAck,
|
'verack': VerAck,
|
||||||
'inv': Inventory,
|
'inv': Inventory,
|
||||||
'ping': Ping,
|
'ping': Ping,
|
||||||
'pong': Pong
|
'pong': Pong,
|
||||||
|
'addr': Addresses,
|
||||||
|
'getaddr': GetAddresses,
|
||||||
|
'reject': Reject
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.buildMessage = function(command, payload) {
|
module.exports.buildMessage = function(command, payload) {
|
||||||
|
@ -31,9 +35,10 @@ module.exports.buildMessage = function(command, payload) {
|
||||||
// ====== VERSION MESSAGE ======
|
// ====== VERSION MESSAGE ======
|
||||||
function Version(subversion, nonce) {
|
function Version(subversion, nonce) {
|
||||||
this.command = 'version';
|
this.command = 'version';
|
||||||
|
this.version = PROTOCOL_VERSION;
|
||||||
this.subversion = subversion || '/BitcoinX:0.1/';
|
this.subversion = subversion || '/BitcoinX:0.1/';
|
||||||
this.nonce = nonce || CONNECTION_NONCE;
|
this.nonce = nonce || CONNECTION_NONCE;
|
||||||
}
|
};
|
||||||
|
|
||||||
Version.fromBuffer = function(payload) {
|
Version.fromBuffer = function(payload) {
|
||||||
var message = new Version();
|
var message = new Version();
|
||||||
|
@ -49,11 +54,11 @@ Version.fromBuffer = function(payload) {
|
||||||
message.start_height = parser.readUInt32LE();
|
message.start_height = parser.readUInt32LE();
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
};
|
||||||
|
|
||||||
Version.prototype.serialize = function() {
|
Version.prototype.serialize = function() {
|
||||||
var put = new Put();
|
var put = new Put();
|
||||||
put.word32le(PROTOCOL_VERSION); // version
|
put.word32le(this.version); // version
|
||||||
put.word64le(1); // services
|
put.word64le(1); // services
|
||||||
put.word64le(Math.round(new Date().getTime() / 1000)); // timestamp
|
put.word64le(Math.round(new Date().getTime() / 1000)); // timestamp
|
||||||
put.pad(26); // addr_me
|
put.pad(26); // addr_me
|
||||||
|
@ -64,11 +69,11 @@ Version.prototype.serialize = function() {
|
||||||
put.word32le(0);
|
put.word32le(0);
|
||||||
|
|
||||||
return put.buffer();
|
return put.buffer();
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports.Version = Version;
|
module.exports.Version = Version;
|
||||||
|
|
||||||
// ====== INV MESSAGE ======
|
// ====== INV/GETDATA MESSAGE ======
|
||||||
function Inventory(inventory) {
|
function Inventory(inventory) {
|
||||||
this.command = 'inv';
|
this.command = 'inv';
|
||||||
this.inventory = inventory || [];
|
this.inventory = inventory || [];
|
||||||
|
@ -87,7 +92,7 @@ Inventory.fromBuffer = function(payload) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
};
|
||||||
|
|
||||||
Inventory.prototype.serialize = function() {
|
Inventory.prototype.serialize = function() {
|
||||||
var put = new Put();
|
var put = new Put();
|
||||||
|
@ -99,8 +104,15 @@ Inventory.prototype.serialize = function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
return put.buffer();
|
return put.buffer();
|
||||||
|
};
|
||||||
|
|
||||||
|
function GetData(inventory) {
|
||||||
|
this.command = 'getdata';
|
||||||
|
this.inventory = inventory || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetData.fromBuffer = Inventory.fromBuffer;
|
||||||
|
GetData.prototype.serialize = Inventory.prototype.serialize;
|
||||||
|
|
||||||
// ====== PING/PONG MESSAGE ======
|
// ====== PING/PONG MESSAGE ======
|
||||||
function Ping(nonce) {
|
function Ping(nonce) {
|
||||||
|
@ -111,11 +123,11 @@ function Ping(nonce) {
|
||||||
Ping.fromBuffer = function(payload) {
|
Ping.fromBuffer = function(payload) {
|
||||||
var nonce = new BufferReader(payload).read(8);
|
var nonce = new BufferReader(payload).read(8);
|
||||||
return new Ping(nonce);
|
return new Ping(nonce);
|
||||||
}
|
};
|
||||||
|
|
||||||
Ping.prototype.serialize = function() {
|
Ping.prototype.serialize = function() {
|
||||||
return this.nonce;
|
return this.nonce;
|
||||||
}
|
};
|
||||||
|
|
||||||
function Pong(nonce) {
|
function Pong(nonce) {
|
||||||
this.command = 'pong';
|
this.command = 'pong';
|
||||||
|
@ -126,57 +138,202 @@ Pong.fromBuffer = Ping.fromBuffer;
|
||||||
Pong.prototype.serialize = Ping.prototype.serialize;
|
Pong.prototype.serialize = Ping.prototype.serialize;
|
||||||
|
|
||||||
|
|
||||||
// ====== VARIOUS MESSAGE ======
|
// ====== ADDR MESSAGE ======
|
||||||
|
function Addresses(nonce) {
|
||||||
|
this.command = 'addr';
|
||||||
|
this.addresses = [];
|
||||||
function GetAddr() {};
|
|
||||||
|
|
||||||
function VerAck() {};
|
|
||||||
VerAck.fromBuffer = function() {
|
|
||||||
return new VerAck();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Reject() {};
|
Address.fromBuffer = function(payload) {
|
||||||
|
var message = new Address();
|
||||||
|
|
||||||
function Ping(payload) {
|
|
||||||
var parser = new BufferReader(payload);
|
var parser = new BufferReader(payload);
|
||||||
|
var addrCount = Math.min(parser.readVarintNum(), 1000);
|
||||||
|
|
||||||
this.nonce = parser.read(8);
|
message.addresses = [];
|
||||||
};
|
for (var i = 0; i < addrCount; i++) {
|
||||||
|
|
||||||
// ====== 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)
|
// TODO: Time actually depends on the version of the other peer (>=31402)
|
||||||
this.addresses.push({
|
message.addresses.push({
|
||||||
time: parser.readUInt32LE(),
|
time: parser.readUInt32LE(),
|
||||||
services: parser.readUInt64LEBN(),
|
services: parser.readUInt64LEBN(),
|
||||||
ip: parser.read(16), // TODO: Parse IP Address
|
ip: parser.read(16),
|
||||||
port: parser.readUInt16BE()
|
port: parser.readUInt16BE()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
};
|
};
|
||||||
|
|
||||||
function GetHeaders(payload) {
|
Address.prototype.serialize = function() {
|
||||||
|
return BufferUtil.EMPTY_BUFFER; // TODO
|
||||||
|
};
|
||||||
|
|
||||||
|
// ====== GETADDR MESSAGE ======
|
||||||
|
function GetAddresses() {
|
||||||
|
this.command = 'getaddr';
|
||||||
|
}
|
||||||
|
|
||||||
|
GetAddresses.fromBuffer = function() {
|
||||||
|
return new GetAddresses();
|
||||||
|
};
|
||||||
|
|
||||||
|
GetAddresses.prototype.serialize = function() {
|
||||||
|
return BufferUtil.EMPTY_BUFFER;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ====== VERACK MESSAGE ======
|
||||||
|
function VerAck() {
|
||||||
|
this.command = 'verack';
|
||||||
|
}
|
||||||
|
|
||||||
|
VerAck.fromBuffer = function() {
|
||||||
|
return new VerAck();
|
||||||
|
};
|
||||||
|
|
||||||
|
VerAck.prototype.serialize = function() {
|
||||||
|
return BufferUtil.EMPTY_BUFFER;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ====== REJECT MESSAGE ======
|
||||||
|
// TODO: Parse REJECT message
|
||||||
|
function Reject() {
|
||||||
|
this.command = 'reject';
|
||||||
|
}
|
||||||
|
|
||||||
|
Reject.fromBuffer = function() {
|
||||||
|
return new Reject();
|
||||||
|
};
|
||||||
|
|
||||||
|
Reject.prototype.serialize = function() {
|
||||||
|
return BufferUtil.EMPTY_BUFFER;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ====== ALERT MESSAGE ======
|
||||||
|
function Alert(payload) {
|
||||||
|
this.command = 'reject';
|
||||||
|
}
|
||||||
|
|
||||||
|
Alert.fromBuffer = function() {
|
||||||
|
var message = new Alert();
|
||||||
|
|
||||||
var parser = new BufferReader(payload);
|
var parser = new BufferReader(payload);
|
||||||
|
message.payload = parser.readVarintBuf(); // TODO: Use current format
|
||||||
|
message.signature = parser.readVarintBuf();
|
||||||
|
return message;
|
||||||
|
};
|
||||||
|
|
||||||
this.version = parser.readUInt32LE();
|
Alert.prototype.serialize = function() {
|
||||||
|
return BufferUtil.EMPTY_BUFFER; // TODO: Serialize
|
||||||
|
};
|
||||||
|
|
||||||
var startCount = parser.readVarintNum();
|
// ====== HEADERS MESSAGE ======
|
||||||
startCount = Math.min(startCount, 500);
|
function Headers(blockheaders) {
|
||||||
|
this.command = 'headers';
|
||||||
this.starts = [];
|
this.headers = blockheaders || [];
|
||||||
for (i = 0; i < startCount; i++) {
|
|
||||||
this.starts.push(parser.read(32));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stop = parser.read(32);
|
Headers.fromBuffer = function() {
|
||||||
|
var message = new Headers();
|
||||||
|
|
||||||
|
var parser = new BufferReader(payload);
|
||||||
|
var count = parser.readVarintNum();
|
||||||
|
|
||||||
|
message.headers = [];
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
var header = Block().fromBufferReader(parser);
|
||||||
|
message.headers.push(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
};
|
||||||
|
|
||||||
|
Headers.prototype.serialize = function() {
|
||||||
|
return BufferUtil.EMPTY_BUFFER; // TODO: Serialize
|
||||||
|
};
|
||||||
|
|
||||||
|
// ====== BLOCK MESSAGE ======
|
||||||
|
function Block(block) {
|
||||||
|
this.command = 'block';
|
||||||
|
this.block = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block.fromBuffer = function() {
|
||||||
|
var parser = new BufferReader(payload);
|
||||||
|
var block = Block().fromBufferReader(parser);
|
||||||
|
return new Block(block);
|
||||||
|
};
|
||||||
|
|
||||||
|
Block.prototype.serialize = function() {
|
||||||
|
return BufferUtil.EMPTY_BUFFER; // TODO: Serialize
|
||||||
|
};
|
||||||
|
|
||||||
|
// ====== TX MESSAGE ======
|
||||||
|
function Transaction(transaction) {
|
||||||
|
this.command = 'tx';
|
||||||
|
this.transaction = transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transaction.fromBuffer = function() {
|
||||||
|
var parser = new BufferReader(payload);
|
||||||
|
var transaction = Transaction().fromBufferReader(parser);
|
||||||
|
return new Transaction(transaction);
|
||||||
|
};
|
||||||
|
|
||||||
|
Transaction.prototype.serialize = function() {
|
||||||
|
return BufferUtil.EMPTY_BUFFER; // TODO: Serialize
|
||||||
|
};
|
||||||
|
|
||||||
|
// ====== GETBLOCKS/GETHEADERS MESSAGE ======
|
||||||
|
function GetBlocks(starts, stop) {
|
||||||
|
this.command = 'getblocks';
|
||||||
|
this.version = PROTOCOL_VERSION;
|
||||||
|
this.starts = starts || [];
|
||||||
|
this.stop = stop || BufferUtil.NULL_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetBlocks.fromBuffer = function() {
|
||||||
|
var message = new GetBlocks();
|
||||||
|
|
||||||
|
var parser = new BufferReader(payload);
|
||||||
|
message.version = parser.readUInt32LE();
|
||||||
|
|
||||||
|
var startCount = Math.min(parser.readVarintNum(), 500);
|
||||||
|
message.starts = [];
|
||||||
|
for (var i = 0; i < startCount; i++) {
|
||||||
|
message.starts.push(parser.read(32));
|
||||||
|
}
|
||||||
|
message.stop = parser.read(32);
|
||||||
|
};
|
||||||
|
|
||||||
|
GetBlocks.prototype.serialize = function() {
|
||||||
|
var put = new Put();
|
||||||
|
put.word32le(this.version);
|
||||||
|
put.varint(this.starts.length);
|
||||||
|
|
||||||
|
for (var i = 0; i < 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();
|
||||||
|
};
|
||||||
|
|
||||||
|
function GetHeaders(starts, stop) {
|
||||||
|
this.command = 'getheaders';
|
||||||
|
this.version = PROTOCOL_VERSION;
|
||||||
|
this.starts = starts || [];
|
||||||
|
this.stop = stop || BufferUtil.NULL_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetHeaders.fromBuffer = GetBlocks.fromBuffer;
|
||||||
|
GetHeaders.prototype.serialize = GetBlocks.prototype.serialize;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,6 @@ function equals(a, b) {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
NULL_HASH: buffertools.fill(new Buffer(32), 0),
|
NULL_HASH: buffertools.fill(new Buffer(32), 0),
|
||||||
EMPTY_BUFFER: new Buffer(0),
|
EMPTY_BUFFER: new Buffer(0),
|
||||||
ZERO_VALUE: buffertools.fill(new Buffer(8), 0),
|
|
||||||
INT64_MAX: new Buffer('ffffffffffffffff', 'hex'),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given argument is an instance of a buffer. Tests for
|
* Returns true if the given argument is an instance of a buffer. Tests for
|
||||||
|
|
Loading…
Reference in New Issue