From 73d2ad393a7d10551e77a257a6aa537342f8ecff Mon Sep 17 00:00:00 2001 From: Kagami Hiiragi Date: Fri, 16 Jan 2015 00:00:27 +0300 Subject: [PATCH] Implement inv_vect, inv --- README.md | 5 +++-- lib/messages.js | 46 ++++++++++++++++++++++++++++++++++++++++++++-- lib/structs.js | 17 +++++++++++++++++ test.js | 36 +++++++++++++++++++++++++++++++----- 4 files changed, 95 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e8667a2..f4ab98e 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ API documentation is available [here](https://bitchan.github.io/bitmessage/docs/ ## Feature matrix (both Browser and Node) -- [x] crypto +- [x] Crypto - [x] SHA-512 - [x] SHA-256 - [x] RIPEMD-160 @@ -31,6 +31,7 @@ API documentation is available [here](https://bitchan.github.io/bitmessage/docs/ - [x] var_str - [x] var_int_list - [x] net_addr + - [x] inv_vect - [x] encrypted - [x] message encodings - [x] service features @@ -39,7 +40,7 @@ API documentation is available [here](https://bitchan.github.io/bitmessage/docs/ - [x] version - [x] verack - [x] addr - - [ ] inv + - [x] inv - [ ] getdata - [ ] error - [ ] object diff --git a/lib/messages.js b/lib/messages.js index edc34f0..f738caf 100644 --- a/lib/messages.js +++ b/lib/messages.js @@ -12,7 +12,7 @@ var UserAgent = require("./user-agent"); var util = require("./util"); /** - * Version message. + * `version` message. * @see {@link https://bitmessage.org/wiki/Protocol_specification#version} * @namespace */ @@ -99,7 +99,7 @@ exports.version = { }; /** - * Addresses message. Provide information on known nodes of the network. + * `addr` message. Provide information on known nodes of the network. * @see {@link https://bitmessage.org/wiki/Protocol_specification#addr} * @namespace */ @@ -138,3 +138,45 @@ exports.addr = { return Buffer.concat([structs.var_int.encode(addrs.length), addrsBuf]); }, }; + +/** + * `inv` message. Allows a node to advertise its knowledge of one or + * more objects. + * @see {@link https://bitmessage.org/wiki/Protocol_specification#inv} + * @namespace + */ +exports.inv = { + /** + * Decode `inv` payload. + * @param {Buffer} buf - Buffer that starts with encoded `inv` payload + * @return {Object} Decoded `inv` structure. + */ + decode: function(buf) { + var decoded = structs.var_int.decode(buf); + var listLength = decoded.value; + assert(listLength <= 50000, "Too many inventory entires"); + var length = decoded.length + listLength * 32; + assert(buf.length >= length, "Buffer is too small"); + var rest = decoded.rest; + var inventory = new Array(listLength); + for (var i = 0; i < listLength; i++) { + inventory[i] = rest.slice(i*32, (i+1)*32); + } + return { + inventory: inventory, + // Real data length. + length: length, + }; + }, + + /** + * Encode `inv` payload. + * @param {Buffer[]} inventory - Inventory vectors (encoded) + * @return {Buffer} Encoded `inv` payload. + */ + encode: function(inventory) { + assert(inventory.length <= 50000, "Too many inventory entires"); + var invBuf = Buffer.concat(inventory); + return Buffer.concat([structs.var_int.encode(inventory.length), invBuf]); + }, +}; diff --git a/lib/structs.js b/lib/structs.js index 8b8d21e..73d0a11 100644 --- a/lib/structs.js +++ b/lib/structs.js @@ -417,6 +417,23 @@ exports.net_addr = { }, }; +/** + * Inventory vector. + * @see {@link https://bitmessage.org/wiki/Protocol_specification#Inventory_Vectors} + * @namespace + */ +// Only encode operation is defined because decode is impossible. +exports.inv_vect = { + /** + * Encode inventory vector. + * @param {Buffer} buf - Payload to calculate inventory vector for + * @return {Buffer} Encoded `inv_vect`. + */ + encode: function(buf) { + return bmcrypto.sha512(bmcrypto.sha512(buf)).slice(0, 32); + }, +}; + var SECP256K1_TYPE = 714; /** diff --git a/test.js b/test.js index cffaa96..44c601b 100644 --- a/test.js +++ b/test.js @@ -12,6 +12,7 @@ var var_int = structs.var_int; var var_str = structs.var_str; var var_int_list = structs.var_int_list; var net_addr = structs.net_addr; +var inv_vect = structs.inv_vect; var encrypted = structs.encrypted; var messageEncodings = structs.messageEncodings; var serviceFeatures = structs.serviceFeatures; @@ -19,6 +20,7 @@ var pubkeyFeatures = structs.pubkeyFeatures; var messages = bitmessage.messages; var version = messages.version; var addr = messages.addr; +var inv = messages.inv; var WIF = bitmessage.WIF; var POW = bitmessage.POW; var Address = bitmessage.Address; @@ -225,7 +227,13 @@ describe("Common structures", function() { }); }); - describe("Encrypted", function() { + describe("inv_vect", function() { + it("should encode", function() { + expect(inv_vect.encode("test").toString("hex")).to.equal("faadcaf60afd35dfcdb5e9ea0d0a0531f6338c62187cff37a1efe11f1d41a348"); + }); + }); + + describe("encrypted", function() { it("should encode and decode", function() { var iv = Buffer(16); var ephemPublicKey = Buffer(65); @@ -249,7 +257,7 @@ describe("Common structures", function() { }); }); - describe("Message encodings", function() { + describe("message encodings", function() { it("should decode", function() { expect(messageEncodings.decode(Buffer([2])).value).to.equal(messageEncodings.SIMPLE); }); @@ -259,7 +267,7 @@ describe("Common structures", function() { }); }); - describe("Service features", function() { + describe("service features", function() { it("should decode", function() { expect(serviceFeatures.decode(Buffer("0000000000000001", "hex"))).to.have.members([serviceFeatures.NODE_NETWORK]); }); @@ -270,7 +278,7 @@ describe("Common structures", function() { }); }); - describe("Pubkey features", function() { + describe("pubkey features", function() { it("should decode", function() { expect(pubkeyFeatures.decode(Buffer("c0000000", "hex"))).to.have.members([pubkeyFeatures.DOES_ACK, pubkeyFeatures.INCLUDE_DESTINATION]); }); @@ -326,6 +334,24 @@ describe("Message types", function() { expect(addr.decode.bind(null, var_int.encode(2000))).to.throw(/too many/i); }); }); + + describe("inv", function() { + it("should encode and decode", function() { + var vect1 = inv_vect.encode(Buffer("test")); + var vect2 = inv_vect.encode(Buffer("test2")); + var inventory = [vect1, vect2]; + var res = inv.decode(inv.encode(inventory)); + expect(res.inventory.length).to.equal(2); + expect(bufferEqual(res.inventory[0], vect1)).to.be.true; + expect(bufferEqual(res.inventory[1], vect2)).to.be.true; + expect(res.length).to.equal(65); + }); + + it("shouldn't encode/decode more than 1000 entires", function() { + expect(inv.encode.bind(null, Array(60000))).to.throw(/too many/i); + expect(inv.decode.bind(null, var_int.encode(60000))).to.throw(/too many/i); + }); + }); }); describe("WIF", function() { @@ -447,7 +473,7 @@ describe("High-level classes", function() { } }); - describe("User Agent", function() { + describe("UserAgent", function() { var pybm = {name: "PyBitmessage", version: "0.4.4"}; var bnode = {name: "bitchan-node", version: "0.0.1"}; var bweb = {name: "bitchan-web"};