implement account serializer and deserializer
This commit is contained in:
parent
a540b8cbeb
commit
2ae02fd629
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue