2019-02-05 12:01:10 +00:00
|
|
|
import
|
|
|
|
unittest, strutils,
|
2019-07-07 09:55:17 +00:00
|
|
|
stew/ranges/bitranges, eth/rlp/types, nimcrypto/[keccak, hash],
|
2019-02-05 12:01:10 +00:00
|
|
|
eth/trie/[binaries, trie_utils],
|
2019-02-14 22:40:23 +00:00
|
|
|
./testutils
|
2019-02-05 12:01:10 +00:00
|
|
|
|
|
|
|
proc parseBitVector(x: string): BitRange =
|
|
|
|
result = genBitVec(x.len)
|
|
|
|
for i, c in x:
|
|
|
|
result[i] = (c == '1')
|
|
|
|
|
|
|
|
const
|
|
|
|
commonPrefixData = [
|
|
|
|
(@[0b0000_0000.byte], @[0b0000_0000.byte], 8),
|
|
|
|
(@[0b0000_0000.byte], @[0b1000_0000.byte], 0),
|
|
|
|
(@[0b1000_0000.byte], @[0b1100_0000.byte], 1),
|
|
|
|
(@[0b0000_0000.byte], @[0b0100_0000.byte], 1),
|
|
|
|
(@[0b1110_0000.byte], @[0b1100_0000.byte], 2),
|
|
|
|
(@[0b0000_1111.byte], @[0b1111_1111.byte], 0)
|
|
|
|
]
|
|
|
|
|
|
|
|
suite "binaries utils":
|
|
|
|
|
|
|
|
test "get common prefix length":
|
|
|
|
for c in commonPrefixData:
|
|
|
|
var
|
|
|
|
c0 = c[0]
|
|
|
|
c1 = c[1]
|
|
|
|
let actual_a = getCommonPrefixLength(c0.bits, c1.bits)
|
|
|
|
let actual_b = getCommonPrefixLength(c1.bits, c0.bits)
|
|
|
|
let expected = c[2]
|
|
|
|
check actual_a == actual_b
|
|
|
|
check actual_a == expected
|
|
|
|
|
|
|
|
const
|
|
|
|
None = ""
|
|
|
|
parseNodeData = {
|
|
|
|
"\x00\x03\x04\x05\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p":
|
|
|
|
(0, "00110000010000000101", "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", false),
|
|
|
|
"\x01\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p":
|
|
|
|
(1, "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", false),
|
|
|
|
"\x02value": (2, None, "value", false),
|
|
|
|
"": (0, None, None, true),
|
|
|
|
"\x00\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p": (0, None, None, true),
|
|
|
|
"\x01\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p": (0, None, None, true),
|
|
|
|
"\x01\x02\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p":
|
|
|
|
(0, None, None, true),
|
|
|
|
"\x02": (0, None, None, true),
|
|
|
|
"\x03": (0, None, None, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
test "node parsing":
|
|
|
|
for c in parseNodeData:
|
|
|
|
let input = toRange(c[0])
|
|
|
|
let node = c[1]
|
|
|
|
let kind = TrieNodeKind(node[0])
|
|
|
|
let raiseError = node[3]
|
|
|
|
var res: TrieNode
|
|
|
|
|
|
|
|
if raiseError:
|
|
|
|
expect(InvalidNode):
|
|
|
|
res = parseNode(input)
|
|
|
|
else:
|
|
|
|
res = parseNode(input)
|
|
|
|
|
|
|
|
check(kind == res.kind)
|
|
|
|
case res.kind
|
|
|
|
of KV_TYPE:
|
|
|
|
check(res.keyPath == parseBitVector(node[1]))
|
|
|
|
check(res.child == toRange(node[2]))
|
|
|
|
of BRANCH_TYPE:
|
|
|
|
check(res.leftChild == toRange(node[2]))
|
|
|
|
check(res.rightChild == toRange(node[2]))
|
|
|
|
of LEAF_TYPE:
|
|
|
|
check(res.value == toRange(node[2]))
|
|
|
|
|
|
|
|
const
|
|
|
|
kvData = [
|
|
|
|
("0", "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", "\x00\x10\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", false),
|
|
|
|
("" , "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", None, true),
|
|
|
|
("0", "\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", None, true),
|
|
|
|
("1", "\x00\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", None, true),
|
|
|
|
("2", "", None, true)
|
|
|
|
]
|
|
|
|
|
|
|
|
test "kv node encoding":
|
|
|
|
for c in kvData:
|
|
|
|
let keyPath = parseBitVector(c[0])
|
|
|
|
let node = toRange(c[1])
|
|
|
|
let output = toBytes(c[2])
|
|
|
|
let raiseError = c[3]
|
|
|
|
|
|
|
|
if raiseError:
|
|
|
|
expect(ValidationError):
|
|
|
|
check output == encodeKVNode(keyPath, node)
|
|
|
|
else:
|
|
|
|
check output == encodeKVNode(keyPath, node)
|
|
|
|
|
|
|
|
const
|
|
|
|
branchData = [
|
|
|
|
("\xc8\x9e\xfd\xaaT\xc0\xf2\x0cz\xdfa(\x82\xdf\tP\xf5\xa9Qc~\x03\x07\xcd\xcbLg/)\x8b\x8b\xc6", "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p",
|
|
|
|
"\x01\xc8\x9e\xfd\xaaT\xc0\xf2\x0cz\xdfa(\x82\xdf\tP\xf5\xa9Qc~\x03\x07\xcd\xcbLg/)\x8b\x8b\xc6\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", false),
|
|
|
|
("", "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", None, true),
|
|
|
|
("\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", "\x01", None, true),
|
|
|
|
("\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p", "12345", None, true),
|
|
|
|
(repeat('\x01', 33), repeat('\x01', 32), None, true),
|
|
|
|
]
|
|
|
|
|
|
|
|
test "branch node encode":
|
|
|
|
for c in branchData:
|
|
|
|
let left = toRange(c[0])
|
|
|
|
let right = toRange(c[1])
|
|
|
|
let output = toBytes(c[2])
|
|
|
|
let raiseError = c[3]
|
|
|
|
|
|
|
|
if raiseError:
|
|
|
|
expect(ValidationError):
|
|
|
|
check output == encodeBranchNode(left, right)
|
|
|
|
else:
|
|
|
|
check output == encodeBranchNode(left, right)
|
|
|
|
|
|
|
|
const
|
|
|
|
leafData = [
|
|
|
|
("\x03\x04\x05", "\x02\x03\x04\x05", false),
|
|
|
|
("", None, true)
|
|
|
|
]
|
|
|
|
|
|
|
|
test "leaf node encode":
|
|
|
|
for c in leafData:
|
|
|
|
let raiseError = c[2]
|
|
|
|
if raiseError:
|
|
|
|
expect(ValidationError):
|
|
|
|
check toBytes(c[1]) == encodeLeafNode(toRange(c[0]))
|
|
|
|
else:
|
|
|
|
check toBytes(c[1]) == encodeLeafNode(toRange(c[0]))
|
|
|
|
|
|
|
|
test "random kv encoding":
|
|
|
|
let lengths = randList(int, randGen(1, 999), randGen(100, 100), unique = false)
|
|
|
|
for len in lengths:
|
|
|
|
var k = len
|
|
|
|
var bitvec = genBitVec(len)
|
|
|
|
var nodeHash = keccak256.digest(cast[ptr byte](k.addr), uint(sizeof(int))).toRange
|
|
|
|
var kvnode = encodeKVNode(bitvec, nodeHash).toRange
|
|
|
|
# first byte if KV_TYPE
|
|
|
|
# in the middle are 1..n bits of binary-encoded-keypath
|
|
|
|
# last 32 bytes are hash
|
|
|
|
var keyPath = decodeToBinKeypath(kvnode[1..^33])
|
|
|
|
check kvnode[0].ord == KV_TYPE.ord
|
|
|
|
check keyPath == bitvec
|
|
|
|
check kvnode[^32..^1] == nodeHash
|
|
|
|
|
|
|
|
test "optimized single bit keypath kvnode encoding":
|
|
|
|
var k = 1
|
|
|
|
var nodeHash = keccak256.digest(cast[ptr byte](k.addr), uint(sizeof(int))).toRange
|
|
|
|
var bitvec = genBitVec(1)
|
|
|
|
bitvec[0] = false
|
|
|
|
var kvnode = encodeKVNode(bitvec, nodeHash).toRange
|
|
|
|
var kp = decodeToBinKeypath(kvnode[1..^33])
|
|
|
|
|
|
|
|
var okv = encodeKVNode(false, nodeHash).toRange
|
|
|
|
check okv == kvnode
|
|
|
|
var okp = decodeToBinKeypath(kvnode[1..^33])
|
|
|
|
check okp == kp
|
|
|
|
check okp.len == 1
|
|
|
|
check okp == bitvec
|
|
|
|
|
|
|
|
bitvec[0] = true
|
|
|
|
kvnode = encodeKVNode(bitvec, nodeHash).toRange
|
|
|
|
kp = decodeToBinKeypath(kvnode[1..^33])
|
|
|
|
|
|
|
|
okv = encodeKVNode(true, nodeHash).toRange
|
|
|
|
check okv == kvnode
|
|
|
|
okp = decodeToBinKeypath(kvnode[1..^33])
|
|
|
|
check okp == kp
|
|
|
|
check okp.len == 1
|
|
|
|
check okp == bitvec
|