From 9b18f1d261c5fa3b4e909b8bbdedf99f1f541bbc Mon Sep 17 00:00:00 2001 From: yenda Date: Thu, 2 May 2019 10:47:49 +0200 Subject: [PATCH] [feature] add varint encoding/decoding Signed-off-by: yenda --- src/status_im/utils/varint.cljs | 54 ++++++++++++++++++++++ test/cljs/status_im/test/utils/varint.cljs | 28 +++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/status_im/utils/varint.cljs create mode 100644 test/cljs/status_im/test/utils/varint.cljs diff --git a/src/status_im/utils/varint.cljs b/src/status_im/utils/varint.cljs new file mode 100644 index 0000000000..9c4d099c03 --- /dev/null +++ b/src/status_im/utils/varint.cljs @@ -0,0 +1,54 @@ +(ns ^{:doc "Implementation of varint based on https://github.com/chrisdickinson/varint"} + status-im.utils.varint + (:require [status-im.utils.ethereum.abi-spec :as abi-spec] + [status-im.js-dependencies :as dependencies])) + +(def utils dependencies/web3-utils) + +(def most-significant-bit 0x80) +(def biggest-int-per-byte 0x7F) +(def biggest-int 2147483648) ;; 2^31 + +(defn encode [num] + (loop [num num + out []] + (if (>= num 128) + (recur (if (>= num biggest-int) + (/ num 128) + (bit-shift-right num 7)) + (conj out (bit-or (bit-and num 0xFF) + most-significant-bit))) + (conj out (bit-or num 0))))) + +(defn encode-hex [num] + (reduce (fn [hex current-bit] + (str hex + (.leftPad utils + (abi-spec/number-to-hex current-bit) + 2))) + "" + (encode num))) + +(defn add-b-to-res + [res b shift] + (+ res (if (< shift 28) + (bit-shift-left (bit-and b biggest-int-per-byte) + shift) + (* (bit-and b biggest-int-per-byte) + shift shift)))) + +(defn decode [buf] + (loop [res 0 + shift 0 + [b & rest-buf] buf] + (if (>= b most-significant-bit) + (recur (add-b-to-res res b shift) + (+ shift 7) + rest-buf) + (add-b-to-res res b shift)))) + +(defn decode-hex [hex] + (->> hex + (partition 2) + (mapv #(abi-spec/hex-to-number (apply str %))) + decode)) diff --git a/test/cljs/status_im/test/utils/varint.cljs b/test/cljs/status_im/test/utils/varint.cljs new file mode 100644 index 0000000000..f827c4f14f --- /dev/null +++ b/test/cljs/status_im/test/utils/varint.cljs @@ -0,0 +1,28 @@ +(ns status-im.test.utils.varint + (:require [cljs.test :refer-macros [deftest is testing]] + [status-im.utils.varint :as varint])) + +(deftest encode + (is (= (varint/encode-hex 0x0) + "0")) + (is (= (varint/encode-hex 0x70) + "70")) + (is (= (varint/encode-hex 0xe3) + "e301"))) + +(deftest decode + (is (= (varint/decode-hex "0") + 0x0)) + (is (= (varint/decode-hex "70") + 0x70)) + (is (= (varint/decode-hex "e301") + 0xe301))) + +(defn test-roundtrip [n] + (= (varint/decode-hex (varint/encode-hex n)) + n)) + +(deftest roundtrip + (is (test-roundtrip 0)) + (is (test-roundtrip 23948)) + (is (test-roundtrip 2684453)))