From a3c4ebac7d5b6d525cacd4e87a462c364eb0ae30 Mon Sep 17 00:00:00 2001 From: Kagami Hiiragi Date: Fri, 2 Jan 2015 17:27:03 +0300 Subject: [PATCH] Implement var_int_list --- README.md | 19 +++---------------- lib/index.js | 2 ++ lib/struct.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ test.js | 44 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 89 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 778e78b..dbd15c1 100644 --- a/README.md +++ b/README.md @@ -35,23 +35,11 @@ With the help of browserify `bitmessage` provides different implementations for - [ ] HMAC-SHA-256 - [ ] Core structures - [x] var_int - - [x] encode - - [x] decode - - [ ] var_str - - [ ] encode - - [ ] decode - - [ ] var_int_list - - [ ] encode - - [ ] decode + - [x] var_str + - [x] var_int_list - [ ] inv_vect - - [ ] encode - - [ ] decode - [ ] net_addr - - [ ] encode - - [ ] decode - [ ] bitfield - - [ ] encode - - [ ] decode - [ ] High-level objects - [ ] Address - [x] encode @@ -63,8 +51,7 @@ With the help of browserify `bitmessage` provides different implementations for - [ ] encode - [ ] decode - [x] WIF - - [x] encode - - [x] decode +- [ ] POW - [ ] Parse PyBitmessage configs - [ ] decode keys.dat - [ ] decode knownnodes.dat diff --git a/lib/index.js b/lib/index.js index 87e3cb4..cc8d154 100644 --- a/lib/index.js +++ b/lib/index.js @@ -12,6 +12,8 @@ * platform and [node-int64](https://www.npmjs.com/package/node-int64) * for Browser. You may replace it with other library with the same API. */ +// TODO(Kagami): Find another JS implementation, it should be able to +// operate with `uint64_t` not just store it. exports.Int64 = require("int64-native"); /** Working with addresses. */ exports.Address = require("./address"); diff --git a/lib/struct.js b/lib/struct.js index fc8c1dc..84a71d0 100644 --- a/lib/struct.js +++ b/lib/struct.js @@ -35,6 +35,8 @@ var var_int = exports.var_int = { length = 5; break; case 255: + // TODO(Kagami): Should we still use native number if value is + // less than 2^53? var hi = buf.readUInt32BE(1); assert(hi !== 0, "Impractical var_int"); var lo = buf.readUInt32BE(5); @@ -120,6 +122,8 @@ exports.var_str = { decode: function(buf) { var decoded = var_int.decode(buf); var strLength = decoded.value; + // FIXME(Kagami): We will fail here if var_int value is bigger than + // 2^32. Though it will require ~4G of RAM so it's not that bad. // XXX(Kagami): Spec doesn't mention encoding, using UTF-8. var str = decoded.rest.slice(0, strLength).toString(); var rest = decoded.rest.slice(strLength); @@ -137,3 +141,43 @@ exports.var_str = { return Buffer.concat([var_int.encode(strBuf.length), strBuf]); }, }; + +/** + * var_int_list. + * @see {@link https://bitmessage.org/wiki/Protocol_specification#Variable_length_list_of_integers} + */ +exports.var_int_list = { + /** + * Decode var_int_list. + * @param {Buffer} buf - Buffer that starts with encoded var_int_list + * @return {{list: number[], length: number, rest: Buffer}} + * Decoded var_int_list structure. + */ + decode: function(buf) { + var decoded = var_int.decode(buf); + var listLength = decoded.value; + // FIXME(Kagami): We will fail here if var_int value is bigger than + // 2^32. Though such list would require more than 4G of RAM so it's + // not that bad. + var list = new Array(listLength); + var rest = decoded.rest; + var sumLength = decoded.length; + for (var i = 0; i < listLength; i++) { + decoded = var_int.decode(rest); + list[i] = decoded.value; + rest = decoded.rest; + sumLength += decoded.length; + } + return {list: list, length: sumLength, rest: rest} + }, + + /** + * Encode list of numbers into var_int_list. + * @param {number[]} list - A number list + * @return {Buffer} Encoded var_int_list. + */ + encode: function(list) { + var listBuf = Buffer.concat(list.map(var_int.encode)); + return Buffer.concat([var_int.encode(list.length), listBuf]); + }, +}; diff --git a/test.js b/test.js index a722f3c..9ef5ab6 100644 --- a/test.js +++ b/test.js @@ -9,6 +9,7 @@ var Address = bitmessage.Address; var wif = bitmessage.wif; var var_int = bitmessage.struct.var_int; var var_str = bitmessage.struct.var_str; +var var_int_list = bitmessage.struct.var_int_list; var bmcrypto = require("./lib/crypto"); describe("Core structures", function() { @@ -61,15 +62,20 @@ describe("Core structures", function() { describe("var_str", function() { it("should decode", function() { var res; + res = var_str.decode(Buffer("00", "hex")); + expect(res.str).to.equal(""); + expect(res.length).to.equal(1); + expect(res.rest.toString("hex")).to.equal(""); + res = var_str.decode(Buffer("0474657374", "hex")); expect(res.str).to.equal("test"); expect(res.length).to.equal(5); expect(res.rest.toString("hex")).to.equal(""); - res = var_str.decode(Buffer("00", "hex")); - expect(res.str).to.equal(""); - expect(res.length).to.equal(1); - expect(res.rest.toString("hex")).to.equal(""); + res = var_str.decode(Buffer("0474657374ffffff", "hex")); + expect(res.str).to.equal("test"); + expect(res.length).to.equal(5); + expect(res.rest.toString("hex")).to.equal("ffffff"); }); it("should encode", function() { @@ -77,6 +83,36 @@ describe("Core structures", function() { expect(var_str.encode("").toString("hex")).to.equal("00"); }); }); + + describe("var_int_list", function() { + it("should decode", function() { + var res; + res = var_int_list.decode(Buffer("00", "hex")); + expect(res.list).to.deep.equal([]); + expect(res.length).to.equal(1); + expect(res.rest.toString("hex")).to.equal(""); + + res = var_int_list.decode(Buffer("0501fd0400ff0004000000000000fd9c40fe000186a0", "hex")); + expect(res.length).to.equal(22); + expect(res.list.length).to.equal(5); + expect(res.list[0]).to.equal(1); + expect(res.list[1]).to.equal(1024); + expect(res.list[2] == 1125899906842624).to.be.true; + expect(res.list[3]).to.equal(40000); + expect(res.list[4]).to.equal(100000); + expect(res.rest.toString("hex")).to.equal(""); + + res = var_int_list.decode(Buffer("0501fd0400ff0004000000000000fd9c40fe000186a0ffffff", "hex")); + expect(res.length).to.equal(22); + expect(res.list.length).to.equal(5); + expect(res.rest.toString("hex")).to.equal("ffffff"); + }); + + it("should encode", function() { + expect(var_int_list.encode([]).toString("hex")).to.equal("00"); + expect(var_int_list.encode([1, 1024, 1125899906842624, 40000, 100000]).toString("hex")).to.equal("0501fd0400ff0004000000000000fd9c40fe000186a0"); + }); + }); }); describe("WIF", function() {