diff --git a/stateless/tree_from_witness.nim b/stateless/tree_from_witness.nim index ef093f2b0..b8345e168 100644 --- a/stateless/tree_from_witness.nim +++ b/stateless/tree_from_witness.nim @@ -1,7 +1,7 @@ import faststreams/input_stream, eth/[common, rlp], stint, stew/endians2, eth/trie/[db, trie_defs], nimcrypto/[keccak, hash], - ./witness_types, stew/byteutils + ./witness_types, stew/byteutils, ../nimbus/constants type DB = TrieDatabaseRef @@ -102,6 +102,10 @@ proc toNodeKey(z: openArray[byte]): NodeKey = result.data = keccak(z).data result.usedBytes = 32 +proc writeCode(t: var TreeBuilder, code: openArray[byte]): Hash256 = + result = keccak(code) + put(t.db, result.data, code) + proc branchNode(t: var TreeBuilder, depth: int): NodeKey proc extensionNode(t: var TreeBuilder, depth: int): NodeKey proc accountNode(t: var TreeBuilder, depth: int): NodeKey @@ -156,16 +160,22 @@ proc branchNode(t: var TreeBuilder, depth: int): NodeKey = debugEcho "DEPTH: ", depth debugEcho "result: ", result.data.toHex, " vs. ", hash.data.toHex -func hexPrefix(r: var RlpWriter, x: openArray[byte], nibblesLen: int) = +func hexPrefix(r: var RlpWriter, x: openArray[byte], nibblesLen: int, isLeaf: static[bool] = false) = var bytes: array[33, byte] - if (nibblesLen mod 2) == 0: - bytes[0] = 0.byte + if (nibblesLen mod 2) == 0: # even + when isLeaf: + bytes[0] = 0b0010_0000.byte + else: + bytes[0] = 0.byte var i = 1 for y in x: bytes[i] = y inc i - else: - bytes[0] = 0b0001_0000.byte or (x[0] shr 4) + else: # odd + when isLeaf: + bytes[0] = 0b0011_0000.byte or (x[0] shr 4) + else: + bytes[0] = 0b0001_0000.byte or (x[0] shr 4) var last = nibblesLen div 2 for i in 1..last: bytes[i] = (x[i-1] shl 4) or (x[i] shr 4) @@ -210,19 +220,32 @@ proc accountNode(t: var TreeBuilder, depth: int): NodeKey = let readDepth = t.readByte.int doAssert(readDepth == depth, "accountNode " & $readDepth & " vs. " & $depth) - #[let nodeType = AccountType(t.readByte) + let accountType = AccountType(t.readByte) let nibblesLen = 64 - depth - let pathNibbles = @(t.read(nibblesLen div 2 + nibblesLen mod 2)) - let address = toAddress(t.read(20)) - let balance = UInt256.fromBytesBE(t.read(32), false) - # TODO: why nonce must be 32 bytes, isn't 64 bit uint enough? - let nonce = UInt256.fromBytesBE(t.read(32), false) - if nodeType == ExtendedAccountType: + var r = initRlpList(2) + r.hexPrefix(t.read(nibblesLen div 2 + nibblesLen mod 2), nibblesLen, true) + + #let address = toAddress(t.read(20)) + var acc = Account( + balance: UInt256.fromBytesBE(t.read(32), false), + # TODO: why nonce must be 32 bytes, isn't 64 bit uint enough? + nonce: UInt256.fromBytesBE(t.read(32), false).truncate(AccountNonce) + ) + + if accountType == SimpleAccountType: + acc.codeHash = blankStringHash + acc.storageRoot = emptyRlpHash + else: let codeLen = t.readU32() - let code = @(t.read(codeLen)) + if codeLen > EIP170_CODE_SIZE_LIMIT: + raise newException(ValueError, "code len exceed EIP170 code size limit") + acc.codeHash = t.writeCode(t.read(codeLen.int)) + # switch to account storage parsing mode # and reset the depth - t.treeNode(0, accountMode = true)]# + let storageRoot = t.treeNode(0, accountMode = true) + doAssert(storageRoot.usedBytes == 32) + acc.storageRoot.data = storageRoot.data proc accountStorageLeafNode(t: var TreeBuilder, depth: int): NodeKey = assert(depth < 65) diff --git a/stateless/witness_from_tree.nim b/stateless/witness_from_tree.nim index 3b93abf30..d441f9f49 100644 --- a/stateless/witness_from_tree.nim +++ b/stateless/witness_from_tree.nim @@ -87,6 +87,11 @@ proc writeBranchNode(wb: var WitnessBuilder, mask: uint, depth: int, node: openA when defined(debugHash): wb.output.append(keccak(node).data) +proc writeHashNode(wb: var WitnessBuilder, node: openArray[byte]) = + # write type + wb.output.append(HashNodeType.byte) + wb.output.append(node) + proc writeAccountNode(wb: var WitnessBuilder, acc: Account, nibbles: NibblesSeq, node: openArray[byte], depth: int) = # write type wb.output.append(AccountNodeType.byte) @@ -96,30 +101,34 @@ proc writeAccountNode(wb: var WitnessBuilder, acc: Account, nibbles: NibblesSeq, when defined(debugDepth): wb.output.append(depth.byte) - #EIP170_CODE_SIZE_LIMIT - doAssert(nibbles.len == 64 - depth) - let accountType = if acc.codeHash == blankStringHash or acc.storageRoot == emptyRlpHash: SimpleAccountType + let accountType = if acc.codeHash == blankStringHash and acc.storageRoot == emptyRlpHash: SimpleAccountType else: ExtendedAccountType - #wb.output.append(accountType.byte) - #wb.writeNibbles(nibbles, false) + wb.output.append(accountType.byte) + wb.writeNibbles(nibbles, false) #wb.output.append(acc.address) - #wb.output.append(acc.balance.toBytesBE) - #wb.output.append(acc.nonce.u256.toBytesBE) + wb.output.append(acc.balance.toBytesBE) + wb.output.append(acc.nonce.u256.toBytesBE) - #if accountType == ExtendedAccountType: + if accountType == ExtendedAccountType: + if acc.codeHash != blankStringHash: + let code = get(wb.db, acc.codeHash.data) + if code.len > EIP170_CODE_SIZE_LIMIT: + raise newException(ValueError, "code len exceed EIP170 code size limit") + wb.writeU32(code.len.uint32) + wb.output.append(code) + else: + wb.writeU32(0'u32) + + if acc.storageRoot != emptyRlpHash: + wb.writeHashNode(acc.storageRoot.data) + else: + wb.writeHashNode(emptyRlpHash.data) #0x00 pathnibbles: address:
balance: nonce: #0x01 pathnibbles: address:
balance: nonce: bytecode: storage: - # := len: b:^len - -proc writeHashNode(wb: var WitnessBuilder, node: openArray[byte]) = - # write type - wb.output.append(HashNodeType.byte) - wb.output.append(node) - proc writeShortNode(wb: var WitnessBuilder, node: openArray[byte], depth: int) = var nodeRlp = rlpFromBytes node if not nodeRlp.hasData or nodeRlp.isEmpty: return @@ -127,7 +136,7 @@ proc writeShortNode(wb: var WitnessBuilder, node: openArray[byte], depth: int) = of 2: let (isLeaf, k) = nodeRlp.extensionNodeKey if isLeaf: - let acc = nodeRlp.listElem(1).toBytes.decode(Account) + let acc = nodeRlp.listElem(1).toBytes.decode(Account) writeAccountNode(wb, acc, k, node, depth) else: # why this short extension node have no