refactor message#fromBuffer()

This commit is contained in:
Manuel Araoz 2015-01-27 16:29:34 -03:00
parent ce7ccc773e
commit eaca92b1c6
3 changed files with 87 additions and 57 deletions

View File

@ -17,6 +17,7 @@ var BufferUtil = bitcore.util.buffer;
var Hash = bitcore.crypto.Hash;
var Random = bitcore.crypto.Random;
var TransactionModel = bitcore.Transaction;
var errors = bitcore.Errors;
var CONNECTION_NONCE = Random.getPseudoRandomBuffer(8);
var PROTOCOL_VERSION = 70000;
@ -88,7 +89,7 @@ function discardUntilNextMessage(network, dataBuffer) {
/**
* Abstract Message that knows how to parse and serialize itself.
* Concret subclases should implement {fromBuffer} and {getPayload} methods.
* Concrete subclasses should implement {fromBuffer} and {getPayload} methods.
* @name P2P.Message
*/
function Message() {}
@ -106,7 +107,7 @@ Message.COMMANDS = {};
Message.buildMessage = function(command, payload) {
try {
var CommandClass = Message.COMMANDS[command];
return new CommandClass().fromBuffer(payload);
return new CommandClass.fromBuffer(payload);
} catch (err) {
console.log('Error while parsing message', err);
}
@ -118,9 +119,9 @@ Message.buildMessage = function(command, payload) {
* @param{Buffer} payload - the buffer to read from
* @returns{Message} The same message instance
*/
Message.prototype.fromBuffer = function(payload) {
Message.fromBuffer = function(payload) {
/* jshint unused: false */
return this;
throw new errors.NotImplemented();
};
/**
@ -180,51 +181,52 @@ function Version(subversion, nonce) {
}
util.inherits(Version, Message);
Version.prototype.fromBuffer = function(payload) {
Version.fromBuffer = function(payload) {
var that = new Version();
var parser = new BufferReader(payload);
/**
* @type {number}
* @desc The version of the bitcoin protocol
*/
this.version = parser.readUInt32LE();
that.version = parser.readUInt32LE();
/**
* @type {BN}
* @desc A mapbit with service bits: what features are supported by the peer
*/
this.services = parser.readUInt64LEBN();
that.services = parser.readUInt64LEBN();
/**
* @type {BN}
* @desc The time this message was sent
*/
this.timestamp = parser.readUInt64LEBN();
that.timestamp = parser.readUInt64LEBN();
/**
* @type {Buffer}
* @desc IPv4/6 address of the interface used to connect to this peer
*/
this.addr_me = parser.read(26);
that.addr_me = parser.read(26);
/**
* @type {Buffer}
* @desc IPv4/6 address of the peer
*/
this.addr_you = parser.read(26);
that.addr_you = parser.read(26);
/**
* @type {Buffer}
* @desc A random number
*/
this.nonce = parser.read(8);
that.nonce = parser.read(8);
/**
* @desc A random number
* @type {string}
*/
this.subversion = parser.readVarintBuf().toString();
that.subversion = parser.readVarintBuf().toString();
/**
* @desc The height of the last block accepted in the blockchain by this peer
* @type {number}
*/
this.start_height = parser.readUInt32LE();
that.start_height = parser.readUInt32LE();
return this;
return that;
};
Version.prototype.getPayload = function() {
@ -263,17 +265,18 @@ function Inventory(inventory) {
}
util.inherits(Inventory, Message);
Inventory.prototype.fromBuffer = function(payload) {
Inventory.fromBuffer = function(payload) {
var that = new Inventory();
var parser = new BufferReader(payload);
var count = parser.readVarintNum();
for (var i = 0; i < count; i++) {
this.inventory.push({
that.inventory.push({
type: parser.readUInt32LE(),
hash: parser.read(32)
});
}
return this;
return that;
};
Inventory.prototype.getPayload = function() {
@ -327,9 +330,10 @@ function Ping(nonce) {
}
util.inherits(Ping, Message);
Ping.prototype.fromBuffer = function(payload) {
this.nonce = new BufferReader(payload).read(8);
return this;
Ping.fromBuffer = function(payload) {
var that = new Ping();
that.nonce = new BufferReader(payload).read(8);
return that;
};
Ping.prototype.getPayload = function() {
@ -354,6 +358,9 @@ function Pong(nonce) {
}
util.inherits(Pong, Ping);
Pong.fromBuffer = function() {
return new Pong();
};
module.exports.Pong = Message.COMMANDS.pong = Pong;
/**
@ -372,11 +379,12 @@ function Addresses(addresses) {
}
util.inherits(Addresses, Message);
Addresses.prototype.fromBuffer = function(payload) {
Addresses.fromBuffer = function(payload) {
var that = new Addresses();
var parser = new BufferReader(payload);
var addrCount = Math.min(parser.readVarintNum(), 1000);
this.addresses = [];
that.addresses = [];
for (var i = 0; i < addrCount; i++) {
// TODO: Time actually depends on the version of the other peer (>=31402)
@ -399,7 +407,7 @@ Addresses.prototype.fromBuffer = function(payload) {
var port = parser.readUInt16BE();
this.addresses.push({
that.addresses.push({
time: time,
services: services,
ip: { v6: ipv6, v4: ipv4 },
@ -407,7 +415,7 @@ Addresses.prototype.fromBuffer = function(payload) {
});
}
return this;
return that;
};
Addresses.prototype.getPayload = function() {
@ -436,6 +444,9 @@ function GetAddresses() {
}
util.inherits(GetAddresses, Message);
GetAddresses.fromBuffer = function() {
return new GetAddresses();
};
module.exports.GetAddresses = Message.COMMANDS.getaddr = GetAddresses;
/**
@ -448,6 +459,9 @@ function VerAck() {
}
util.inherits(VerAck, Message);
VerAck.fromBuffer = function() {
return new VerAck();
};
module.exports.VerAck = Message.COMMANDS.verack = VerAck;
/**
@ -477,11 +491,12 @@ function Alert(payload, signature) {
}
util.inherits(Alert, Message);
Alert.prototype.fromBuffer = function(payload) {
Alert.fromBuffer = function(payload) {
var that = new Alert();
var parser = new BufferReader(payload);
this.payload = parser.readVarintBuf(); // TODO: Use current format
this.signature = parser.readVarintBuf();
return this;
that.payload = parser.readVarintBuf(); // TODO: Use current format
that.signature = parser.readVarintBuf();
return that;
};
Alert.prototype.getPayload = function() {
@ -514,17 +529,18 @@ function Headers(blockheaders) {
}
util.inherits(Headers, Message);
Headers.prototype.fromBuffer = function(payload) {
Headers.fromBuffer = function(payload) {
var that = new Headers();
var parser = new BufferReader(payload);
var count = parser.readVarintNum();
this.headers = [];
that.headers = [];
for (var i = 0; i < count; i++) {
var header = BlockHeaderModel._fromBufferReader(parser);
this.headers.push(header);
that.headers.push(header);
}
return this;
return that;
};
Headers.prototype.getPayload = function() {
@ -558,9 +574,10 @@ function Block(block) {
}
util.inherits(Block, Message);
Block.prototype.fromBuffer = function(payload) {
this.block = BlockModel(payload);
return this;
Block.fromBuffer = function(payload) {
var that = new Block();
that.block = BlockModel(payload);
return that;
};
Block.prototype.getPayload = function() {
@ -584,9 +601,10 @@ function Transaction(transaction) {
}
util.inherits(Transaction, Message);
Transaction.prototype.fromBuffer = function(payload) {
this.transaction = TransactionModel(payload);
return this;
Transaction.fromBuffer = function(payload) {
var that = new Transaction();
that.transaction = TransactionModel(payload);
return that;
};
Transaction.prototype.getPayload = function() {
@ -622,18 +640,19 @@ function GetBlocks(starts, stop) {
}
util.inherits(GetBlocks, Message);
GetBlocks.prototype.fromBuffer = function(payload) {
GetBlocks.fromBuffer = function(payload) {
var that = new GetBlocks();
var parser = new BufferReader(payload);
this.version = parser.readUInt32LE();
that.version = parser.readUInt32LE();
var startCount = Math.min(parser.readVarintNum(), 500);
this.starts = [];
that.starts = [];
for (var i = 0; i < startCount; i++) {
this.starts.push(parser.read(32));
that.starts.push(parser.read(32));
}
this.stop = parser.read(32);
that.stop = parser.read(32);
return this;
return that;
};
GetBlocks.prototype.getPayload = function() {

View File

@ -36,31 +36,32 @@ describe('Messages', function() {
it('should be able to parse payload', function() {
var payload = new Buffer(Data.VERSION.payload, 'hex');
new Messages.Version().fromBuffer(payload);
var m = Messages.Version.fromBuffer(payload);
should.exist(m);
});
});
describe('VerAck', function() {
var name = 'VerAck';
describe(name, function() {
var message = new Messages[name]();
it('should be able to create instance', function() {
var message = new Messages.VerAck();
message.command.should.equal('verack');
message.command.should.equal(name.toLowerCase());
});
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);
var payload = new Buffer(Data[name.toUpperCase()].payload, 'hex');
var m = Messages[name].fromBuffer(payload);
should.exist(m);
});
});
@ -84,7 +85,8 @@ describe('Messages', function() {
it('should be able to parse payload', function() {
var payload = new Buffer(Data.INV.payload, 'hex');
new Messages.Inventory().fromBuffer(payload);
var m = Messages.Inventory.fromBuffer(payload);
should.exist(m);
});
});
@ -108,10 +110,17 @@ describe('Messages', function() {
it('should be able to parse payload', function() {
var payload = new Buffer(Data.ADDR.payload, 'hex');
new Messages.Addresses().fromBuffer(payload);
var m = Messages.Addresses.fromBuffer(payload);
should.exist(m);
});
});
/*
Data.forEach(function(x) {
console.log(x);
});
*/
describe('Ping', function() {
it('should be able to create instance', function() {
var message = new Messages.Ping();
@ -132,7 +141,8 @@ describe('Messages', function() {
it('should be able to parse payload', function() {
var payload = new Buffer(Data.PING.payload, 'hex');
new Messages.Ping().fromBuffer(payload);
var m = Messages.Ping.fromBuffer(payload);
should.exist(m);
});
});
@ -156,7 +166,8 @@ describe('Messages', function() {
it('should be able to parse payload', function() {
var payload = new Buffer(Data.PING.payload, 'hex');
new Messages.Pong().fromBuffer(payload);
var m = Messages.Pong.fromBuffer(payload);
should.exist(m);
});
});

View File

@ -66,7 +66,7 @@ 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 message = Messages.Addresses.fromBuffer(payload);
this.emit(message.command, message);
});