diff --git a/integration/bitcoind.js b/integration/bitcoind.js index 97e6b39..e1a1448 100644 --- a/integration/bitcoind.js +++ b/integration/bitcoind.js @@ -94,7 +94,7 @@ describe('Integration with ' + network.name + ' bitcoind', function() { }); cb(); }); - var message = messages.build('getaddr'); + var message = messages.GetAddr(); peer.sendMessage(message); }); }); @@ -108,9 +108,9 @@ describe('Integration with ' + network.name + ' bitcoind', function() { should.exist(message.transaction); cb(); }); - peer.once('inv', function(m) { - var message = messages.build('getdata', {inventory: m.inventory}); - peer.sendMessage(message); + peer.once('inv', function(message) { + var get = messages.GetData(message.inventory); + peer.sendMessage(get); }); }); }); @@ -125,7 +125,7 @@ describe('Integration with ' + network.name + ' bitcoind', function() { message.inventory.should.deep.equal(inv); cb(); }); - var message = messages.build('inv', {inventory: inv}); + var message = messages.Inventory(inv); message.inventory[0].hash.length.should.equal(32); peer.sendMessage(message); }); @@ -136,23 +136,22 @@ describe('Integration with ' + network.name + ' bitcoind', function() { (message.block instanceof Block).should.equal(true); cb(); }); - var inventory = Inventory.forBlock(blockHash[network.name]); - var message = messages.build('getdata', {inventory: [inventory]}); + var message = messages.GetData.forBlock(blockHash[network.name]); peer.sendMessage(message); }); }); var fakeHash = 'e2dfb8afe1575bfacae1a0b4afc49af7ddda69285857267bae0e22be15f74a3a'; it('handles request tx data not found', function(cb) { connect(function(peer) { - var inventory = Inventory.forTransaction(fakeHash); - var expected = messages.build('notfound', {inventory: [inventory]}); + var expected = messages.NotFound.forTransaction(fakeHash); peer.once('notfound', function(message) { - message.command.should.equal('notfound'); + (message instanceof messages.NotFound).should.equal(true); message.inventory[0].type.should.equal(Inventory.TYPE.TX); - message.inventory[0].hash.toString('hex').should.equal(inventory.hash.toString('hex')); + var expectedHash = expected.inventory[0].hash.toString('hex'); + message.inventory[0].hash.toString('hex').should.equal(expectedHash); cb(); }); - var message = messages.build('getdata', {inventory: [inventory]}); + var message = messages.GetData.forTransaction(fakeHash); peer.sendMessage(message); }); }); @@ -161,11 +160,11 @@ describe('Integration with ' + network.name + ' bitcoind', function() { it('gets headers', function(cb) { connect(function(peer) { peer.once('headers', function(message) { - message.command.should.equal('headers'); + (message instanceof messages.Headers).should.equal(true); message.headers.length.should.equal(3); cb(); }); - var message = messages.build('getheaders', {starts: from, stop: stop}); + var message = messages.GetHeaders({starts: from, stop: stop}); peer.sendMessage(message); }); }); @@ -178,7 +177,7 @@ describe('Integration with ' + network.name + ' bitcoind', function() { cb(); } }); - var message = messages.build('getblocks', {starts: from, stop: stop}); + var message = messages.GetBlocks({starts: from, stop: stop}); peer.sendMessage(message); }); }); @@ -196,16 +195,14 @@ describe('Integration with ' + network.name + ' bitcoind', function() { }; it('sends block inv and receives getdata', function(cb) { var randomHash = new Buffer(Random.getRandomBuffer(32)); // slow buffer - var inventory = Inventory.forBlock(randomHash); - var expected = messages.build('getdata', {inventory: [inventory]}); - var message = messages.build('inv', {inventory: [inventory]}); + var expected = messages.GetData.forBlock(randomHash); + var message = messages.Inventory.forBlock(randomHash); testInvGetData(expected, message, cb); }); it('sends tx inv and receives getdata', function(cb) { var randomHash = new Buffer(Random.getRandomBuffer(32)); // slow buffer - var inventory = Inventory.forTransaction(randomHash); - var expected = messages.build('getdata', {inventory: [inventory]}); - var message = messages.build('inv', {inventory: [inventory]}); + var expected = messages.GetData.forTransaction(randomHash); + var message = messages.Inventory.forTransaction(randomHash); testInvGetData(expected, message, cb); }); }); diff --git a/lib/inventory.js b/lib/inventory.js index ba6b19e..e5e7e96 100644 --- a/lib/inventory.js +++ b/lib/inventory.js @@ -13,7 +13,6 @@ function Inventory(obj) { throw new TypeError('Unexpected hash, expected to be a buffer'); } this.hash = obj.hash; - } Inventory.forItem = function(type, hash) { diff --git a/lib/messages/commands/addr.js b/lib/messages/commands/addr.js index 5491c09..e8c1772 100644 --- a/lib/messages/commands/addr.js +++ b/lib/messages/commands/addr.js @@ -10,6 +10,9 @@ var BufferWriter = bitcore.encoding.BufferWriter; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function AddrMessage(options) { + if (!(this instanceof AddrMessage)) { + return new AddrMessage(options); + } Message.call(this, options); this.command = 'addr'; this.magicNumber = magicNumber; diff --git a/lib/messages/commands/alert.js b/lib/messages/commands/alert.js index 7e4926a..17f7902 100644 --- a/lib/messages/commands/alert.js +++ b/lib/messages/commands/alert.js @@ -10,6 +10,9 @@ var BufferWriter = bitcore.encoding.BufferWriter; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function AlertMessage(options) { + if (!(this instanceof AlertMessage)) { + return new AlertMessage(options); + } Message.call(this, options); this.magicNumber = magicNumber; this.command = 'alert'; diff --git a/lib/messages/commands/block.js b/lib/messages/commands/block.js index f29450f..29876de 100644 --- a/lib/messages/commands/block.js +++ b/lib/messages/commands/block.js @@ -8,6 +8,9 @@ var Block = bitcore.Block; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function BlockMessage(options) { + if (!(this instanceof BlockMessage)) { + return new BlockMessage(options); + } Message.call(this, options); this.command = 'block'; this.magicNumber = magicNumber; diff --git a/lib/messages/commands/filteradd.js b/lib/messages/commands/filteradd.js index a7966f7..ed67f8f 100644 --- a/lib/messages/commands/filteradd.js +++ b/lib/messages/commands/filteradd.js @@ -18,6 +18,9 @@ var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); * @param{Buffer} data - Array of bytes representing bloom filter data */ function FilteraddMessage(options) { + if (!(this instanceof FilteraddMessage)) { + return new FilteraddMessage(options); + } Message.call(this, options); this.magicNumber = magicNumber; this.command = 'filteradd'; diff --git a/lib/messages/commands/filterclear.js b/lib/messages/commands/filterclear.js index 0da1f5a..8acd582 100644 --- a/lib/messages/commands/filterclear.js +++ b/lib/messages/commands/filterclear.js @@ -8,6 +8,9 @@ var BufferUtil = bitcore.util.buffer; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function FilterclearMessage(options) { + if (!(this instanceof FilterclearMessage)) { + return new FilterclearMessage(options); + } Message.call(this, options); this.magicNumber = magicNumber; this.command = 'filterclear'; diff --git a/lib/messages/commands/filterload.js b/lib/messages/commands/filterload.js index 7e0ece9..04c1a97 100644 --- a/lib/messages/commands/filterload.js +++ b/lib/messages/commands/filterload.js @@ -11,6 +11,9 @@ var _ = bitcore.deps._; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function FilterloadMessage(options) { + if (!(this instanceof FilterloadMessage)) { + return new FilterloadMessage(options); + } Message.call(this, options); this.magicNumber = magicNumber; this.command = 'filterload'; diff --git a/lib/messages/commands/getaddr.js b/lib/messages/commands/getaddr.js index fa97d9d..70d0e7b 100644 --- a/lib/messages/commands/getaddr.js +++ b/lib/messages/commands/getaddr.js @@ -8,6 +8,9 @@ var BufferUtil = bitcore.util.buffer; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function GetaddrMessage(options) { + if (!(this instanceof GetaddrMessage)) { + return new GetaddrMessage(options); + } if (!options) { options = {}; } diff --git a/lib/messages/commands/getblocks.js b/lib/messages/commands/getblocks.js index e8ff388..97ae5d7 100644 --- a/lib/messages/commands/getblocks.js +++ b/lib/messages/commands/getblocks.js @@ -20,6 +20,9 @@ var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); * @param{Buffer} [stop] - hash of the last block */ function GetblocksMessage(options) { + if (!(this instanceof GetblocksMessage)) { + return new GetblocksMessage(options); + } Message.call(this, options); this.command = 'getblocks'; this.version = protocolVersion; diff --git a/lib/messages/commands/getdata.js b/lib/messages/commands/getdata.js index 229bcb4..266b17e 100644 --- a/lib/messages/commands/getdata.js +++ b/lib/messages/commands/getdata.js @@ -6,17 +6,43 @@ var bitcore = require('bitcore'); var utils = require('../utils'); var BufferReader = bitcore.encoding.BufferReader; var BufferWriter = bitcore.encoding.BufferWriter; +var Inventory = require('../../inventory'); +var _ = bitcore.deps._; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function GetdataMessage(options) { + if (!(this instanceof GetdataMessage)) { + return new GetdataMessage(options); + } Message.call(this, options); this.command = 'getdata'; this.magicNumber = magicNumber; - this.inventory = options.inventory; + + var inventory; + if (_.isArray(options)) { + inventory = options; + } else { + inventory = options.inventory; + } + + utils.checkInventory(inventory); + this.inventory = inventory; } inherits(GetdataMessage, Message); +GetdataMessage.forTransaction = function(hash) { + return new GetdataMessage([Inventory.forTransaction(hash)]); +}; + +GetdataMessage.forBlock = function(hash) { + return new GetdataMessage([Inventory.forBlock(hash)]); +}; + +GetdataMessage.forFilteredBlock = function(hash) { + return new GetdataMessage([Inventory.forFilteredBlock(hash)]); +}; + GetdataMessage.fromObject = function(options) { return new GetdataMessage(options); }; diff --git a/lib/messages/commands/getheaders.js b/lib/messages/commands/getheaders.js index 97a5068..0beb550 100644 --- a/lib/messages/commands/getheaders.js +++ b/lib/messages/commands/getheaders.js @@ -18,6 +18,9 @@ var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); * @param{Buffer} [stop] - hash of the last block */ function GetheadersMessage(options) { + if (!(this instanceof GetheadersMessage)) { + return new GetheadersMessage(options); + } Message.call(this, options); this.command = 'getheaders'; this.version = protocolVersion; diff --git a/lib/messages/commands/headers.js b/lib/messages/commands/headers.js index 05b1549..4911684 100644 --- a/lib/messages/commands/headers.js +++ b/lib/messages/commands/headers.js @@ -18,6 +18,9 @@ var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); * @param{Array} blockheaders - array of block headers */ function HeadersMessage(options) { + if (!(this instanceof HeadersMessage)) { + return new HeadersMessage(options); + } Message.call(this, options); this.magicNumber = magicNumber; this.command = 'headers'; diff --git a/lib/messages/commands/inv.js b/lib/messages/commands/inv.js index dba560a..83cfbc3 100644 --- a/lib/messages/commands/inv.js +++ b/lib/messages/commands/inv.js @@ -6,17 +6,42 @@ var bitcore = require('bitcore'); var utils = require('../utils'); var BufferReader = bitcore.encoding.BufferReader; var BufferWriter = bitcore.encoding.BufferWriter; +var Inventory = require('../../inventory'); +var _ = bitcore.deps._; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function InvMessage(options) { + if (!(this instanceof InvMessage)) { + return new InvMessage(options); + } Message.call(this, options); this.command = 'inv'; this.magicNumber = magicNumber; - this.inventory = options.inventory; + + var inventory; + if (_.isArray(options)) { + inventory = options; + } else { + inventory = options.inventory; + } + utils.checkInventory(inventory); + this.inventory = inventory; } inherits(InvMessage, Message); +InvMessage.forTransaction = function(hash) { + return new InvMessage([Inventory.forTransaction(hash)]); +}; + +InvMessage.forBlock = function(hash) { + return new InvMessage([Inventory.forBlock(hash)]); +}; + +InvMessage.forFilteredBlock = function(hash) { + return new InvMessage([Inventory.forFilteredBlock(hash)]); +}; + InvMessage.fromObject = function(options) { return new InvMessage(options); }; diff --git a/lib/messages/commands/mempool.js b/lib/messages/commands/mempool.js index 321f087..45e3b5a 100644 --- a/lib/messages/commands/mempool.js +++ b/lib/messages/commands/mempool.js @@ -8,6 +8,9 @@ var BufferUtil = bitcore.util.buffer; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function MempoolMessage(options) { + if (!(this instanceof MempoolMessage)) { + return new MempoolMessage(options); + } Message.call(this, options); this.magicNumber = magicNumber; this.command = 'mempool'; diff --git a/lib/messages/commands/merkleblock.js b/lib/messages/commands/merkleblock.js index af2ade1..f2e3539 100644 --- a/lib/messages/commands/merkleblock.js +++ b/lib/messages/commands/merkleblock.js @@ -17,6 +17,9 @@ var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); * @param {MerkleBlock} block */ function MerkleblockMessage(options) { + if (!(this instanceof MerkleblockMessage)) { + return new MerkleblockMessage(options); + } Message.call(this, options); this.magicNumber = magicNumber; this.command = 'merkleblock'; diff --git a/lib/messages/commands/notfound.js b/lib/messages/commands/notfound.js index d8f27f4..8905c7f 100644 --- a/lib/messages/commands/notfound.js +++ b/lib/messages/commands/notfound.js @@ -6,17 +6,42 @@ var bitcore = require('bitcore'); var utils = require('../utils'); var BufferReader = bitcore.encoding.BufferReader; var BufferWriter = bitcore.encoding.BufferWriter; +var Inventory = require('../../inventory'); +var _ = bitcore.deps._; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function NotfoundMessage(options) { + if (!(this instanceof NotfoundMessage)) { + return new NotfoundMessage(options); + } Message.call(this, options); this.command = 'notfound'; this.magicNumber = magicNumber; - this.inventory = options.inventory; + + var inventory; + if (_.isArray(options)) { + inventory = options; + } else { + inventory = options.inventory; + } + utils.checkInventory(inventory); + this.inventory = inventory; } inherits(NotfoundMessage, Message); +NotfoundMessage.forTransaction = function(hash) { + return new NotfoundMessage([Inventory.forTransaction(hash)]); +}; + +NotfoundMessage.forBlock = function(hash) { + return new NotfoundMessage([Inventory.forBlock(hash)]); +}; + +NotfoundMessage.forFilteredBlock = function(hash) { + return new NotfoundMessage([Inventory.forFilteredBlock(hash)]); +}; + NotfoundMessage.fromObject = function(options) { return new NotfoundMessage(options); }; diff --git a/lib/messages/commands/ping.js b/lib/messages/commands/ping.js index 84536b9..9300988 100644 --- a/lib/messages/commands/ping.js +++ b/lib/messages/commands/ping.js @@ -9,6 +9,9 @@ var BufferReader = bitcore.encoding.BufferReader; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function PingMessage(options) { + if (!(this instanceof PingMessage)) { + return new PingMessage(options); + } if (!options) { options = {}; } diff --git a/lib/messages/commands/pong.js b/lib/messages/commands/pong.js index 66eb4f4..af99a95 100644 --- a/lib/messages/commands/pong.js +++ b/lib/messages/commands/pong.js @@ -9,6 +9,9 @@ var BufferReader = bitcore.encoding.BufferReader; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function PongMessage(options) { + if (!(this instanceof PongMessage)) { + return new PongMessage(options); + } Message.call(this, options); this.command = 'pong'; this.magicNumber = magicNumber; diff --git a/lib/messages/commands/reject.js b/lib/messages/commands/reject.js index 4b38d67..4c197f7 100644 --- a/lib/messages/commands/reject.js +++ b/lib/messages/commands/reject.js @@ -9,6 +9,9 @@ var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); // todo: add payload: https://en.bitcoin.it/wiki/Protocol_documentation#reject function RejectMessage(options) { + if (!(this instanceof RejectMessage)) { + return new RejectMessage(options); + } Message.call(this, options); this.magicNumber = magicNumber; this.command = 'reject'; diff --git a/lib/messages/commands/tx.js b/lib/messages/commands/tx.js index 676809a..9f4409d 100644 --- a/lib/messages/commands/tx.js +++ b/lib/messages/commands/tx.js @@ -8,6 +8,9 @@ var Transaction = bitcore.Transaction; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function TransactionMessage(options) { + if (!(this instanceof TransactionMessage)) { + return new TransactionMessage(options); + } Message.call(this, options); this.command = 'tx'; this.magicNumber = magicNumber; diff --git a/lib/messages/commands/verack.js b/lib/messages/commands/verack.js index 5def3e2..ddc79c2 100644 --- a/lib/messages/commands/verack.js +++ b/lib/messages/commands/verack.js @@ -8,6 +8,9 @@ var BufferUtil = bitcore.util.buffer; var magicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0); function VerackMessage(options) { + if (!(this instanceof VerackMessage)) { + return new VerackMessage(options); + } if(!options) { options = {}; } diff --git a/lib/messages/commands/version.js b/lib/messages/commands/version.js index dc78c37..7652cf6 100644 --- a/lib/messages/commands/version.js +++ b/lib/messages/commands/version.js @@ -24,6 +24,9 @@ var packageInfo = require('../../../package.json'); * @param{Buffer} obj.nonce - a random 8 byte buffer */ function VersionMessage(obj) { + if (!(this instanceof VersionMessage)) { + return new VersionMessage(obj); + } /* jshint maxcomplexity: 10 */ Message.call(this, obj); this.command = 'version'; diff --git a/lib/messages/utils.js b/lib/messages/utils.js index b97fec8..d1bd29e 100644 --- a/lib/messages/utils.js +++ b/lib/messages/utils.js @@ -7,6 +7,14 @@ var _ = bitcore.deps._; var utils; module.exports = utils = { + checkInventory: function(inventory) { + $.checkArgument( + _.isUndefined(inventory) || + inventory.length === 0 || + (!_.isUndefined(inventory[0].type) && !_.isUndefined(inventory[0].hash)), + 'Inventory must be an array of inventory objects' + ); + }, checkFinished: function checkFinished(parser) { if(!parser.finished()) { throw new Error('Data still available after parsing');