implement account serializer and deserializer
This commit is contained in:
parent
a540b8cbeb
commit
2ae02fd629
|
@ -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)
|
||||
|
|
|
@ -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:<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)>
|
||||
|
||||
#<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) =
|
||||
var nodeRlp = rlpFromBytes node
|
||||
if not nodeRlp.hasData or nodeRlp.isEmpty: return
|
||||
|
|
Loading…
Reference in New Issue