diff --git a/docs/messages.md b/docs/messages.md new file mode 100644 index 0000000..0f757ed --- /dev/null +++ b/docs/messages.md @@ -0,0 +1,50 @@ +title: Messages +description: A superclass for the messages of the bitcoin network +--- +# Messages + +The bitcoin protocol specifies a set of [messages](https://en.bitcoin.it/wiki/Protocol_specification) that can be sent from peer to peer. `bitcore-p2p` provides partial support for some of these messages. + +## List of Messages + +### Version + +The version message (`ver`) is used on connection creation, to advertise the type of node. The remote node will respond with its version, and no communication is possible until both peers have exchanged their versions. By default, bitcore advertises itself as named `bitcore:0.8`. + +### VerAck + +Finishes the connection handshake started by the `ver` message. + +### Inventory + +From the bitcoin protocol spec: "Allows a node to advertise its knowledge of one or more objects. It can be received unsolicited, or in reply to getblocks.". + +### GetData + +From the bitcoin protocol spec: `getdata` is used in response to `inv`, to retrieve the content of a specific object, and is usually sent after receiving an `inv` packet, after filtering known elements. It can be used to retrieve transactions, but only if they are in the memory pool or relay set - arbitrary access to transactions in the chain is not allowed to avoid having clients start to depend on nodes having full transaction indexes (which modern nodes do not). + +GetData inherits from Inventory, as they both have the same structure. + +### Ping + +Sent to another peer mainly to check the connection is still alive. + +### Pong + +Sent in response to a `ping` message. + +### Address and GetAddresses + +Provides information on known nodes of the network. `GetAddresses` is used to query another peer for known addresses. + +### GetHeaders and Headers + +`getheaders` allows a peer to query another about blockheaders. `headers` is sent in response to a `getheaders` message, containing information about block headers. + +### GetBlocks and Block + +Same as `getheaders` and `headers`, but the response comes one block at the time. + +### Transaction + +Message that contains a transaction. diff --git a/lib/messages.js b/lib/messages.js index c7a60f1..6d55a03 100644 --- a/lib/messages.js +++ b/lib/messages.js @@ -61,7 +61,7 @@ var parseMessage = function(network, dataBuffer) { module.exports.parseMessage = parseMessage; /** - * @desc Internal function that discards data until founds the next message. + * @desc Internal function that discards data until another message is found. * @name P2P.Message#discardUntilNextMessage */ function discardUntilNextMessage(network, dataBuffer) { @@ -162,7 +162,10 @@ Message.prototype.serialize = function(network) { module.exports.Message = Message; /** - * Version Message + * The version message(`ver`) is used on connection creation, to advertise + * the type of node.The remote node will respond with its version, and no + * communication is possible until both peers have exchanged their versions. + * By default, bitcore advertises itself as named `bitcore:0.8`. * * @name P2P.Message.Version * @param{string} subversion - version of the client @@ -171,20 +174,53 @@ module.exports.Message = Message; function Version(subversion, nonce) { this.command = 'version'; this.version = PROTOCOL_VERSION; - this.subversion = subversion || '/BitcoinX:0.1/'; + this.subversion = subversion || '/bitcore:0.8/'; this.nonce = nonce || CONNECTION_NONCE; } util.inherits(Version, Message); Version.prototype.fromBuffer = function(payload) { var parser = new BufferReader(payload); + + /** + * @type {number} + * @desc The version of the bitcoin protocol + */ this.version = parser.readUInt32LE(); + /** + * @type {BN} + * @desc A mapbit with service bits: what features are supported by the peer + */ this.services = parser.readUInt64LEBN(); + /** + * @type {BN} + * @desc The time this message was sent + */ this.timestamp = parser.readUInt64LEBN(); + /** + * @type {Buffer} + * @desc IPv4/6 address of the interface used to connect to this peer + */ this.addr_me = parser.read(26); + /** + * @type {Buffer} + * @desc IPv4/6 address of the peer + */ this.addr_you = parser.read(26); + /** + * @type {Buffer} + * @desc A random number + */ this.nonce = parser.read(8); + /** + * @desc A random number + * @type {string} + */ this.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(); return this; @@ -208,13 +244,20 @@ Version.prototype.getPayload = function() { module.exports.Version = Message.COMMANDS.version = Version; /** - * Inv Message + * From the bitcoin protocol spec: "Allows a node to advertise its knowledge of + * one or more objects. It can be received unsolicited, or in reply to + * getblocks.". * * @name P2P.Message.Inventory * @param{Array} inventory - reported elements */ function Inventory(inventory) { this.command = 'inv'; + /** + * @name P2P.Message.Inventory.inventory + * @desc An array of objects with `{type: int, hash: buffer}` signature + * @type {Array.Buffer} + */ this.inventory = inventory || []; } util.inherits(Inventory, Message); @@ -247,7 +290,14 @@ Inventory.prototype.getPayload = function() { module.exports.Inventory = Message.COMMANDS.inv = Inventory; /** - * Getdata Message + * getdata is used in response to inv, to retrieve the content of a specific + * object, and is usually sent after receiving an inv packet, after filtering + * known elements. It can be used to retrieve transactions, but only if they + * are in the memory pool or relay set - arbitrary access to transactions in the + * chain is not allowed to avoid having clients start to depend on nodes having + * full transaction indexes (which modern nodes do not). + * + * (taken from bitcoin's protocol spec) * * @name P2P.Message.GetData * @param{Array} inventory - requested elements @@ -261,13 +311,17 @@ util.inherits(GetData, Inventory); module.exports.GetData = GetData; /** - * Ping Message + * Sent to another peer mainly to check the connection is still alive. * * @name P2P.Message.Ping * @param{Buffer} nonce - a random 8 bytes buffer */ function Ping(nonce) { this.command = 'ping'; + /** + * @desc A random number that should be returned by the peer in a pong message + * @type {number} + */ this.nonce = nonce || CONNECTION_NONCE; } util.inherits(Ping, Message); @@ -284,13 +338,17 @@ Ping.prototype.getPayload = function() { module.exports.Ping = Message.COMMANDS.ping = Ping; /** - * Pong Message + * Sent in response to a Ping message * * @name P2P.Message.Pong * @param{Buffer} nonce - a random 8 bytes buffer */ function Pong(nonce) { this.command = 'pong'; + /** + * @desc A random number that must match the one sent in the corresponding `ping` message + * @type {number} + */ this.nonce = nonce || CONNECTION_NONCE; } @@ -298,13 +356,17 @@ util.inherits(Pong, Ping); module.exports.Pong = Message.COMMANDS.pong = Pong; /** - * Addr Message + * Message used to notify about known addresses. * * @name P2P.Message.Addressess * @param{Array} addresses - array of know addresses */ function Addresses(addresses) { this.command = 'addr'; + /** + * @type {Array.Buffer} + * @desc An array of ipv4/6 addresses + */ this.addresses = addresses || []; } util.inherits(Addresses, Message); @@ -364,7 +426,7 @@ Addresses.prototype.getPayload = function() { module.exports.Addresses = Message.COMMANDS.addr = Addresses; /** - * GetAddr Message + * Query another node for known IPV4/6 addresses. * * @name P2P.Message.GetAddresses */ @@ -376,7 +438,7 @@ util.inherits(GetAddresses, Message); module.exports.GetAddresses = Message.COMMANDS.getaddr = GetAddresses; /** - * Verack Message + * Finishes the connection handshake started by the `ver` message. * * @name P2P.Message.VerAck */ @@ -388,7 +450,8 @@ util.inherits(VerAck, Message); module.exports.VerAck = Message.COMMANDS.verack = VerAck; /** - * Reject Message + * A reject message should be sent when a message is not supported or + * interpreted as invalid. * * @name P2P.Message.Reject */ @@ -402,7 +465,7 @@ util.inherits(Reject, Message); module.exports.Reject = Message.COMMANDS.reject = Reject; /** - * Alert Message + * Used to send a message signed by a developer of the bitcoin project. * * @name P2P.Message.Alert */ @@ -434,13 +497,18 @@ Alert.prototype.getPayload = function() { module.exports.Alert = Message.COMMANDS.alert = Alert; /** - * Headers Message + * Sent in response to a `getheaders` message. It contains information about + * block headers. * * @name P2P.Message.Headers * @param{Array} blockheaders - array of block headers */ function Headers(blockheaders) { this.command = 'headers'; + /** + * @type {Array.BlockHeader} + * @desc An array of `BlockHeader` + */ this.headers = blockheaders || []; } util.inherits(Headers, Message); @@ -473,13 +541,18 @@ Headers.prototype.getPayload = function() { module.exports.Headers = Message.COMMANDS.headers = Headers; /** - * Block Message + * Contains information about a Block * * @name P2P.Message.Block - * @param{Block} block + * @param {Block} block */ function Block(block) { this.command = 'block'; + + /** + * @type {Block} + * The + */ this.block = block; } util.inherits(Block, Message); @@ -496,13 +569,16 @@ Block.prototype.getPayload = function() { module.exports.Block = Message.COMMANDS.block = Block; /** - * Tx Message + * Contains information about a transaction * * @name P2P.Message.Transaction * @param{Transaction} transaction */ function Transaction(transaction) { this.command = 'tx'; + /** + * @type {Transaction} + */ this.transaction = transaction; } util.inherits(Transaction, Message); @@ -519,7 +595,9 @@ Transaction.prototype.getPayload = function() { module.exports.Transaction = Message.COMMANDS.tx = Transaction; /** - * Getblocks Message + * Query another peer about blocks. It can query for multiple block hashes, + * and the response will contain all the chains of blocks starting from those + * hashes. * * @name P2P.Message.GetBlocks * @param{Array} starts - array of buffers with the starting block hashes @@ -527,8 +605,18 @@ module.exports.Transaction = Message.COMMANDS.tx = Transaction; */ function GetBlocks(starts, stop) { this.command = 'getblocks'; + /** + * @type {number} + */ this.version = PROTOCOL_VERSION; + /** + * @type {Array.Buffer} + */ this.starts = starts || []; + /** + * @type {Array.Buffer} + * @desc Hashes to limit the amount of blocks to be sent + */ this.stop = stop || BufferUtil.NULL_HASH; } util.inherits(GetBlocks, Message); @@ -570,7 +658,7 @@ GetBlocks.prototype.getPayload = function() { module.exports.GetBlocks = Message.COMMANDS.getblocks = GetBlocks; /** - * Getheaders Message + * Request block headers starting from a hash * * @name P2P.Message.GetHeaders * @param{Array} starts - array of buffers with the starting block hashes @@ -578,8 +666,17 @@ module.exports.GetBlocks = Message.COMMANDS.getblocks = GetBlocks; */ function GetHeaders(starts, stop) { this.command = 'getheaders'; + /** + * @type {number} + */ this.version = PROTOCOL_VERSION; + /** + * @type {Array.Buffer} + */ this.starts = starts || []; + /** + * @type {Array.Buffer} + */ this.stop = stop || BufferUtil.NULL_HASH; } @@ -587,7 +684,7 @@ util.inherits(GetHeaders, GetBlocks); module.exports.GetHeaders = Message.COMMANDS.getheaders = GetHeaders; /** - * GetMempool Message + * Request for transactions on the mempool * * @name P2P.Message.GetMempool */