tidier readbytes exception

This commit is contained in:
andri lim 2020-04-29 16:59:38 +07:00
parent 41753a55e9
commit 6ccb2d65cd
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9

View File

@ -1,4 +1,5 @@
import import
typetraits,
faststreams/input_stream, eth/[common, rlp], stint, stew/endians2, faststreams/input_stream, eth/[common, rlp], stint, stew/endians2,
eth/trie/[db, trie_defs], nimcrypto/[keccak, hash], eth/trie/[db, trie_defs], nimcrypto/[keccak, hash],
./witness_types, stew/byteutils, ../nimbus/constants ./witness_types, stew/byteutils, ../nimbus/constants
@ -94,6 +95,18 @@ proc safeReadU32(t: var TreeBuilder): uint32 =
else: else:
raise newException(IOError, "Cannot read U32 from input stream") raise newException(IOError, "Cannot read U32 from input stream")
template safeReadEnum(t: var TreeBuilder, T: type): untyped =
let typ = t.safeReadByte.int
if typ < low(T).int or typ > high(T).int:
raise newException(ParsingError, "Wrong " & T.name & " value")
T(typ)
template safeReadBytes(t: var TreeBuilder, length: int, body: untyped) =
if t.readable(length):
body
else:
raise newException(ParsingError, "Failed when try to read " & $length & " bytes")
proc toKeccak(r: var NodeKey, x: openArray[byte]) {.inline.} = proc toKeccak(r: var NodeKey, x: openArray[byte]) {.inline.} =
r.data[0..31] = x[0..31] r.data[0..31] = x[0..31]
r.usedBytes = 32 r.usedBytes = 32
@ -113,6 +126,12 @@ proc toNodeKey(t: var TreeBuilder, z: openArray[byte]): NodeKey =
result.usedBytes = 32 result.usedBytes = 32
t.db.put(result.data, z) t.db.put(result.data, z)
proc forceSmallNodeKeyToHash(t: var TreeBuilder, r: NodeKey): NodeKey =
let hash = keccak(r.data.toOpenArray(0, r.usedBytes-1))
t.db.put(hash.data, r.data.toOpenArray(0, r.usedBytes-1))
result.data = hash.data
result.usedBytes = 32
proc writeCode(t: var TreeBuilder, code: openArray[byte]): Hash256 = proc writeCode(t: var TreeBuilder, code: openArray[byte]): Hash256 =
result = keccak(code) result = keccak(code)
put(t.db, result.data, code) put(t.db, result.data, code)
@ -160,11 +179,7 @@ proc buildForest*(t: var TreeBuilder): seq[KeccakHash] =
proc treeNode(t: var TreeBuilder, depth: int = 0, storageMode = false): NodeKey = proc treeNode(t: var TreeBuilder, depth: int = 0, storageMode = false): NodeKey =
assert(depth < 64) assert(depth < 64)
let typ = t.safeReadByte().int let nodeType = safeReadEnum(t, TrieNodeType)
if typ < low(TrieNodeType).int or typ > high(TrieNodeType).int:
raise newException(ParsingError, "Wrong trie node type")
let nodeType = TrieNodeType(typ)
case nodeType case nodeType
of BranchNodeType: result = t.branchNode(depth, storageMode) of BranchNodeType: result = t.branchNode(depth, storageMode)
of ExtensionNodeType: result = t.extensionNode(depth, storageMode) of ExtensionNodeType: result = t.extensionNode(depth, storageMode)
@ -177,11 +192,7 @@ proc treeNode(t: var TreeBuilder, depth: int = 0, storageMode = false): NodeKey
of HashNodeType: result = t.hashNode() of HashNodeType: result = t.hashNode()
if depth == 0 and result.usedBytes < 32: if depth == 0 and result.usedBytes < 32:
let hash = keccak(result.data.toOpenArray(0, result.usedBytes-1)) result = t.forceSmallNodeKeyToHash(result)
t.db.put(hash.data, result.data.toOpenArray(0, result.usedBytes-1))
result.data = hash.data
result.usedBytes = 32
proc branchNode(t: var TreeBuilder, depth: int, storageMode: bool): NodeKey = proc branchNode(t: var TreeBuilder, depth: int, storageMode: bool): NodeKey =
assert(depth < 64) assert(depth < 64)
@ -257,11 +268,7 @@ proc extensionNode(t: var TreeBuilder, depth: int, storageMode: bool): NodeKey =
let hash = toKeccak(t.read(32)) let hash = toKeccak(t.read(32))
assert(depth + nibblesLen < 65) assert(depth + nibblesLen < 65)
let typ = t.safeReadByte.int let nodeType = safeReadEnum(t, TrieNodeType)
if typ < low(TrieNodeType).int or typ > high(TrieNodeType).int:
raise newException(ParsingError, "Wrong trie node type")
let nodeType = TrieNodeType(typ)
case nodeType case nodeType
of BranchNodeType: r.append t.branchNode(depth + nibblesLen, storageMode) of BranchNodeType: r.append t.branchNode(depth + nibblesLen, storageMode)
of HashNodeType: r.append t.hashNode() of HashNodeType: r.append t.hashNode()
@ -286,52 +293,43 @@ proc accountNode(t: var TreeBuilder, depth: int): NodeKey =
let readDepth = t.safeReadByte().int let readDepth = t.safeReadByte().int
doAssert(readDepth == depth, "accountNode " & $readDepth & " vs. " & $depth) doAssert(readDepth == depth, "accountNode " & $readDepth & " vs. " & $depth)
let typ = t.safeReadByte.int let accountType = safeReadEnum(t, AccountType)
if typ < low(AccountType).int or typ > high(AccountType).int:
raise newException(ParsingError, "Wrong account type")
let accountType = AccountType(typ)
let nibblesLen = 64 - depth let nibblesLen = 64 - depth
var r = initRlpList(2) var r = initRlpList(2)
let pathLen = nibblesLen div 2 + nibblesLen mod 2 let pathLen = nibblesLen div 2 + nibblesLen mod 2
if t.readable(pathLen): safeReadBytes(t, pathLen):
r.hexPrefix(t.read(pathLen), nibblesLen, true) r.hexPrefix(t.read(pathLen), nibblesLen, true)
else:
raise newException(ParsingError, "Failed when read nibbles path")
# TODO: parse address # TODO: parse address
# let address = toAddress(t.read(20)) # let address = toAddress(t.read(20))
if not t.readable(64): safeReadBytes(t, 64):
raise newException(ParsingError, "Not enough bytes to read account") 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)
)
var acc = Account( if accountType == SimpleAccountType:
balance: UInt256.fromBytesBE(t.read(32), false), acc.codeHash = blankStringHash
# TODO: why nonce must be 32 bytes, isn't 64 bit uint enough? acc.storageRoot = emptyRlpHash
nonce: UInt256.fromBytesBE(t.read(32), false).truncate(AccountNonce)
)
if accountType == SimpleAccountType:
acc.codeHash = blankStringHash
acc.storageRoot = emptyRlpHash
else:
let codeLen = t.safeReadU32()
if wfEIP170 in t.flags and codeLen > EIP170_CODE_SIZE_LIMIT:
raise newException(ContractCodeError, "code len exceed EIP170 code size limit")
if t.readable(codeLen.int):
acc.codeHash = t.writeCode(t.read(codeLen.int))
else: else:
raise newException(ParsingError, "not enought bytes to read contract code") let codeLen = t.safeReadU32()
if wfEIP170 in t.flags and codeLen > EIP170_CODE_SIZE_LIMIT:
raise newException(ContractCodeError, "code len exceed EIP170 code size limit")
# switch to account storage parsing mode safeReadBytes(t, codeLen.int):
# and reset the depth acc.codeHash = t.writeCode(t.read(codeLen.int))
let storageRoot = t.treeNode(0, storageMode = true)
doAssert(storageRoot.usedBytes == 32) # switch to account storage parsing mode
acc.storageRoot.data = storageRoot.data # and reset the depth
let storageRoot = t.treeNode(0, storageMode = true)
doAssert(storageRoot.usedBytes == 32)
acc.storageRoot.data = storageRoot.data
r.append rlp.encode(acc)
r.append rlp.encode(acc)
let nodeRes = r.finish let nodeRes = r.finish
result = t.toNodeKey(nodeRes) result = t.toNodeKey(nodeRes)
@ -355,22 +353,18 @@ proc accountStorageLeafNode(t: var TreeBuilder, depth: int): NodeKey =
let nibblesLen = 64 - depth let nibblesLen = 64 - depth
var r = initRlpList(2) var r = initRlpList(2)
let pathLen = nibblesLen div 2 + nibblesLen mod 2 let pathLen = nibblesLen div 2 + nibblesLen mod 2
if not t.readable(pathLen): safeReadBytes(t, pathLen):
raise newException(ParsingError, "Enot enough bytes to read path nibbles") r.hexPrefix(t.read(pathLen), nibblesLen, true)
r.hexPrefix(t.read(pathLen), nibblesLen, true)
# TODO: parse key # TODO: parse key
# let key = @(t.read(32)) # let key = @(t.read(32))
# UInt256 -> BytesBE -> keccak # UInt256 -> BytesBE -> keccak
if not t.readable(32): safeReadBytes(t, 32):
raise newException(ParsingError, "Not enough bytes to read path storage value") let val = UInt256.fromBytesBE(t.read(32))
r.append rlp.encode(val)
let val = UInt256.fromBytesBE(t.read(32)) result = t.toNodeKey(r.finish)
r.append rlp.encode(val)
result = t.toNodeKey(r.finish)
proc hashNode(t: var TreeBuilder): NodeKey = proc hashNode(t: var TreeBuilder): NodeKey =
if not t.readable(32): safeReadBytes(t, 32):
raise newException(ParsingError, "Not enough bytes to read hash node") result.toKeccak(t.read(32))
result.toKeccak(t.read(32))