From f01d6c98fbf7112e7ce993f307c9b0940238b09d Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 20 Apr 2015 15:44:09 -0300 Subject: [PATCH] refactor network handling --- docs/messages.md | 4 +-- integration/bitcoind.js | 24 ++++++++++++----- lib/messages/builder.js | 6 ++--- lib/messages/commands/addr.js | 2 -- lib/messages/commands/alert.js | 2 -- lib/messages/commands/block.js | 2 -- lib/messages/commands/filteradd.js | 2 -- lib/messages/commands/filterclear.js | 2 -- lib/messages/commands/filterload.js | 2 -- lib/messages/commands/getaddr.js | 2 -- lib/messages/commands/getblocks.js | 2 -- lib/messages/commands/getdata.js | 2 -- lib/messages/commands/getheaders.js | 2 -- lib/messages/commands/headers.js | 2 -- lib/messages/commands/inv.js | 2 -- lib/messages/commands/mempool.js | 2 -- lib/messages/commands/merkleblock.js | 2 -- lib/messages/commands/notfound.js | 2 -- lib/messages/commands/ping.js | 2 -- lib/messages/commands/pong.js | 2 -- lib/messages/commands/reject.js | 1 - lib/messages/commands/tx.js | 2 -- lib/messages/commands/verack.js | 2 -- lib/messages/commands/version.js | 2 -- lib/messages/index.js | 12 +++++---- lib/messages/message.js | 10 ++++--- lib/peer.js | 4 ++- test/messages/builder.js | 2 +- test/messages/index.js | 40 ++++++++++++++++------------ test/messages/message.js | 14 +++++++--- test/mocha.opts | 1 + 31 files changed, 75 insertions(+), 83 deletions(-) create mode 100644 test/mocha.opts diff --git a/docs/messages.md b/docs/messages.md index 9d6bcfe..c2721c3 100644 --- a/docs/messages.md +++ b/docs/messages.md @@ -36,10 +36,10 @@ For advanced usage, you can also customize which constructor is used for Block a var messages = new Messages({Block: MyBlock, Transaction: MyTransaction}); ``` -And additionally custom network magic: +And additionally custom network: ```javascript -var messages = new Messages({magicNumber: 0x0b120907}); +var messages = new Messages({network: Networks.testnet}); ``` ## List of Messages diff --git a/integration/bitcoind.js b/integration/bitcoind.js index d3e5f9f..8d07056 100644 --- a/integration/bitcoind.js +++ b/integration/bitcoind.js @@ -22,7 +22,7 @@ var Block = bitcore.Block; var Transaction = bitcore.Transaction; // config -var network = Networks.livenet; +var network = process.env.NETWORK === 'testnet'? Networks.testnet: Networks.livenet; var blockHash = { 'livenet': '000000000000000013413cf2536b491bf0988f52e90c476ffeb701c8bfdb1db9', 'testnet': '0000000058cc069d964711cd25083c0a709f4df2b34c8ff9302ce71fe5b45786' @@ -40,8 +40,12 @@ var txHash = { describe('Integration with ' + network.name + ' bitcoind', function() { this.timeout(15000); + var opts = { + host: 'localhost', + network: network.name + }; it('handshakes', function(cb) { - var peer = new Peer('localhost', network); + var peer = new Peer(opts); peer.once('version', function(m) { m.version.should.be.above(70000); m.services.toString().should.equal('1'); @@ -57,7 +61,7 @@ describe('Integration with ' + network.name + ' bitcoind', function() { peer.connect(); }); var connect = function(cb) { - var peer = new Peer('localhost', network); + var peer = new Peer(opts); peer.once('ready', function() { cb(peer); }); @@ -164,20 +168,28 @@ describe('Integration with ' + network.name + ' bitcoind', function() { message.headers.length.should.equal(3); cb(); }); - var message = messages.GetHeaders({starts: from, stop: stop}); + var message = messages.GetHeaders({ + starts: from, + stop: stop + }); peer.sendMessage(message); }); }); - it('gets blocks', function(cb) { + it.only('gets blocks', function(cb) { connect(function(peer) { peer.once('inv', function(message) { message.command.should.equal('inv'); + console.log('LLEGO UN INV', message.inventory.length); if (message.inventory.length === 2) { message.inventory[0].type.should.equal(Inventory.TYPE.BLOCK); + message.inventory[1].type.should.equal(Inventory.TYPE.BLOCK); cb(); } }); - var message = messages.GetBlocks({starts: from, stop: stop}); + var message = messages.GetBlocks({ + starts: from, + stop: stop + }); peer.sendMessage(message); }); }); diff --git a/lib/messages/builder.js b/lib/messages/builder.js index 590038c..068d672 100644 --- a/lib/messages/builder.js +++ b/lib/messages/builder.js @@ -11,8 +11,8 @@ function builder(options) { options = {}; } - if (!options.magicNumber) { - options.magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); + if (!options.network) { + options.network = bitcore.Networks.defaultNetwork; } options.Block = options.Block || bitcore.Block; @@ -30,7 +30,7 @@ function builder(options) { }, defaults: { protocolVersion: options.protocolVersion, - magicNumber: options.magicNumber + network: options.network }, inventoryCommands: [ 'getdata', diff --git a/lib/messages/commands/addr.js b/lib/messages/commands/addr.js index ed86b99..609a7a9 100644 --- a/lib/messages/commands/addr.js +++ b/lib/messages/commands/addr.js @@ -12,14 +12,12 @@ var BufferWriter = bitcore.encoding.BufferWriter; /** * @param {Array=} arg - An array of addrs * @param {Object=} options - * @param {Number} options.magicNumber * @extends Message * @constructor */ function AddrMessage(arg, options) { Message.call(this, options); this.command = 'addr'; - this.magicNumber = options.magicNumber; $.checkArgument( _.isUndefined(arg) || (Array.isArray(arg) && diff --git a/lib/messages/commands/alert.js b/lib/messages/commands/alert.js index 28c12e1..24c26a8 100644 --- a/lib/messages/commands/alert.js +++ b/lib/messages/commands/alert.js @@ -12,13 +12,11 @@ var BufferWriter = bitcore.encoding.BufferWriter; * @param {Buffer=} arg.payload * @param {Buffer=} arg.signature * @param {Object} options - * @param {Number} options.magicNumber * @extends Message * @constructor */ function AlertMessage(arg, options) { Message.call(this, options); - this.magicNumber = options.magicNumber; this.command = 'alert'; if (!arg) { arg = {}; diff --git a/lib/messages/commands/block.js b/lib/messages/commands/block.js index 9bcf9db..c681f8c 100644 --- a/lib/messages/commands/block.js +++ b/lib/messages/commands/block.js @@ -9,7 +9,6 @@ var _ = bitcore.deps._; /** * @param {Block=} arg - An instance of a Block * @param {Object} options - * @param {Number} options.magicNumber * @param {Function} options.Block - A block constructor * @extends Message * @constructor @@ -18,7 +17,6 @@ function BlockMessage(arg, options) { Message.call(this, options); this.Block = options.Block; this.command = 'block'; - this.magicNumber = options.magicNumber; $.checkArgument( _.isUndefined(arg) || arg instanceof this.Block, 'An instance of Block or undefined is expected' diff --git a/lib/messages/commands/filteradd.js b/lib/messages/commands/filteradd.js index 7cd82e1..6ee821f 100644 --- a/lib/messages/commands/filteradd.js +++ b/lib/messages/commands/filteradd.js @@ -14,13 +14,11 @@ var _ = bitcore.deps._; * Request peer to add data to a bloom filter already set by 'filterload' * @param {Buffer=} data - Array of bytes representing bloom filter data * @param {Object=} options - * @param {Number} options.magicNumber * @extends Message * @constructor */ function FilteraddMessage(arg, options) { Message.call(this, options); - this.magicNumber = options.magicNumber; this.command = 'filteradd'; $.checkArgument( _.isUndefined(arg) || BufferUtil.isBuffer(arg), diff --git a/lib/messages/commands/filterclear.js b/lib/messages/commands/filterclear.js index 017ba20..41e8d1d 100644 --- a/lib/messages/commands/filterclear.js +++ b/lib/messages/commands/filterclear.js @@ -8,12 +8,10 @@ var BufferUtil = bitcore.util.buffer; /** * Request peer to clear data for a bloom filter * @extends Message - * @param {Number} options.magicNumber * @constructor */ function FilterclearMessage(arg, options) { Message.call(this, options); - this.magicNumber = options.magicNumber; this.command = 'filterclear'; } inherits(FilterclearMessage, Message); diff --git a/lib/messages/commands/filterload.js b/lib/messages/commands/filterload.js index 63465e9..fbc3d59 100644 --- a/lib/messages/commands/filterload.js +++ b/lib/messages/commands/filterload.js @@ -12,13 +12,11 @@ var _ = bitcore.deps._; * Request peer to send inv messages based on a bloom filter * @param {BloomFilter=} arg - An instance of BloomFilter * @param {Object} options - * @param {Number} options.magicNumber * @extends Message * @constructor */ function FilterloadMessage(arg, options) { Message.call(this, options); - this.magicNumber = options.magicNumber; this.command = 'filterload'; $.checkArgument( _.isUndefined(arg) || arg instanceof BloomFilter, diff --git a/lib/messages/commands/getaddr.js b/lib/messages/commands/getaddr.js index 2beca5d..18f0073 100644 --- a/lib/messages/commands/getaddr.js +++ b/lib/messages/commands/getaddr.js @@ -9,12 +9,10 @@ var BufferUtil = bitcore.util.buffer; * Request information about active peers * @extends Message * @param {Object} options - * @param {Number} options.magicNumber * @constructor */ function GetaddrMessage(arg, options) { Message.call(this, options); - this.magicNumber = options.magicNumber; this.command = 'getaddr'; } inherits(GetaddrMessage, Message); diff --git a/lib/messages/commands/getblocks.js b/lib/messages/commands/getblocks.js index 771c5b2..0e35483 100644 --- a/lib/messages/commands/getblocks.js +++ b/lib/messages/commands/getblocks.js @@ -16,7 +16,6 @@ var $ = bitcore.util.preconditions; * @param {Array=} arg.starts - Array of buffers or strings with the starting block hashes * @param {Buffer=} arg.stop - Hash of the last block * @param {Object} options - * @param {Number} options.magicNumber * @extends Message * @constructor */ @@ -24,7 +23,6 @@ function GetblocksMessage(arg, options) { Message.call(this, options); this.command = 'getblocks'; this.version = options.protocolVersion; - this.magicNumber = options.magicNumber; if (!arg) { arg = {}; } diff --git a/lib/messages/commands/getdata.js b/lib/messages/commands/getdata.js index cd9b7ef..3a6eb0e 100644 --- a/lib/messages/commands/getdata.js +++ b/lib/messages/commands/getdata.js @@ -11,14 +11,12 @@ var _ = bitcore.deps._; /** * @param {Object|Array=} - options - If options is an array will use as "inventory" * @param {Array=} options.inventory - An array of inventory items - * @param {Number} options.magicNumber * @extends Message * @constructor */ function GetdataMessage(arg, options) { Message.call(this, options); this.command = 'getdata'; - this.magicNumber = options.magicNumber; utils.checkInventory(arg); this.inventory = arg; } diff --git a/lib/messages/commands/getheaders.js b/lib/messages/commands/getheaders.js index 19b96bd..d561e4c 100644 --- a/lib/messages/commands/getheaders.js +++ b/lib/messages/commands/getheaders.js @@ -15,7 +15,6 @@ var $ = bitcore.util.preconditions; * @param {Object=} options * @param {Array=} options.starts - Array of buffers or strings with the starting block hashes * @param {Buffer=} options.stop - Hash of the last block - * @param {Number} options.magicNumber * @extends Message * @constructor */ @@ -23,7 +22,6 @@ function GetheadersMessage(arg, options) { Message.call(this, options); this.command = 'getheaders'; this.version = options.protocolVersion; - this.magicNumber = options.magicNumber; if (!arg) { arg = {}; } diff --git a/lib/messages/commands/headers.js b/lib/messages/commands/headers.js index 4fd1688..a61f16e 100644 --- a/lib/messages/commands/headers.js +++ b/lib/messages/commands/headers.js @@ -15,7 +15,6 @@ var $ = bitcore.util.preconditions; * @param {Array} arg - An array of BlockHeader instances * @param {Object=} options * @param {Array=} options.headers - array of block headers - * @param {Number} options.magicNumber * @param {Function} options.BlockHeader - a BlockHeader constructor * @extends Message * @constructor @@ -23,7 +22,6 @@ var $ = bitcore.util.preconditions; function HeadersMessage(arg, options) { Message.call(this, options); this.BlockHeader = options.BlockHeader; - this.magicNumber = options.magicNumber; this.command = 'headers'; $.checkArgument( _.isUndefined(arg) || (Array.isArray(arg) && arg[0] instanceof this.BlockHeader), diff --git a/lib/messages/commands/inv.js b/lib/messages/commands/inv.js index 073354b..da4f67c 100644 --- a/lib/messages/commands/inv.js +++ b/lib/messages/commands/inv.js @@ -12,14 +12,12 @@ var _ = bitcore.deps._; * @param {Array=} arg - An array of inventory * @param {Object} options * @param {Array=} options.inventory - An array of inventory items - * @param {Number} options.magicNumber * @extends Message * @constructor */ function InvMessage(arg, options) { Message.call(this, options); this.command = 'inv'; - this.magicNumber = options.magicNumber; utils.checkInventory(arg); this.inventory = arg; } diff --git a/lib/messages/commands/mempool.js b/lib/messages/commands/mempool.js index 00fad39..fcfebc7 100644 --- a/lib/messages/commands/mempool.js +++ b/lib/messages/commands/mempool.js @@ -10,13 +10,11 @@ var BufferUtil = bitcore.util.buffer; * transactions it has verified but which have not yet confirmed. * @see https://en.bitcoin.it/wiki/Protocol_documentation#mempool * @param {Object} options - * @param {Number} options.magicNumber * @extends Message * @constructor */ function MempoolMessage(arg, options) { Message.call(this, options); - this.magicNumber = options.magicNumber; this.command = 'mempool'; } inherits(MempoolMessage, Message); diff --git a/lib/messages/commands/merkleblock.js b/lib/messages/commands/merkleblock.js index e26f405..c8bc04a 100644 --- a/lib/messages/commands/merkleblock.js +++ b/lib/messages/commands/merkleblock.js @@ -12,7 +12,6 @@ var _ = bitcore.deps._; * @see https://en.bitcoin.it/wiki/Protocol_documentation * @param {MerkleBlock} arg - An instance of MerkleBlock * @param {Object=} options - * @param {Number} options.magicNumber * @param {Function} options.MerkleBlock - a MerkleBlock constructor * @extends Message * @constructor @@ -20,7 +19,6 @@ var _ = bitcore.deps._; function MerkleblockMessage(arg, options) { Message.call(this, options); this.MerkleBlock = options.MerkleBlock; // constructor - this.magicNumber = options.magicNumber; this.command = 'merkleblock'; $.checkArgument( _.isUndefined(arg) || arg instanceof this.MerkleBlock, diff --git a/lib/messages/commands/notfound.js b/lib/messages/commands/notfound.js index a8c9f03..31c7727 100644 --- a/lib/messages/commands/notfound.js +++ b/lib/messages/commands/notfound.js @@ -12,14 +12,12 @@ var _ = bitcore.deps._; * @param {Array} arg - An array of inventory * @param {Object} options * @param {Array=} options.inventory - An array of inventory items - * @param {Number} options.magicNumber * @extends Message * @constructor */ function NotfoundMessage(arg, options) { Message.call(this, options); this.command = 'notfound'; - this.magicNumber = options.magicNumber; utils.checkInventory(arg); this.inventory = arg; } diff --git a/lib/messages/commands/ping.js b/lib/messages/commands/ping.js index 92ba3f3..0f77cee 100644 --- a/lib/messages/commands/ping.js +++ b/lib/messages/commands/ping.js @@ -13,14 +13,12 @@ var BufferReader = bitcore.encoding.BufferReader; * A message to confirm that a connection is still valid. * @param {Number} arg - A nonce for the Ping message * @param {Object=} options - * @param {Number} options.magicNumber * @extends Message * @constructor */ function PingMessage(arg, options) { Message.call(this, options); this.command = 'ping'; - this.magicNumber = options.magicNumber; $.checkArgument( _.isUndefined(arg) || (BufferUtil.isBuffer(arg) && arg.length === 8), 'First argument is expected to be an 8 byte buffer' diff --git a/lib/messages/commands/pong.js b/lib/messages/commands/pong.js index 111c4cc..519b531 100644 --- a/lib/messages/commands/pong.js +++ b/lib/messages/commands/pong.js @@ -13,14 +13,12 @@ var BufferReader = bitcore.encoding.BufferReader; * A message in response to a ping message. * @param {Number} arg - A nonce for the Pong message * @param {Object=} options - * @param {Number} options.magicNumber * @extends Message * @constructor */ function PongMessage(arg, options) { Message.call(this, options); this.command = 'pong'; - this.magicNumber = options.magicNumber; $.checkArgument( _.isUndefined(arg) || (BufferUtil.isBuffer(arg) && arg.length === 8), 'First argument is expected to be an 8 byte buffer' diff --git a/lib/messages/commands/reject.js b/lib/messages/commands/reject.js index ab73e36..5dea254 100644 --- a/lib/messages/commands/reject.js +++ b/lib/messages/commands/reject.js @@ -8,7 +8,6 @@ var BufferUtil = bitcore.util.buffer; // todo: add payload: https://en.bitcoin.it/wiki/Protocol_documentation#reject function RejectMessage(arg, options) { Message.call(this, options); - this.magicNumber = options.magicNumber; this.command = 'reject'; } inherits(RejectMessage, Message); diff --git a/lib/messages/commands/tx.js b/lib/messages/commands/tx.js index 614c42b..db3eae7 100644 --- a/lib/messages/commands/tx.js +++ b/lib/messages/commands/tx.js @@ -9,14 +9,12 @@ var _ = bitcore.deps._; /** * @param {Transaction=} arg - An instance of Transaction * @param {Object} options - * @param {Number} options.magicNumber * @extends Message * @constructor */ function TransactionMessage(arg, options) { Message.call(this, options); this.command = 'tx'; - this.magicNumber = options.magicNumber; this.Transaction = options.Transaction; $.checkArgument( _.isUndefined(arg) || arg instanceof this.Transaction, diff --git a/lib/messages/commands/verack.js b/lib/messages/commands/verack.js index 5c19751..6260bdd 100644 --- a/lib/messages/commands/verack.js +++ b/lib/messages/commands/verack.js @@ -7,13 +7,11 @@ var BufferUtil = bitcore.util.buffer; /** * A message in response to a version message. - * @param {Number} options.magicNumber * @extends Message * @constructor */ function VerackMessage(arg, options) { Message.call(this, options); - this.magicNumber = options.magicNumber; this.command = 'verack'; } inherits(VerackMessage, Message); diff --git a/lib/messages/commands/version.js b/lib/messages/commands/version.js index 11dc5ad..fb00ca7 100644 --- a/lib/messages/commands/version.js +++ b/lib/messages/commands/version.js @@ -23,7 +23,6 @@ var packageInfo = require('../../../package.json'); * @param {Date=} arg.timestamp * @param {Number=} arg.startHeight * @param {Object} options - * @param {Number} options.magicNumber * @extends Message * @constructor */ @@ -34,7 +33,6 @@ function VersionMessage(arg, options) { } Message.call(this, options); this.command = 'version'; - this.magicNumber = options.magicNumber; this.version = arg.version || options.protocolVersion; this.nonce = arg.nonce || utils.getNonce(); this.services = arg.services || new BN(1, 10); diff --git a/lib/messages/index.js b/lib/messages/index.js index d55e9f8..7fe58a4 100644 --- a/lib/messages/index.js +++ b/lib/messages/index.js @@ -3,11 +3,12 @@ var bitcore = require('bitcore'); var BufferUtil = bitcore.util.buffer; var Hash = bitcore.crypto.Hash; +var $ = bitcore.util.preconditions; /** * A factory to build Bitcoin protocol messages. * @param {Object=} options - * @param {Number=} options.magicNumber + * @param {Network=} options.network * @param {Function=} options.Block - A block constructor * @param {Function=} options.BlockHeader - A block header constructor * @param {Function=} options.MerkleBlock - A merkle block constructor @@ -26,8 +27,7 @@ function Messages(options) { if (!options) { options = {}; } - var defaultMagicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); - this.magicNumber = options.magicNumber || defaultMagicNumber; + this.network = options.network || bitcore.Networks.defaultNetwork; } Messages.MINIMUM_LENGTH = 20; @@ -75,11 +75,13 @@ Messages.prototype.parseBuffer = function(dataBuffer) { }; Messages.prototype._discardUntilNextMessage = function(dataBuffer) { + $.checkArgument(dataBuffer); + $.checkState(this.network, 'network must be set'); var i = 0; for (;;) { // check if it's the beginning of a new message - var packageNumber = dataBuffer.slice(0, 4).readUInt32LE(0); - if (packageNumber === this.magicNumber) { + var packageNumber = dataBuffer.slice(0, 4).toString('hex'); + if (packageNumber === this.network.networkMagic.toString('hex')) { dataBuffer.skip(i); return true; } diff --git a/lib/messages/message.js b/lib/messages/message.js index 4165914..3d04235 100644 --- a/lib/messages/message.js +++ b/lib/messages/message.js @@ -1,6 +1,8 @@ 'use strict'; var bitcore = require('bitcore'); +var $ = bitcore.util.preconditions; +var Networks = bitcore.Networks; var BufferWriter = bitcore.encoding.BufferWriter; var Hash = bitcore.crypto.Hash; @@ -9,12 +11,12 @@ var Hash = bitcore.crypto.Hash; * `getPayload` method to modify the message payload. * @param {Object=} options * @param {String=} options.command - * @param {Number=} options.magicNumber + * @param {Network=} options.network * @constructor */ function Message(options) { this.command = options.command; - this.magicNumber = options.magicNumber; + this.network = options.network || Networks.defaultNetwork; } /** @@ -22,7 +24,7 @@ function Message(options) { * @constructor */ Message.prototype.toBuffer = Message.prototype.serialize = function() { - + $.checkState(this.network, 'Need to have a defined network to serialize message'); var commandBuf = new Buffer(Array(12)); commandBuf.write(this.command, 'ascii'); @@ -30,7 +32,7 @@ Message.prototype.toBuffer = Message.prototype.serialize = function() { var checksum = Hash.sha256sha256(payload).slice(0, 4); var bw = new BufferWriter(); - bw.writeUInt32LE(this.magicNumber); + bw.write(this.network.networkMagic); bw.write(commandBuf); bw.writeUInt32LE(payload.length); bw.write(checksum); diff --git a/lib/peer.js b/lib/peer.js index f81b510..13f4bd3 100644 --- a/lib/peer.js +++ b/lib/peer.js @@ -64,7 +64,7 @@ function Peer(options) { } this.messages = options.messages || new Messages({ - magicNumber: this.network.networkMagic.readUInt32LE(0), + network: this.network, Block: bitcore.Block, Transaction: bitcore.Transaction }); @@ -191,6 +191,7 @@ Peer.prototype.disconnect = function() { * @param {Message} message - A message instance */ Peer.prototype.sendMessage = function(message) { + console.log('>sending', message.command); this.socket.write(message.toBuffer()); }; @@ -218,6 +219,7 @@ Peer.prototype._sendPong = function(nonce) { Peer.prototype._readMessage = function() { var message = this.messages.parseBuffer(this.dataBuffer); if (message) { + console.log('