From fdb750f67e5c41829f145ddb0ee0c7767f3a7ebb Mon Sep 17 00:00:00 2001 From: andri lim Date: Wed, 29 Apr 2020 15:29:25 +0700 Subject: [PATCH] implement witness header encoding decoding and implement buildForest --- stateless/test_block_witness.nim | 2 +- stateless/test_witness_keys.nim | 2 +- stateless/tree_from_witness.nim | 44 +++++++++++++++++++++++++++++--- stateless/witness_from_tree.nim | 11 +++++++- stateless/witness_types.nim | 10 +++++--- 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/stateless/test_block_witness.nim b/stateless/test_block_witness.nim index 4ef23a431..b1422f7d8 100644 --- a/stateless/test_block_witness.nim +++ b/stateless/test_block_witness.nim @@ -40,7 +40,7 @@ proc testGetBranch(tester: Tester, rootHash: KeccakHash, testStatusIMPL: var Tes else: var tb = initTreeBuilder(witness, db, flags) - var root = tb.treeNode() + var root = tb.buildTree() check root.data == rootHash.data except ContractCodeError as e: debugEcho "CONTRACT CODE ERROR: ", e.msg diff --git a/stateless/test_witness_keys.nim b/stateless/test_witness_keys.nim index 16aec21d4..292a69e6e 100644 --- a/stateless/test_witness_keys.nim +++ b/stateless/test_witness_keys.nim @@ -67,7 +67,7 @@ proc runTest(numPairs: int) = var tb = initTreeBuilder(input, db, {wfEIP170}) else: var tb = initTreeBuilder(witness, db, {wfEIP170}) - var root = tb.treeNode() + var root = tb.buildTree() debugEcho "root: ", root.data.toHex debugEcho "rootHash: ", rootHash.data.toHex doAssert root.data == rootHash.data diff --git a/stateless/tree_from_witness.nim b/stateless/tree_from_witness.nim index bbc27eb37..5d0b8c5e6 100644 --- a/stateless/tree_from_witness.nim +++ b/stateless/tree_from_witness.nim @@ -60,6 +60,8 @@ when defined(useInputStream): template read(t: var TreeBuilder, len: int): auto = t.input.read(len) + template readable(t: var TreeBuilder): bool = + t.input.readable else: template readByte(t: var TreeBuilder): byte = let pos = t.pos @@ -69,9 +71,8 @@ else: template len(t: TreeBuilder): int = t.input.len - template peek(t: TreeBuilder): byte = - t.input.peek - t.input[t.pos] + template readable(t: var TreeBuilder): bool = + t.pos < t.input.len template read(t: var TreeBuilder, len: int): auto = let pos = t.pos @@ -115,8 +116,43 @@ proc extensionNode(t: var TreeBuilder, depth: int, storageMode: bool): NodeKey proc accountNode(t: var TreeBuilder, depth: int): NodeKey proc accountStorageLeafNode(t: var TreeBuilder, depth: int): NodeKey proc hashNode(t: var TreeBuilder): NodeKey +proc treeNode(t: var TreeBuilder, depth: int = 0, storageMode = false): NodeKey -proc treeNode*(t: var TreeBuilder, depth: int = 0, storageMode = false): NodeKey = +proc buildTree*(t: var TreeBuilder): KeccakHash = + let version = t.readByte().int + if version != BlockWitnessVersion.int: + raise newException(ParsingError, "Wrong block witness version") + + # one or more trees + + # we only parse one tree here + let metadataType = t.readByte().int + if metadataType != MetadataNothing.int: + raise newException(ParsingError, "This tree builder support no metadata") + + var res = treeNode(t) + if res.usedBytes != 32: + raise newException(ParsingError, "Buildtree should produce hash") + + result.data = res.data + +proc buildForest*(t: var TreeBuilder): seq[KeccakHash] = + let version = t.readByte().int + if version != BlockWitnessVersion.int: + raise newException(ParsingError, "Wrong block witness version") + + while t.readable: + let metadataType = t.readByte().int + if metadataType != MetadataNothing.int: + raise newException(ParsingError, "This tree builder support no metadata") + + var res = treeNode(t) + if res.usedBytes != 32: + raise newException(ParsingError, "Buildtree should produce hash") + + result.add KeccakHash(data: res.data) + +proc treeNode(t: var TreeBuilder, depth: int = 0, storageMode = false): NodeKey = assert(depth < 64) let nodeType = TrieNodeType(t.readByte) diff --git a/stateless/witness_from_tree.nim b/stateless/witness_from_tree.nim index 637e927c0..f178162ef 100644 --- a/stateless/witness_from_tree.nim +++ b/stateless/witness_from_tree.nim @@ -244,8 +244,17 @@ proc getBranchRecurseAux(wb: var WitnessBuilder, node: openArray[byte], path: Ni raise newException(CorruptedTrieDatabase, "HexaryTrie node with an unexpected number of children") -proc buildWitness*(wb: var WitnessBuilder; address: EthAddress): seq[byte] = +proc buildWitness*(wb: var WitnessBuilder; address: EthAddress, withVersion: bool = true): seq[byte] = + # witness version + wb.output.append(BlockWitnessVersion.byte) + + # one or more trees + + # we only output one tree + wb.output.append(MetadataNothing.byte) let key = keccak(address) var node = wb.db.get(wb.root.data) getBranchRecurseAux(wb, node, initNibbleRange(key.data), 0, false) + + # result result = wb.output.getOutput(seq[byte]) diff --git a/stateless/witness_types.nim b/stateless/witness_types.nim index 5dbd6ee41..dd1c8f9d5 100644 --- a/stateless/witness_types.nim +++ b/stateless/witness_types.nim @@ -15,9 +15,14 @@ type wfNoFlag wfEIP170 # fork >= Spurious Dragon + MetadataType* = enum + MetadataNothing + MetadataSomething + WitnessFlags* = set[WitnessFlag] ContractCodeError* = object of ValueError + ParsingError* = object of ValueError const StorageLeafNodeType* = AccountNodeType @@ -33,6 +38,5 @@ func branchMaskBitIsSet*(x: uint, i: int): bool {.inline.} = func constructBranchMask*(b1, b2: byte): uint {.inline.} = result = uint(b1) shl 8 or uint(b2) - if countOnes(result) < 2: - debugEcho "MASK: ", result - assert(countOnes(result) > 1) + if countOnes(result) < 2 or ((result and (not 0x1FFFF'u)) != 0): + raise newException(ParsingError, "Invalid branch mask pattern")