implement account serializer and deserializer

This commit is contained in:
andri lim 2020-04-28 14:27:55 +07:00
parent a540b8cbeb
commit 2ae02fd629
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
2 changed files with 63 additions and 31 deletions

View File

@ -1,7 +1,7 @@
import import
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 ./witness_types, stew/byteutils, ../nimbus/constants
type type
DB = TrieDatabaseRef DB = TrieDatabaseRef
@ -102,6 +102,10 @@ proc toNodeKey(z: openArray[byte]): NodeKey =
result.data = keccak(z).data result.data = keccak(z).data
result.usedBytes = 32 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 branchNode(t: var TreeBuilder, depth: int): NodeKey
proc extensionNode(t: var TreeBuilder, depth: int): NodeKey proc extensionNode(t: var TreeBuilder, depth: int): NodeKey
proc accountNode(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 "DEPTH: ", depth
debugEcho "result: ", result.data.toHex, " vs. ", hash.data.toHex 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] var bytes: array[33, byte]
if (nibblesLen mod 2) == 0: if (nibblesLen mod 2) == 0: # even
bytes[0] = 0.byte when isLeaf:
bytes[0] = 0b0010_0000.byte
else:
bytes[0] = 0.byte
var i = 1 var i = 1
for y in x: for y in x:
bytes[i] = y bytes[i] = y
inc i inc i
else: else: # odd
bytes[0] = 0b0001_0000.byte or (x[0] shr 4) 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 var last = nibblesLen div 2
for i in 1..last: for i in 1..last:
bytes[i] = (x[i-1] shl 4) or (x[i] shr 4) 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 let readDepth = t.readByte.int
doAssert(readDepth == depth, "accountNode " & $readDepth & " vs. " & $depth) doAssert(readDepth == depth, "accountNode " & $readDepth & " vs. " & $depth)
#[let nodeType = AccountType(t.readByte) let accountType = AccountType(t.readByte)
let nibblesLen = 64 - depth let nibblesLen = 64 - depth
let pathNibbles = @(t.read(nibblesLen div 2 + nibblesLen mod 2)) var r = initRlpList(2)
let address = toAddress(t.read(20)) r.hexPrefix(t.read(nibblesLen div 2 + nibblesLen mod 2), nibblesLen, true)
let balance = UInt256.fromBytesBE(t.read(32), false)
# TODO: why nonce must be 32 bytes, isn't 64 bit uint enough? #let address = toAddress(t.read(20))
let nonce = UInt256.fromBytesBE(t.read(32), false) var acc = Account(
if nodeType == ExtendedAccountType: 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 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 # switch to account storage parsing mode
# and reset the depth # 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 = proc accountStorageLeafNode(t: var TreeBuilder, depth: int): NodeKey =
assert(depth < 65) assert(depth < 65)

View File

@ -87,6 +87,11 @@ proc writeBranchNode(wb: var WitnessBuilder, mask: uint, depth: int, node: openA
when defined(debugHash): when defined(debugHash):
wb.output.append(keccak(node).data) 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) = proc writeAccountNode(wb: var WitnessBuilder, acc: Account, nibbles: NibblesSeq, node: openArray[byte], depth: int) =
# write type # write type
wb.output.append(AccountNodeType.byte) wb.output.append(AccountNodeType.byte)
@ -96,30 +101,34 @@ proc writeAccountNode(wb: var WitnessBuilder, acc: Account, nibbles: NibblesSeq,
when defined(debugDepth): when defined(debugDepth):
wb.output.append(depth.byte) wb.output.append(depth.byte)
#EIP170_CODE_SIZE_LIMIT
doAssert(nibbles.len == 64 - depth) 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 else: ExtendedAccountType
#wb.output.append(accountType.byte) wb.output.append(accountType.byte)
#wb.writeNibbles(nibbles, false) wb.writeNibbles(nibbles, false)
#wb.output.append(acc.address) #wb.output.append(acc.address)
#wb.output.append(acc.balance.toBytesBE) wb.output.append(acc.balance.toBytesBE)
#wb.output.append(acc.nonce.u256.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:<Nibbles(64-d)> address:<Address> balance:<Bytes32> nonce:<Bytes32> #0x00 pathnibbles:<Nibbles(64-d)> address:<Address> balance:<Bytes32> nonce:<Bytes32>
#0x01 pathnibbles:<Nibbles(64-d)> address:<Address> balance:<Bytes32> nonce:<Bytes32> bytecode:<Bytecode> storage:<Tree_Node(0,1)> #0x01 pathnibbles:<Nibbles(64-d)> address:<Address> balance:<Bytes32> nonce:<Bytes32> bytecode:<Bytecode> storage:<Tree_Node(0,1)>
#<Bytecode> := len:<U32> b:<Byte>^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) = proc writeShortNode(wb: var WitnessBuilder, node: openArray[byte], depth: int) =
var nodeRlp = rlpFromBytes node var nodeRlp = rlpFromBytes node
if not nodeRlp.hasData or nodeRlp.isEmpty: return if not nodeRlp.hasData or nodeRlp.isEmpty: return