Cleanup stateless and block witness code. (#2295)

* Cleanup unneeded stateless and block witness code. Keeping MultiKeys which is used in the eth_getProofsByBlockNumber RPC endpoint which is needed for the Fluffy state network bridge.

* Rename generateWitness flag to collectWitnessData to better describe what the flag does. We only collect the keys of the touched accounts and storage slots but no block witness generation is supported for now.

* Move remaining stateless code into nimbus directory.

* Add vmstate parameter to ChainRef to fix test.

* Exclude *.in from check copyright year

---------

Co-authored-by: jangko <jangko128@gmail.com>
This commit is contained in:
web3-developer 2024-06-08 16:05:00 +08:00 committed by GitHub
parent 0524fe8fd1
commit db8c5b90bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
68 changed files with 182 additions and 6321 deletions

View File

@ -197,12 +197,6 @@ type
defaultValueDesc: ""
name: "verify-from" }: Option[uint64]
generateWitness* {.
hidden
desc: "Enable experimental generation and storage of block witnesses"
defaultValue: false
name: "generate-witness" }: bool
evm* {.
desc: "Load alternative EVM from EVMC-compatible shared library" & sharedLibText
defaultValue: ""

View File

@ -33,20 +33,21 @@ type
## Trigger extra validation, currently within `persistBlocks()`
## function only.
generateWitness: bool ##\
## Enable generation of block witness, currently within `persistBlocks()`
## function only.
verifyFrom: BlockNumber ##\
## First block to when `extraValidation` will be applied (only
## effective if `extraValidation` is true.)
vmState: BaseVMState
## If it's not nil, block validation will use this
## If it's nil, a new vmState state will be created.
# ------------------------------------------------------------------------------
# Public constructors
# ------------------------------------------------------------------------------
proc newChain*(com: CommonRef,
extraValidation: bool): ChainRef =
extraValidation: bool,
vmState = BaseVMState(nil)): ChainRef =
## Constructor for the `Chain` descriptor object.
## The argument `extraValidation` enables extra block
## chain validation if set `true`.
@ -54,6 +55,7 @@ proc newChain*(com: CommonRef,
com: com,
validateBlock: true,
extraValidation: extraValidation,
vmState: vmState
)
func newChain*(com: CommonRef): ChainRef =
@ -93,10 +95,6 @@ proc extraValidation*(c: ChainRef): bool =
## Getter
c.extraValidation
proc generateWitness*(c: ChainRef): bool =
## Getter
c.generateWitness
proc verifyFrom*(c: ChainRef): BlockNumber =
## Getter
c.verifyFrom
@ -121,11 +119,6 @@ proc `extraValidation=`*(c: ChainRef; extraValidation: bool) =
## extra block chain validation.
c.extraValidation = extraValidation
proc `generateWitness=`*(c: ChainRef; generateWitness: bool) =
## Setter. If set `true`, the assignment value `generateWitness` enables
## block witness generation.
c.generateWitness = generateWitness
proc `verifyFrom=`*(c: ChainRef; verifyFrom: BlockNumber) =
## Setter. The assignment value `verifyFrom` defines the first block where
## validation should start if the `Clique` field `extraValidation` was set

View File

@ -111,11 +111,8 @@ proc persistBlocksImpl(c: ChainRef; headers: openArray[BlockHeader];
body,
checkSealOK = false) # TODO: how to checkseal from here
if c.generateWitness:
vmState.generateWitness = true
let
validationResult = if c.validateBlock or c.generateWitness:
validationResult = if c.validateBlock:
vmState.processBlock(header, body)
else:
ValidationResult.OK
@ -129,21 +126,6 @@ proc persistBlocksImpl(c: ChainRef; headers: openArray[BlockHeader];
if validationResult != ValidationResult.OK:
return err("Failed to validate block")
if c.generateWitness:
let dbTx = c.db.newTransaction()
defer: dbTx.dispose()
let
mkeys = vmState.stateDB.makeMultiKeys()
# Reset state to what it was before executing the block of transactions
initialState = BaseVMState.new(header, c.com).valueOr:
return err("Failed to create vm state")
witness = initialState.buildWitness(mkeys)
dbTx.rollback()
c.db.setBlockWitness(header.blockHash(), witness)
if NoPersistHeader notin flags:
discard c.db.persistHeaderToDb(
header, c.com.consensus == ConsensusType.POS, c.com.startOfHistory)

View File

@ -114,7 +114,7 @@ proc procBlkEpilogue(vmState: BaseVMState;
{.gcsafe, raises: [].} =
# Reward beneficiary
vmState.mutateStateDB:
if vmState.generateWitness:
if vmState.collectWitnessData:
db.collectWitnessData()
db.persist(clearEmptyAccount = vmState.determineFork >= FkSpurious)

View File

@ -115,7 +115,7 @@ proc processTransactionImpl(
else:
res = err(txRes.error)
if vmState.generateWitness:
if vmState.collectWitnessData:
vmState.stateDB.collectWitnessData()
vmState.stateDB.persist(clearEmptyAccount = fork >= FkSpurious)

View File

@ -108,7 +108,7 @@ proc runTxCommit(pst: TxPackerStateRef; item: TxItemRef; gasBurned: GasInt)
vmState.stateDB.addBalance(xp.chain.feeRecipient, reward)
xp.blockValue += reward
if vmState.generateWitness:
if vmState.collectWitnessData:
vmState.stateDB.collectWitnessData()
# Save accounts via persist() is not needed unless the fork is smaller
@ -245,7 +245,7 @@ proc vmExecCommit(pst: TxPackerStateRef)
# Reward beneficiary
vmState.mutateStateDB:
if vmState.generateWitness:
if vmState.collectWitnessData:
db.collectWitnessData()
# Finish up, then vmState.stateDB.rootHash may be accessed
db.persist(clearEmptyAccount = xp.chain.nextFork >= FkSpurious)

View File

@ -984,20 +984,6 @@ proc haveBlockAndState*(db: CoreDbRef, headerHash: Hash256): bool =
# see if stateRoot exists
db.exists(header.stateRoot)
proc getBlockWitness*(
db: CoreDbRef, blockHash: Hash256): Result[seq[byte], string] {.gcsafe.} =
let res = db.newKvt().get(blockHashToBlockWitnessKey(blockHash).toOpenArray)
if res.isErr():
err("Failed to get block witness from database: " & $res.error.error)
else:
ok(res.value())
proc setBlockWitness*(db: CoreDbRef, blockHash: Hash256, witness: seq[byte]) =
let witnessKey = blockHashToBlockWitnessKey(blockHash)
db.newKvt.put(witnessKey.toOpenArray, witness).isOkOr:
warn logTxt "setBlockWitness()", witnessKey, action="put()", error=($$error)
return
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------

View File

@ -29,7 +29,7 @@ import
chronicles,
eth/[common, rlp],
results,
../../../stateless/multi_keys,
../../stateless/multi_keys,
"../.."/[constants, utils/utils],
../access_list as ac_access_list,
".."/[core_db, storage_types, transient_storage],

View File

@ -14,7 +14,7 @@
import
eth/common,
../../../stateless/multi_keys,
../../stateless/multi_keys,
../core_db,
./base/[api_tracking, base_desc]

View File

@ -13,7 +13,6 @@
import
std/[options, sets, strformat],
eth/keys,
../../stateless/[witness_from_tree, witness_types, multi_keys],
../db/ledger,
../common/[common, evmforks],
./interpreter/[op_codes, gas_costs],
@ -259,31 +258,12 @@ proc `status=`*(vmState: BaseVMState, status: bool) =
if status: vmState.flags.incl ExecutionOK
else: vmState.flags.excl ExecutionOK
proc generateWitness*(vmState: BaseVMState): bool =
GenerateWitness in vmState.flags
proc collectWitnessData*(vmState: BaseVMState): bool =
CollectWitnessData in vmState.flags
proc `generateWitness=`*(vmState: BaseVMState, status: bool) =
if status: vmState.flags.incl GenerateWitness
else: vmState.flags.excl GenerateWitness
proc buildWitness*(
vmState: BaseVMState,
mkeys: MultiKeysRef): seq[byte] {.raises: [CatchableError].} =
let rootHash = vmState.stateDB.rootHash
let flags = if vmState.fork >= FkSpurious: {wfEIP170} else: {}
# A valid block having no transactions should return an empty witness
if mkeys.keys.len() == 0:
return @[]
# build witness from tree
var wb = initWitnessBuilder(vmState.com.db, rootHash, flags)
wb.buildWitness(mkeys)
proc buildWitness*(
vmState: BaseVMState): seq[byte] {.raises: [CatchableError].} =
let mkeys = vmState.stateDB.makeMultiKeys()
buildWitness(vmState, mkeys)
proc `collectWitnessData=`*(vmState: BaseVMState, status: bool) =
if status: vmState.flags.incl CollectWitnessData
else: vmState.flags.excl CollectWitnessData
func forkDeterminationInfoForVMState*(vmState: BaseVMState): ForkDeterminationInfo =
# FIXME-Adam: Is this timestamp right? Note that up above in blockNumber we add 1;

View File

@ -36,7 +36,7 @@ const vm_use_recursion* = defined(evmc_enabled)
type
VMFlag* = enum
ExecutionOK
GenerateWitness
CollectWitnessData
BlockContext* = object
timestamp* : EthTime

View File

@ -54,7 +54,6 @@ proc basicServices(nimbus: NimbusNode,
nimbus.chainRef.extraValidation = 0 < verifyFrom
nimbus.chainRef.verifyFrom = verifyFrom
nimbus.chainRef.generateWitness = conf.generateWitness
nimbus.beaconEngine = BeaconEngineRef.new(nimbus.txPool, nimbus.chainRef)
proc manageAccounts(nimbus: NimbusNode, conf: NimbusConf) =

View File

@ -22,17 +22,17 @@ import
./filters,
../core/executor/process_block,
../db/ledger,
../../stateless/[witness_verification, multi_keys],
../stateless/multi_keys,
./p2p
type
BlockHeader = eth_types.BlockHeader
ReadOnlyStateDB = state_db.ReadOnlyStateDB
proc getBlockWitness*(
proc getMultiKeys*(
com: CommonRef,
blockHeader: BlockHeader,
statePostExecution: bool): (MultiKeysRef, BlockWitness)
statePostExecution: bool): MultiKeysRef
{.raises: [RlpError, BlockNotFound, ValueError, CatchableError].} =
let
@ -45,7 +45,7 @@ proc getBlockWitness*(
vmState = BaseVMState.new(blockHeader, com).valueOr:
raise newException(ValueError, "Cannot create vm state")
vmState.generateWitness = true # Enable saving witness data
vmState.collectWitnessData = true # Enable saving witness data
vmState.com.hardForkTransition(blockHeader)
let dbTx = vmState.com.db.newTransaction()
@ -57,16 +57,10 @@ proc getBlockWitness*(
let mkeys = vmState.stateDB.makeMultiKeys()
if statePostExecution:
result = (mkeys, vmState.buildWitness(mkeys))
else:
# Use the initial state from prior to executing the block of transactions
let initialState = BaseVMState.new(blockHeader, com).valueOr:
raise newException(ValueError, "Cannot create vm state")
result = (mkeys, initialState.buildWitness(mkeys))
dbTx.rollback()
mkeys
proc getBlockProofs*(
accDB: ReadOnlyStateDB,
mkeys: MultiKeysRef): seq[ProofResponse] {.raises: [RlpError].} =
@ -95,19 +89,6 @@ proc setupExpRpc*(com: CommonRef, server: RpcServer) =
let ac = newAccountStateDB(chainDB, header.stateRoot)
result = ReadOnlyStateDB(ac)
server.rpc("exp_getWitnessByBlockNumber") do(quantityTag: BlockTag, statePostExecution: bool) -> seq[byte]:
## Returns the block witness for a block by block number or tag.
##
## quantityTag: integer of a block number, or the string "earliest", "latest" or "pending", as in the default block parameter.
## statePostExecution: bool which indicates whether to return the witness based on the state before or after executing the block.
## Returns seq[byte]
let
blockHeader = chainDB.headerFromTag(quantityTag)
(_, witness) = getBlockWitness(com, blockHeader, statePostExecution)
return witness
server.rpc("exp_getProofsByBlockNumber") do(quantityTag: BlockTag, statePostExecution: bool) -> seq[ProofResponse]:
## Returns the block proofs for a block by block number or tag.
##
@ -117,7 +98,7 @@ proc setupExpRpc*(com: CommonRef, server: RpcServer) =
let
blockHeader = chainDB.headerFromTag(quantityTag)
(mkeys, _) = getBlockWitness(com, blockHeader, statePostExecution)
mkeys = getMultiKeys(com, blockHeader, statePostExecution)
let accDB = if statePostExecution:
getStateDB(blockHeader)

View File

@ -9,11 +9,11 @@
# according to those terms.
import
eth/common, eth/trie/nibbles, algorithm,
./witness_types
eth/common, eth/trie/nibbles, algorithm
type
KeyHash* = array[32, byte]
StorageSlot* = array[32, byte]
KeyData* = object
visited*: bool
@ -47,6 +47,10 @@ type
match*: bool
group*: Group
proc setBranchMaskBit(x: var uint, i: int) =
assert(i >= 0 and i < 17)
x = x or (1 shl i).uint
func cmpHash(a, b: KeyHash): int =
var i = 0
var m = min(a.len, b.len)

View File

@ -17,14 +17,13 @@ export
export
vms.`$`,
vms.blockNumber,
vms.buildWitness,
vms.coinbase,
vms.determineFork,
vms.difficultyOrPrevRandao,
vms.baseFee,
vms.forkDeterminationInfoForVMState,
vms.generateWitness,
vms.`generateWitness=`,
vms.collectWitnessData,
vms.`collectWitnessData=`,
vms.getAncestorHash,
vms.getAndClearLogEntries,
vms.init,

View File

@ -8,7 +8,7 @@
# according to those terms.
excluded_files="config.yaml|.gitmodules|.gitignore"
excluded_extensions="json|md|png|txt|toml|gz|key|rlp|era1|cfg|py|sh"
excluded_extensions="json|md|png|txt|toml|gz|key|rlp|era1|cfg|py|sh|in"
current_year=$(date +"%Y")
outdated_files=()

View File

@ -1,361 +0,0 @@
# Nimbus
# Copyright (c) 2020-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
stew/[byteutils, endians2], json, strutils,
eth/[common, rlp],
eth/trie/[trie_defs, nibbles, db],
./witness_types, ../nimbus/constants,
../nimbus/db/storage_types, ./multi_keys
type
DB = TrieDatabaseRef
WitnessBuilder* = object
db*: DB
root: KeccakHash
flags: WitnessFlags
node: JsonNode
jStack: seq[JsonNode]
StackElem = object
node: seq[byte]
parentGroup: Group
keys: MultiKeysRef
depth: int
storageMode: bool
proc initWitnessBuilder*(db: DB, rootHash: KeccakHash, flags: WitnessFlags = {}): WitnessBuilder =
result.db = db
result.root = rootHash
result.flags = flags
result.node = newJObject()
result.jStack = @[]
template extensionNodeKey(r: Rlp): auto =
hexPrefixDecode r.listElem(0).toBytes
proc expectHash(r: Rlp): seq[byte] =
result = r.toBytes
if result.len != 32:
raise newException(RlpTypeMismatch,
"RLP expected to be a Keccak hash value, but has an incorrect length")
template getNode(elem: untyped): untyped =
if elem.isList: @(elem.rawData)
else: @(get(wb.db, elem.expectHash))
proc rlpListToBitmask(r: var Rlp): uint =
var i = 0
for branch in r:
if not branch.isEmpty:
result.setBranchMaskBit(i)
inc i
r.position = 0
proc writeByte(wb: var WitnessBuilder, x: byte, name: string) =
wb.node[name] = newJString("0x" & toHex(x.int, 2))
proc write(wb: var WitnessBuilder, x: openArray[byte], name: string) =
wb.node[name] = newJString("0x" & toHex(x))
proc write(wb: var WitnessBuilder, a, b: byte, name: string) =
wb.node[name] = newJString("0x" & toHex(a.int, 2) & toHex(b.int, 2))
proc write(wb: var WitnessBuilder, x: bool, name: string) =
wb.node[name] = newJBool(x)
proc pushArray(wb: var WitnessBuilder, name: string) =
var node = newJArray()
wb.node[name] = node
wb.jStack.add wb.node
wb.node = node
proc pushObject(wb: var WitnessBuilder, name: string) =
var node = newJObject()
wb.node[name] = node
wb.jStack.add wb.node
wb.node = node
proc addObject(wb: var WitnessBuilder) =
var node = newJObject()
wb.node.add node
wb.jStack.add wb.node
wb.node = node
proc pop(wb: var WitnessBuilder) =
wb.node = wb.jStack.pop()
proc writeU32Impl(wb: var WitnessBuilder, x: uint32, name: string) =
let y = toBytesBE(x)
wb.node[name] = newJString("0x" & toHex(y))
template writeU32(wb: var WitnessBuilder, x: untyped, name: string) =
wb.writeU32Impl(uint32(x), name)
template writeByte(wb: var WitnessBuilder, x: untyped, name: string) =
writeByte(wb, byte(x), name)
proc writeUVarint[T](wb: var WitnessBuilder, x: T, name: string) =
# LEB128 varint encoding
var data: array[50, byte]
var len = 0
template writeByte(x) =
data[len] = x.byte
inc len
var value = x
while true:
when T is UInt256:
var b = value.truncate(int) and 0x7F # low order 7 bits of value
else:
var b = value and 0x7F # low order 7 bits of value
value = value shr 7
if value != 0: # more bytes to come
b = b or 0x80 # set high order bit of b
writeByte(b)
if value == 0: break
wb.write(data.toOpenArray(0, len-1), name)
template writeUVarint32(wb: var WitnessBuilder, x: untyped, name: string) =
wb.writeUVarint(uint32(x), name)
proc writeNibbles(wb: var WitnessBuilder; n: NibblesSeq) =
# convert the NibblesSeq into left aligned byte seq
# perhaps we can optimize it if the NibblesSeq already left aligned
let nibblesLen = n.len
let numBytes = nibblesLen div 2 + nibblesLen mod 2
var bytes: array[32, byte]
doAssert(nibblesLen >= 1)
doAssert(numBytes >= 0 and numBytes <= 64)
for pos in 0..<n.len:
if (pos and 1) != 0:
bytes[pos div 2] = bytes[pos div 2] or n[pos]
else:
bytes[pos div 2] = bytes[pos div 2] or (n[pos] shl 4)
wb.writeByte(nibblesLen, "nibblesLen")
wb.write(bytes.toOpenArray(0, numBytes-1), "nibbles")
proc writeExtensionNode(wb: var WitnessBuilder, n: NibblesSeq, depth: int, node: openArray[byte]) =
wb.addObject()
wb.writeByte(ExtensionNodeType, "nodeType")
wb.writeNibbles(n)
wb.writeByte(depth, "debugDepth")
wb.write(keccakHash(node).data, "debugHash")
wb.pop()
proc writeBranchNode(wb: var WitnessBuilder, mask: uint, depth: int, node: openArray[byte]) =
doAssert mask.branchMaskBitIsSet(16) == false
wb.addObject()
wb.writeByte(BranchNodeType, "nodeType")
wb.write(byte((mask shr 8) and 0xFF), byte(mask and 0xFF), "mask")
wb.writeByte(depth, "debugDepth")
wb.write(keccakHash(node).data, "debugHash")
wb.pop()
proc writeHashNode(wb: var WitnessBuilder, node: openArray[byte]) =
wb.addObject()
wb.writeByte(HashNodeType, "nodeType")
wb.write(node, "data")
wb.pop()
proc writeHashNode(wb: var WitnessBuilder, node: openArray[byte], name: string) =
wb.pushObject(name)
wb.writeByte(HashNodeType, "nodeType")
wb.write(node, "data")
wb.pop()
proc getBranchRecurse(wb: var WitnessBuilder, z: var StackElem)
proc writeByteCode(wb: var WitnessBuilder, kd: KeyData, acc: Account) =
if not kd.codeTouched:
# the account have code but not touched by the EVM
# in current block execution
wb.writeByte(CodeUntouched, "codeType")
let code = get(wb.db, contractHashKey(acc.codeHash).toOpenArray)
if wfEIP170 in wb.flags and code.len > EIP170_MAX_CODE_SIZE:
raise newException(ContractCodeError, "code len exceed EIP170 code size limit")
wb.writeUVarint32(code.len, "codeLen")
wb.writeHashNode(acc.codeHash.data, "codeHash")
# no need to write 'code' here
return
wb.writeByte(CodeTouched, "codeType")
if acc.codeHash == blankStringHash:
# no code
wb.writeUVarint32(0'u32, "codeLen")
return
# the account have code and the EVM use it
let code = get(wb.db, contractHashKey(acc.codeHash).toOpenArray)
if wfEIP170 in wb.flags and code.len > EIP170_MAX_CODE_SIZE:
raise newException(ContractCodeError, "code len exceed EIP170 code size limit")
wb.writeUVarint32(code.len, "codeLen")
wb.write(code, "code")
proc writeStorage(wb: var WitnessBuilder, kd: KeyData, acc: Account) =
wb.pushArray("storage")
if kd.storageKeys.isNil:
# the account have storage but not touched by EVM
wb.writeHashNode(acc.storageRoot.data)
elif acc.storageRoot != emptyRlpHash:
# the account have storage and the EVM use it
var zz = StackElem(
node: wb.db.get(acc.storageRoot.data),
parentGroup: kd.storageKeys.initGroup(),
keys: kd.storageKeys,
depth: 0, # set depth to zero
storageMode: true # switch to storage mode
)
getBranchRecurse(wb, zz)
else:
# no storage at all
wb.writeHashNode(emptyRlpHash.data)
wb.pop()
proc writeAccountNode(wb: var WitnessBuilder, kd: KeyData, acc: Account, node: openArray[byte], depth: int) =
wb.addObject()
wb.writeByte(AccountNodeType, "nodeType")
var accountType = if acc.codeHash == blankStringHash and acc.storageRoot == emptyRlpHash: SimpleAccountType
else: ExtendedAccountType
wb.writeByte(accountType, "accountType")
wb.write(kd.address, "address")
wb.writeUVarint(acc.balance, "balance")
wb.writeUVarint(acc.nonce, "nonce")
if accountType != SimpleAccountType:
wb.writeByteCode(kd, acc)
wb.writeStorage(kd, acc)
wb.writeByte(depth, "debugDepth")
wb.write(keccakHash(node).data, "debugHash")
wb.pop()
proc writeAccountStorageLeafNode(wb: var WitnessBuilder, key: openArray[byte], val: UInt256, node: openArray[byte], depth: int) =
wb.addObject()
wb.writeByte(StorageLeafNodeType, "nodeType")
wb.write(key, "key")
wb.write(val.toBytesBE, "value")
wb.writeByte(depth, "debugDepth")
wb.write(keccakHash(node).data, "debugHash")
wb.pop()
proc getBranchRecurse(wb: var WitnessBuilder, z: var StackElem) =
if z.node.len == 0: return
var nodeRlp = rlpFromBytes z.node
case nodeRlp.listLen
of 2:
let (isLeaf, k) = nodeRlp.extensionNodeKey
let mg = groups(z.keys, z.depth, k, z.parentGroup)
if not mg.match:
# return immediately if there is no match
writeHashNode(wb, keccakHash(z.node).data)
return
let value = nodeRlp.listElem(1)
if not isLeaf:
# recursion will go deeper depend on the common-prefix length nibbles
writeExtensionNode(wb, k, z.depth, z.node)
var zz = StackElem(
node: value.getNode,
parentGroup: mg.group,
keys: z.keys,
depth: z.depth + k.len, # increase the depth by k.len
storageMode: z.storageMode
)
getBranchRecurse(wb, zz)
return
# there should be only one match
let kd = z.keys.visitMatch(mg, z.depth, k)
if z.storageMode:
doAssert(kd.storageMode)
writeAccountStorageLeafNode(wb, kd.storageSlot, value.toBytes.decode(UInt256), z.node, z.depth)
else:
doAssert(not kd.storageMode)
writeAccountNode(wb, kd, value.toBytes.decode(Account), z.node, z.depth)
of 17:
let branchMask = rlpListToBitmask(nodeRlp)
writeBranchNode(wb, branchMask, z.depth, z.node)
# if there is a match in any branch elem
# 1st to 16th, the recursion will go deeper
# by one nibble
doAssert(z.depth != 64) # notLeaf or path.len == 0
let path = groups(z.keys, z.parentGroup, z.depth)
for i in nonEmpty(branchMask):
let branch = nodeRlp.listElem(i)
if branchMaskBitIsSet(path.mask, i):
# it is a match between multikeys and Branch Node elem
var zz = StackElem(
node: branch.getNode,
parentGroup: path.groups[i],
keys: z.keys,
depth: z.depth + 1, # increase the depth by one
storageMode: z.storageMode
)
getBranchRecurse(wb, zz)
continue
if branch.isList:
# short node appear in yellow paper
# but never in the actual ethereum state trie
# an rlp encoded ethereum account will have length > 32 bytes
# block witness spec silent about this
doAssert(false, "Short node should not exist in block witness")
else:
# if branch elem not empty and not a match, emit hash
writeHashNode(wb, branch.expectHash)
# 17th elem should always empty
# 17th elem appear in yellow paper but never in
# the actual ethereum state trie
# the 17th elem also not included in block witness spec
doAssert branchMask.branchMaskBitIsSet(16) == false
else:
raise newException(CorruptedTrieDatabase,
"HexaryTrie node with an unexpected number of children")
proc buildWitness*(wb: var WitnessBuilder, keys: MultiKeysRef): string =
# witness version
wb.writeByte(BlockWitnessVersion, "version")
# one or more trees
# we only output one tree
wb.writeByte(MetadataNothing, "metadata")
wb.write(wb.root.data, "rootHash")
wb.write(false, "error")
wb.pushArray("tree")
var z = StackElem(
node: @(wb.db.get(wb.root.data)),
parentGroup: keys.initGroup(),
keys: keys,
depth: 0,
storageMode: false
)
getBranchRecurse(wb, z)
wb.pop()
result = wb.node.pretty()

View File

@ -1,128 +0,0 @@
# Nimbus
# Copyright (c) 2020-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
randutils, random, parseopt, strutils, os,
eth/[common, rlp], eth/trie/[hexary, db, trie_defs],
nimcrypto/sysrand, ../stateless/[json_from_tree],
../nimbus/db/[storage_types, distinct_tries],
./witness_types, ./multi_keys
type
DB = TrieDatabaseRef
StorageKeys = tuple[storageRoot: Hash256, keys: MultiKeysRef]
AccountDef = object
storageKeys: MultiKeysRef
account: Account
codeTouched: bool
proc randU256(): UInt256 =
var bytes: array[32, byte]
discard randomBytes(bytes[0].addr, sizeof(result))
result = UInt256.fromBytesBE(bytes)
proc randStorageSlot(): StorageSlot =
discard randomBytes(result[0].addr, sizeof(result))
proc randNonce(): AccountNonce =
discard randomBytes(result.addr, sizeof(result))
proc randCode(db: DB): Hash256 =
if rand(0..1) == 0:
result = blankStringHash
else:
let codeLen = rand(1..150)
let code = randList(byte, rng(0, 255), codeLen, unique = false)
result = keccakHash(code)
db.put(contractHashKey(result).toOpenArray, code)
proc randStorage(db: DB, numSlots: int): StorageKeys =
if rand(0..1) == 0 or numSlots == 0:
result = (emptyRlpHash, MultiKeysRef(nil))
else:
var trie = initStorageTrie(db)
var keys = newSeq[StorageSlot](numSlots)
for i in 0..<numSlots:
keys[i] = randStorageSlot()
trie.putSlotBytes(keys[i], rlp.encode(randU256()))
if rand(0..1) == 0:
result = (trie.rootHash, MultiKeysRef(nil))
else:
var m = newMultikeys(keys)
result = (trie.rootHash, m)
proc randAccount(db: DB, numSlots: int): AccountDef =
result.account.nonce = randNonce()
result.account.balance = randU256()
let z = randStorage(db, numSlots)
result.account.codeHash = randCode(db)
result.account.storageRoot = z.storageRoot
result.storageKeys = z.keys
result.codeTouched = rand(0..1) == 0
proc randAddress(): EthAddress =
discard randomBytes(result.addr, sizeof(result))
proc runGenerator(numPairs, numSlots: int): string =
var memDB = newMemoryDB()
var trie = initAccountsTrie(memDB)
var addrs = newSeq[AccountKey](numPairs)
var accs = newSeq[Account](numPairs)
for i in 0..<numPairs:
let acc = randAccount(memDB, numSlots)
addrs[i] = (randAddress(), acc.codeTouched, acc.storageKeys)
accs[i] = acc.account
trie.putAccountBytes(addrs[i].address, rlp.encode(accs[i]))
var mkeys = newMultiKeys(addrs)
let rootHash = trie.rootHash
var wb = initWitnessBuilder(memDB, rootHash, {wfEIP170})
result = wb.buildWitness(mkeys)
proc writeHelp() =
echo "json_witness_gen output --pairs:val --slots:val -s:val -p:val"
proc main() =
var filename: string
var outputDir: string
var numPairs = 1
var numSlots = 1
for kind, key, val in getopt():
case kind
of cmdArgument:
filename = key
of cmdLongOption, cmdShortOption:
case key
of "pairs", "p":
numPairs = parseInt(val)
if numPairs <= 0: numPairs = 1
of "slots", "s":
numSlots = parseInt(val)
if numSlots < 0: numSlots = 0
of "output", "o":
outputDir = val
of cmdEnd: assert(false) # cannot happen
if filename == "":
writeHelp()
quit(0)
randomize()
let witness = runGenerator(numPairs, numSlots)
let filePath = if outputDir.len > 0: outputDir / filename: else: filename
writeFile(filePath, witness)
main()

View File

@ -1,26 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x3ef071a43e07a7a209d4a67f9edd05477e8e3ac30af64656cfe784961fd2433a",
"error": false,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x720ef0ee74f1b3b8252eb3270d484b223f775810",
"balance": "0xb3c2cee7e2cb9289c8cdd1d9b99ff0e7829fdce2f5afd2fca6a2ff9f9bf8e38493d09bc403",
"nonce": "0xad83abd1899ad9ee56",
"codeType": "0x00",
"codeLen": "0x3d",
"code": "0x09ddefda93a915fe9ac8998e195a5fe0bb85a2474e676551e8978cba5b5ea3af0dc90606fd0e6d4f07b0262ada94b579676f51e4226b2dc456be061e99",
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x3ef071a43e07a7a209d4a67f9edd05477e8e3ac30af64656cfe784961fd2433a"
}
]
}

View File

@ -1,29 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d",
"error": false,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x205aea15c1e739b4acdae0cc3b57c34f55907a73",
"balance": "0x8ca589e2e38294c9899abddfbbe887c9bbc5d296eda1f59b8180d8d88883c88d9a86bdba06",
"nonce": "0xa3e99cc2e5e5e5d6ce01",
"codeType": "0x01",
"codeLen": "0x5e",
"codeHash": {
"nodeType": "0x03",
"data": "0x8dd74346f58c605477239378ca66f42e8a75b9cc8aea3287ad30c8a5932a92da"
},
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d"
}
]
}

View File

@ -1,17 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4",
"error": false,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x080e7dabd304f1acd44786d3ac613a5f2ff66b77",
"balance": "0x8cf8c7f1f3ffad95bce2f996d7e1f5a6d9aa96efce9ccba59789dcd6dce3969cc99bc9c50e",
"nonce": "0xe3f483f981dee9db5e",
"debugDepth": "0x00",
"debugHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4"
}
]
}

View File

@ -1,29 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x0e90a5b7a3cb36d99e318df559f7516e97fbf779bfaa83c7487bef343908f608",
"error": false,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x2a425b119d8bfa8fdb9852f731aaacec27ea76b1",
"balance": "0xeed4ddc3b2b598e1c29ca99aafc3a5e9c3bffbcae3adc4b3a09ea8f6b98ef6ddcaeae3b20c",
"nonce": "0xe5ebf99b83ebe2cfd601",
"codeType": "0x00",
"codeLen": "0x40",
"code": "0x3841c4b026645417401c750b610b3571de8fa8c219933057df4d1b890091a67b2480d3e07459bfa475156f691e0c56c2558c3d01370d15b7f5ceb6f672770899",
"storage": [
{
"nodeType": "0x02",
"key": "0x37e5d5966c3a6e98d9502ae2fe458ce543761384abf07621534a3c8c419bd00b",
"value": "0xd48881272c825d7755d2b88842ab99e8d7ed122050fe3aef9660a0095712bec7",
"debugDepth": "0x00",
"debugHash": "0x77e607b809ddcd8b02a5e1a274d178c8df487ce70667bab68cf1033a721009af"
}
],
"debugDepth": "0x00",
"debugHash": "0x0e90a5b7a3cb36d99e318df559f7516e97fbf779bfaa83c7487bef343908f608"
}
]
}

View File

@ -1,29 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x27e1adcca01a43ba9addd0309b170dbe54a13fd6fc8db32d603ff8acc74c114a",
"error": false,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x1f6d2e14d36e46ed0ffd4bc8f7a99c215c37a987",
"balance": "0xb9c3fdeb80eedb84a7d5cda2a2cccd9dafda8be4fda3a2a5cd848cb0a6f7efd9898b83fd0a",
"nonce": "0xcfea87d0e695cadb11",
"codeType": "0x01",
"codeLen": "0x42",
"codeHash": {
"nodeType": "0x03",
"data": "0x8617fb2d49a06427c5982b03b581f1c7c9bfa7ab4da2e67ca665f21ecc2f70f4"
},
"storage": [
{
"nodeType": "0x03",
"data": "0xe36ab8ab77009fccb7763c179b8bd1c9d87999e60969de56f96c45d868e1c300"
}
],
"debugDepth": "0x00",
"debugHash": "0x27e1adcca01a43ba9addd0309b170dbe54a13fd6fc8db32d603ff8acc74c114a"
}
]
}

View File

@ -1,304 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x4b7082248440f9d040a2f7f55a4177c4f25a70f671aa0cb371b7bf189cc4fc68",
"error": false,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x06852d62c3a302f0cec4a92908f1040f6c1a9357",
"balance": "0xf5bdb1a883a8d8b094ada48e9c80cfa18488f6adbbf0c592f4ceeb98d696d08988d7cb07",
"nonce": "0xcea3dea7b4fb98cdaa01",
"codeType": "0x00",
"codeLen": "0x1a",
"code": "0xd0936ffd3b2a2867f12c8251f72b4997b3080d0f168d34860cb8",
"storage": [
{
"nodeType": "0x00",
"mask": "0xF9FF",
"debugDepth": "0x00",
"debugHash": "0xa8a27dea0be0d4138a6da655a7f5694cb2a0802bba453f7276fb33dd160a5945"
},
{
"nodeType": "0x00",
"mask": "0x0108",
"debugDepth": "0x01",
"debugHash": "0x376834c93db082a8620b021d9a1e3ac5cb14c237d36ded719061153c68d22ae5"
},
{
"nodeType": "0x00",
"mask": "0x4800",
"debugDepth": "0x02",
"debugHash": "0xd9e37be3b9a0c1fa3d53d0c679ccc5401db5a47701c95f2be3f4a084e7a3f27b"
},
{
"nodeType": "0x02",
"key": "0xaa217d9dd11ad18dd431cb5e2270b64c88f9557ef1800f6243c20ed1ae7e3dea",
"value": "0xe13cbcd714d9b1943eec9c6b84062d38f1009fdedf2a52b258cc051d4c4b1e09",
"debugDepth": "0x03",
"debugHash": "0x0a4fa8d829c222e87bc33df9aadd790434a78997fc56a3fb6ae85b7341e2641d"
},
{
"nodeType": "0x02",
"key": "0x2fe189467d5c589df80c15868d154f45647f477ed50cc1989b53555c6c4cfda9",
"value": "0xb792e2a1f4dfc913c45583b1982727a603a4f3a2bdaf2037b38d15664413bbe7",
"debugDepth": "0x03",
"debugHash": "0x288d92ade25c3ceb2cca22ddbf2732f174f7e1d217163893091a4b287ef0fb4b"
},
{
"nodeType": "0x02",
"key": "0xcc70ae02ac6b231c46b6f605d2ace7e5eb0d9944abe28a158e209bbc9afd0c5a",
"value": "0x3dd88f3b80115f0289e52e52f2cfcf04190d1c972ba2314d099ee7a7bc92a1c3",
"debugDepth": "0x02",
"debugHash": "0x1d880ea9b065359bff4373d94b696572bf689d76500377760f460a23af737ae7"
},
{
"nodeType": "0x00",
"mask": "0xC140",
"debugDepth": "0x01",
"debugHash": "0x5e481953f2e2a5b52c2c7857f4ea0dcc318d4d74482632c35c22923331e0c304"
},
{
"nodeType": "0x02",
"key": "0x0e90d4692a812cace9cc53a41c094309bc5f2698066d22187fe658f0fb12aa0a",
"value": "0xc4e820a2d7865ab420db28c3bbafde4d710b18b722403e1e8f6ae88508ff8978",
"debugDepth": "0x02",
"debugHash": "0xf9499523f940aafd0c360880769a33bdbc1ef1f9d55e3ee01b11360fffbccdd4"
},
{
"nodeType": "0x02",
"key": "0xe950abb124a710179726d8ae3443b17f93a67472a20aebee84104c77f6c4cc78",
"value": "0x2d61084050ba6f779324acc8a0ec615ed0bd76e599b4c3b60026bb65bd7e5a9b",
"debugDepth": "0x02",
"debugHash": "0x68cd75fdd8506d48fc81d3e05b3dc7567edd5633787d902283c88eeee0c54694"
},
{
"nodeType": "0x02",
"key": "0xccf524783653b1a14f93d97531222f1a800778fb171c131d3d6774d61325e6bd",
"value": "0x5cb6b329a21ff21795368dd94a2cd50213b5f1daa79f031dbffa66b85a61b348",
"debugDepth": "0x02",
"debugHash": "0x9394b13fc593ee3eff55c8089dc09c6a63cebe879a1717d422f29ed86b344768"
},
{
"nodeType": "0x02",
"key": "0x9e65049f8e10b9388af2a91c131813d960c627f318e10673cf85195cc1656573",
"value": "0x259bc2273654b6da367eba244b38262eec21ba0f07908a22bf3c2dbf080c2465",
"debugDepth": "0x02",
"debugHash": "0x10e97f103bbfe03db4e90ed4441272f535528258c17c16a388f33722e80b046d"
},
{
"nodeType": "0x00",
"mask": "0x8044",
"debugDepth": "0x01",
"debugHash": "0xe1f5c7cd519df9104a4733797d1c3fa748fcd2b3dec935bc4de49db359189cc1"
},
{
"nodeType": "0x02",
"key": "0x5adb66219b58e831bd3723486a3856ae459918527e1414a907d7752c3a528104",
"value": "0x510ddd96fd0fc7919cee9b45b722eb1e58472b39030dc834f107729cd5aeb3e2",
"debugDepth": "0x02",
"debugHash": "0xf0d1de3adf7f429fb2b917ff73d179e801610249bca7eb0bc2855650bcf8dff9"
},
{
"nodeType": "0x02",
"key": "0x162830d8f8deefd4b54836aecad18e6be06c75368ce3856995bf3f95a27bb1dd",
"value": "0x3ac191252ff512e11fc02542185b9fc77160b11d748fd37e6548ef3b4f3b383e",
"debugDepth": "0x02",
"debugHash": "0x02c1bd87d0012905bb8775b5ea773192ab89221e0889e14c33425cb4439a5e94"
},
{
"nodeType": "0x02",
"key": "0xace41e727612c5e12460dd04b2fd0300318b6939572ac5454e4626131b23423a",
"value": "0x40d970c83de360a739f0fedd9d0187ef1c53d258a3927445fedb3320b77c9c9d",
"debugDepth": "0x02",
"debugHash": "0x8bd758a0867e0b61c5adba329379f0e789935f64632924fbf728fc0968be180e"
},
{
"nodeType": "0x02",
"key": "0x5128809b5b57dad7da874ef299779dbb001b3783569ac074d59c50c943d8d198",
"value": "0xcdf46d3f3f58d88f8a614c904e133891f71f136041416f47a52bb751e4c5e563",
"debugDepth": "0x01",
"debugHash": "0xadcbec6b5b96a3a1968bc47904b0a7c725a3e564abb7ceb6ab1df73715a2f54a"
},
{
"nodeType": "0x00",
"mask": "0x2150",
"debugDepth": "0x01",
"debugHash": "0x90891286049642bb7a5e30320d18c6a3f0d27555963d8c6287a05fedc90ec57c"
},
{
"nodeType": "0x02",
"key": "0xc7bb062663c3cbdfaeea8d5a9bc5cf0418bc13a4f9d614fa7dededcba471d7ea",
"value": "0x0a4accc3049d45e5a1c3c53d95d835e0fe78ea8f2da23235fee53fabb5c856b1",
"debugDepth": "0x02",
"debugHash": "0x20d0c7f141867307fbf4423598b7eb9bc5697f85b11d6c8e95c8dd09a2f9005d"
},
{
"nodeType": "0x02",
"key": "0x2df9e20b09b850841177f8cc2e2454f199b2f1ca9d8165879cac6e4e199e4381",
"value": "0x1d3316148b02384ceee672189743dc48b464632e1ce10bf5a747f7bcca63e5b8",
"debugDepth": "0x02",
"debugHash": "0xd36a5b199aeb50b4c540599ec1992cc6d4ed76f4453e0305ae95c9681be27661"
},
{
"nodeType": "0x02",
"key": "0x0cfe461cb96c37e35c97b7c9b0e1cfa4d64133cd9be6b7deb88da316520e534b",
"value": "0x048eef6d6bc92290f3a0fb903c332bb8b89ad3393293e5c74af19190ef634eaa",
"debugDepth": "0x02",
"debugHash": "0x2bb074cb43c3afb0e6c0dcd709ea1943d462932ece4e6677a0bb527a21c1c62a"
},
{
"nodeType": "0x00",
"mask": "0x2040",
"debugDepth": "0x02",
"debugHash": "0xacd53be6d16856dda1b55eac2103188f11b8118b73dc43785f214d8bca184853"
},
{
"nodeType": "0x02",
"key": "0x8d938a0ec13be0f5541b141414293bf0b4aee794aa200530434edb878a577705",
"value": "0xe9f344e60c2353f2781346b26aac0e8bc3fcae11baed9490db849650cd38d0a8",
"debugDepth": "0x03",
"debugHash": "0x166c1a8b7e76bbbe60a2dbe9cb9140dcdee74f18f40b36a8e0ca811a31cf0130"
},
{
"nodeType": "0x02",
"key": "0x890bfd8808f2338b91e2f294e2e80337c2bb485070eea237556201d3d5f46efb",
"value": "0xbea2f844de233796ec0ea2ac2c241c1e149e7bd5037514b0edd89d557aa47dad",
"debugDepth": "0x03",
"debugHash": "0x6a1aa24523cf98745017656555e8adb7d443aff10f3db34e942dee58b6e76d32"
},
{
"nodeType": "0x00",
"mask": "0x0804",
"debugDepth": "0x01",
"debugHash": "0x3b0b7b29bfdccd1bb908c85768e9dc8d96b1eca5344a75d0e2bcdfb92ec7f3e3"
},
{
"nodeType": "0x02",
"key": "0x893135bb24b98b68f6c7bf2fc4d753dd6116f185e15c0f5ff0814224daafae8c",
"value": "0xbad1635b9ac609ebeede00d2a43ec80ee0d4186a59cb3d1bf0854cfa5bd46465",
"debugDepth": "0x02",
"debugHash": "0x61797d1f0b345e427676995ef359ac4da3f8400ac33d86584bc48eb783e4661e"
},
{
"nodeType": "0x02",
"key": "0x20821aa715a79dc7f575d1daae8ee2064211f5e7f1eb19d35197234309191ffc",
"value": "0xe080c2e4c5eaa1d6ebac17bad0c7b1e2be2ea0c1a233f7e7e5a677fa883a6aa6",
"debugDepth": "0x02",
"debugHash": "0x0f6c12390f8054a97d3a6cf5cf5d012ba33989b610af274c6fd215739342edf3"
},
{
"nodeType": "0x00",
"mask": "0x0084",
"debugDepth": "0x01",
"debugHash": "0xecd51e9ed1f6e86de3c6915f648aca3d19dccfffc1403012221d7f561b40b232"
},
{
"nodeType": "0x02",
"key": "0x4ce1880bb013748d79562267a41a55146ab63a9486b80f32b76a9fd368ac383a",
"value": "0x008d79d6b57c0a4d31b0707a3cc09131825ddeda6fa6768fe92408e93b430364",
"debugDepth": "0x02",
"debugHash": "0x5b211f8844398de4a853e07965b9230655532d4ea6702386992ac165399176c8"
},
{
"nodeType": "0x02",
"key": "0x73e5dfe909c2e65e055c8817548f1606e3d3ea5264cef9e9b0d904c33b83fe86",
"value": "0xbe14ee00a056882b3d7a4d172af274bcdba7100b43dd5f4c1519c67151e9b042",
"debugDepth": "0x02",
"debugHash": "0xb66189f5ba1b5921352c5ea8657cfcb2c3f5fe6b047af3ee9ac3a6dda3b26069"
},
{
"nodeType": "0x02",
"key": "0xe4ea4d108992ebb8cda227aa8ce91dd38ab66678c2f4e7ecb522619edfec83ca",
"value": "0xc34e633c1f9d2b04c457277b0da9c31098d8d81a02d12ae8194927b9d92be240",
"debugDepth": "0x01",
"debugHash": "0x9a3c86ac04cff263de7b4ef056c6b6e74903a359f64c284f98b82a8a5bd551e7"
},
{
"nodeType": "0x00",
"mask": "0x0042",
"debugDepth": "0x01",
"debugHash": "0x770756b645c662e497e5f0dc240b5baa9ab9459c87b0f09a1547f1f377257e56"
},
{
"nodeType": "0x02",
"key": "0x6c25538cacf9f7df86f7ed93eac5a56df604f520c5354e04b849a754e92d3406",
"value": "0x0111bded60a83c16f8c75728ae8ea949a823feb9a2f509ec77a454477e550cbe",
"debugDepth": "0x02",
"debugHash": "0xb0e2c050a871f02b05990890fc9c713f67dcad76bde574d9a212e0f884345bb0"
},
{
"nodeType": "0x02",
"key": "0x850a0fde14f360af8a6599f99ccb2d5c6609ef848db2d7caca60476a4b5d476c",
"value": "0xb8c5474632b02c967c98fbc7b96d32c6afa3ea67228c7e6873e79916f0150f8c",
"debugDepth": "0x02",
"debugHash": "0xff4a54e6393b0ebb761138933dd551ad7367cc5d4254dc1742fe47da9db33d6d"
},
{
"nodeType": "0x00",
"mask": "0x2100",
"debugDepth": "0x01",
"debugHash": "0x44bbc4a59fe05c72c24c7f978a388df249933d82c21d10e2ba3a881985f058d0"
},
{
"nodeType": "0x02",
"key": "0x7b3ad2728d8167702b0975e32b881cbbae7f5f8cb2c384372bcb218f400bf34b",
"value": "0x25e6f3859659b65fe4e110e41ccc704aa9562b0e0ec8c11ebf0b2c9de1e4b558",
"debugDepth": "0x02",
"debugHash": "0x6cb83a539fe400b0c89105e150dfe86bd5363e37456d02d64ba1f46122f295ff"
},
{
"nodeType": "0x02",
"key": "0xa9e36fa3f11cad78f92146effddc9983175781527abad56821ba325a9b07ec8f",
"value": "0x93dabe158e5d4de4c752cee95e20bcf896bd9e6e94a41f27277124c3b051e9b0",
"debugDepth": "0x02",
"debugHash": "0x70eb6ee011384f47bb370a3808cf679840fb804358b36b112d861e3d7f607a16"
},
{
"nodeType": "0x02",
"key": "0xa40b51651e9723b9a7c912b96e210b49534188f35d05942aabd87e2b04f337d7",
"value": "0xa293648270a4e3b87140a279d8d169b0cc49b27596a8fff90bfa38a6492f1977",
"debugDepth": "0x01",
"debugHash": "0x12248a11dd27983addce5267b17d6ef210d78b232a53a3ff84d842c3c7446a28"
},
{
"nodeType": "0x02",
"key": "0x69d4da4813c2c4f421a6e86f34989a1c5792b271d74b18e474678054b3c5d410",
"value": "0xd73141b5219ced97e71cd5f09e603439b83358d42e1d0d13054e96fb898b897a",
"debugDepth": "0x01",
"debugHash": "0xb34a23b3999eff09e70284480f09fe7821829f734300577d8580ec5a38f8afd6"
},
{
"nodeType": "0x00",
"mask": "0x8004",
"debugDepth": "0x01",
"debugHash": "0x3e7b136950036ffd956a5aa800861e8578c505bfae051505637ea55959b4dec6"
},
{
"nodeType": "0x02",
"key": "0xcf4a5c8979d764e5cb47226dd8fe5971a13a97e84dc15f5151dabcb132f29f41",
"value": "0x228d8126026eec55f79ef977ec11ba5bb2c8afc68c589c71d989086fe7f39013",
"debugDepth": "0x02",
"debugHash": "0xc41a210065dfc6c2166a0d3a5a1f4300c6c6c01820b66a1ad143401fb3d41eb6"
},
{
"nodeType": "0x02",
"key": "0x1eb5b1d559ad696037a8b6254927200ffafb4f21e55f23470844bf580a8f6c10",
"value": "0x077390e527bedacc743328b2d57a5e04401a94ab7bb671cbc3e1d00d33e56ef2",
"debugDepth": "0x02",
"debugHash": "0x08dfaeea00282b2a7ec8bd615fba98aaa789a6114fc0d129720215b1c3408667"
},
{
"nodeType": "0x02",
"key": "0x23dc4eb4f09b99fc8a22ec960d5de31f2a9144e48046201ead186a60189ca4ac",
"value": "0x3644f85fa6f69f31236d3f57a9eb33c9b6215f3599c3ab765f7e5885660cbb12",
"debugDepth": "0x01",
"debugHash": "0x9216bc6261f0cf48198c006164f9e5a0a05032e8e658f506ce64b006d02e2331"
}
],
"debugDepth": "0x00",
"debugHash": "0x4b7082248440f9d040a2f7f55a4177c4f25a70f671aa0cb371b7bf189cc4fc68"
}
]
}

View File

@ -1,552 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x550f7029a2cf5a8540f63d9210f3eeec2153013317040065c533c0acdab2cd8e",
"error": false,
"tree": [
{
"nodeType": "0x00",
"mask": "0xEFFC",
"debugDepth": "0x00",
"debugHash": "0x550f7029a2cf5a8540f63d9210f3eeec2153013317040065c533c0acdab2cd8e"
},
{
"nodeType": "0x00",
"mask": "0x0260",
"debugDepth": "0x01",
"debugHash": "0x9f4a94996eb88336cd53f37f5d444f7fd2b98e8e9b450eb7b248b472696a0082"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x7e82a56264733a213ffcdd5a218bd999da849257",
"balance": "0xa3e8b6fbcfb7f4a791c7b597aac5cc93bbe5e8b4d299d290d4e79ebe97efa98af8d5e5d407",
"nonce": "0xb190b8fbc0d0c8936d",
"codeType": "0x00",
"codeLen": "0x1c",
"code": "0x55ef5ace99c1023203252cdf1ffa0bb23ac3d37a1eba1da733ee43ab",
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x02",
"debugHash": "0x1967ef43921054004b23174b05ad795499bffbbe93dcab9cc1440d8d12f18350"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x5e3eea97a4565105f98032ef418d883eef902a1f",
"balance": "0xb591a18ee5f3b4d485f3ce85d397c5ffbb9c87dbfec3f881a2c4ee85bbf8a7baccf2b99b03",
"nonce": "0xe2a98eccf69288ca03",
"debugDepth": "0x02",
"debugHash": "0x0df000b5883e85bfc2bd0f2af715b607a3c8201065719beb4b0f3576cf42954a"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x4e53d140f9555fba626103f37741849fa64e9de1",
"balance": "0xfbdcd5fa8bc1d0d8dfb5ebaaf9e3abaa91d6c8f6d5ffc18cbe9485d4b2c2ccb5eef790a401",
"nonce": "0xf2b2acced7e1a4fba801",
"debugDepth": "0x02",
"debugHash": "0x589041613b78de52cd96f1e7defa29a80f9fb58001bb757f33a31ba86f1a2838"
},
{
"nodeType": "0x00",
"mask": "0x1100",
"debugDepth": "0x01",
"debugHash": "0x083da979966f48e2c5a6777f5f5c1b80a70f1bc66dee2bf8615dbbd5dfcff6f4"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x8c095521efe5fa9541e286f4747ea2153c0c6e87",
"balance": "0xa2dafbd7e5d6c581aedcdc82f696dca0d581859eefa0e1cb8e8ec7bad4d885b996a7b9e005",
"nonce": "0xfdf7aacac6d982da9801",
"debugDepth": "0x02",
"debugHash": "0x1010d6c54f31785bfb342a7baac249957fefd79fef1c691f51f2c90a8cd28a82"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x0d9a1172cfdfc7cb8db0ebf9c74f8bc816d1594f",
"balance": "0x82f2b5a8d7b88df1c899debaf69dea83bba6b8f4d7efe2bbc3dab4e8edcfe8d1bb8884ce09",
"nonce": "0x82c5df84d7f3c0b502",
"codeType": "0x00",
"codeLen": "0x71",
"code": "0x7fac9431579dea7e21b894993c8eace8238fe594ce4de5ba6b17dbe4059c9c0ac7ccdeb5cb8dc7d4b8535832c5e1a01001c200ac8c14fc3a6085cd45bd178f094746ef5bd2f2b07782b1a92c120e7e994699001e2c7127a91df8c18a8f118bb3c6b7f8c7f14916ec94726ade5756f4e692",
"storage": [
{
"nodeType": "0x02",
"key": "0x32a0b97a49bc4b41275f2c6cf1afb44fe15e0597da428a46a4f28c1e34ba7f49",
"value": "0x7ce1875ff13e5274f09bbfee4ce2454eed95eb3ef13fe0d41cfe8184a8416d88",
"debugDepth": "0x00",
"debugHash": "0x7c9b62bcb983d19eb1ce478b773166924971a20f40edf2bb489825fbc0bd1803"
}
],
"debugDepth": "0x02",
"debugHash": "0x9b7724ac4ea19385dd9747ad0d27b940bf0e6e588588b07b54957e37aa77915a"
},
{
"nodeType": "0x00",
"mask": "0x1C00",
"debugDepth": "0x01",
"debugHash": "0x328fb899d5b2cd098baa71272cd0c75dac0886774d74d2a2d58d9b345935c472"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0xffa97a82be3512beda8de06865e8ca5a9c7f86a8",
"balance": "0xa2a0a7ccf4ebf38cfcae9f94c0e8c2ecb1b5a499b2a0ad8cc8d7dac4e0bbf0e9f2ad88980d",
"nonce": "0xddf7d0f1c2ddf0a97a",
"codeType": "0x01",
"codeLen": "0x35",
"codeHash": {
"nodeType": "0x03",
"data": "0x287a92b81f6a48744403ad694e309b7e06865b02685644bfcc739afb46ee0cf8"
},
"storage": [
{
"nodeType": "0x02",
"key": "0x715fe227be869e650b1c18b68011be30002e297b17890fb87b95797bc224ed7e",
"value": "0xee15a1528a177599e0706e2adcb132086011475675e883e92a7ca6d8c28f6630",
"debugDepth": "0x00",
"debugHash": "0xb367a969b00fd441ceb23bf718d1b9e8d382036dbfbefe0f1b803bdf92c67a70"
}
],
"debugDepth": "0x02",
"debugHash": "0x466e4aab91b42fa821df749033d11708d222db09f24c73d929cf51c5cd739695"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x2b2e60e1321308f0ca88b430a0a8882a7f2c804c",
"balance": "0xfb88a5eac9aae3fda29af9a8d7a7b593b2a6cbc0d2fca0efe2a282adbed4a692e0cbe8b507",
"nonce": "0xc9beceb1abd8f1ebfc01",
"debugDepth": "0x02",
"debugHash": "0x114ead6a99a020b05538a991a984997dbb7ae5587f666a84d549cf8bf3fe0569"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x200bf417f0def72a080fcab1ffa05d2830e688cc",
"balance": "0xaecee8d5a5aef2e7868aa3edbbefaedcf8f582c4fb8780f1cceecfa5ae99fde88be5ceb103",
"nonce": "0x84e2c9dec5c0c48eff01",
"codeType": "0x01",
"codeLen": "0x00",
"codeHash": {
"nodeType": "0x03",
"data": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
},
"storage": [
{
"nodeType": "0x03",
"data": "0x012298ef3a049f2e882b7f02bdd5ed14b8ceaa397b8044a655071c183443974d"
}
],
"debugDepth": "0x02",
"debugHash": "0x65862fef5dd243421555ef135984f0f58b16214a084709dc8af3174a0e41897a"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x21650b3a41a04a687a787e7699c1e9154204dd72",
"balance": "0x80fab99bf190d6f3c7cbdda293ec87f3e7ede9da87a1c8ede38ec4d1d0d2989bd8d3e5bd05",
"nonce": "0xcff9c7aeb2c1f2d2f601",
"codeType": "0x00",
"codeLen": "0x74",
"code": "0x8846e1571b671559b35c69c83a21b831fac866552aa0f9bcdafb892aa1dfc3d630e4bc04b06968d8efb0801884df61f5f433e5f98e8b3f37c333f531559079868e0d4b1676007477857548c83c902cdd86889a6f75050e9e5e4cf545979dd333616b3d3d38ea4585df4123fcf416f1d7922d8f1a",
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x01",
"debugHash": "0x4849fba014fefc2334af528cdbf71d864e54adc8c73d9aed0e98e0a21f2e3d1a"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x9bd73033c374e374b0c377a5230ba96d2ac74acb",
"balance": "0xa785e48c85a7c89ac2f3d3c7f19ae4a2ffa594c0e0acf3e9d8fbc2b386cdcedbabc2abb009",
"nonce": "0xb0a1eb9be1eadef4d901",
"codeType": "0x00",
"codeLen": "0x00",
"storage": [
{
"nodeType": "0x03",
"data": "0x8294e6e0606231185bdf41da7fc63de48164c15b98f0159290c758e44374e510"
}
],
"debugDepth": "0x01",
"debugHash": "0x3e38ce6c0bb9d113cdec3368f2e1339088e14a0ca55d49ff0d50061a7bb2c864"
},
{
"nodeType": "0x00",
"mask": "0x0012",
"debugDepth": "0x01",
"debugHash": "0x5beed605dc01452aa4f1d21ba8ef73737ceddb240c52d441c7294eaa1680a34c"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0xa4339d77b9e78b3da6c525dabe94361d359accb7",
"balance": "0xe1f7cbabfb83f1ae96b3b780a8ff9fedcb96b4869af0d0e5a0dea7ef9194d5f6dda8c58c0b",
"nonce": "0xf69ee596a9eefd8e13",
"codeType": "0x00",
"codeLen": "0x73",
"code": "0x81e13a7f3dac825c46ae3d5c78183347460a5be6d6c74a6db406581a1c768e8ca6956037a767bbb646f52acfccbe7df13fb547df5421b9ef338d975cbbd1ae1c7b30660941f380bc70c4129f9164e017082f13ef5e5c4d20b27131e1dfd3028a48ab165ccdd73d497a2be10c1dea936badba90",
"storage": [
{
"nodeType": "0x03",
"data": "0x2a96d4ab3c1695b5f724d82877cfdf49bf2205e5df690f9aa69c74d7d44cf5d5"
}
],
"debugDepth": "0x02",
"debugHash": "0x514734ee243da65ac9e3cf6b82a46e6ea2a4b73f40e9dab84e633a90fbe20689"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x25fbbd3025c0d58df78959aa62625df228accae5",
"balance": "0xc3dbeebcd483a4849086a7feb8b7b094d7a2c4dce2ecb4e1fcb2bd899bdba8e3ad9dd6a604",
"nonce": "0x9ff2db9ffb8b85f8ee01",
"debugDepth": "0x02",
"debugHash": "0x3d1eb4951424196849d3fb044c0f7fb6fc8ec6535df8b43f66bb42115a2ffe30"
},
{
"nodeType": "0x00",
"mask": "0xA200",
"debugDepth": "0x01",
"debugHash": "0xaa43092e6689861ee517fc806ff58a413c2fc7892deffa7c2f96c1420c9f7727"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x5a82d40f3a15434eca11825c21b250e4a795526a",
"balance": "0xbb89f9a7cee1b08295f7fcc0edcae681f2d9e99bfbdaffbda0edc3e290bfb2c6d2d9b8b203",
"nonce": "0xc2fbfea5e198f59dba01",
"codeType": "0x00",
"codeLen": "0x23",
"code": "0x491b0781509547a5312567a6cf15f01c2722df7b30bfbc92ffd323acbeafb470c144fd",
"storage": [
{
"nodeType": "0x02",
"key": "0xb71cf463f922b0517bebf1da1903d6e5c276460afec3b1254562bfdae97766a9",
"value": "0x9102ff128ff12ea11191af870ec1d7a7c411f085eb0d18b37eb421a68c55f3aa",
"debugDepth": "0x00",
"debugHash": "0x5e9e575223be8c32ba09e7893a8c5565980eed31174c81108443250d26f60814"
}
],
"debugDepth": "0x02",
"debugHash": "0x26b8bcb90801173039330a43715332fe0e028692eb7b67a878abb602568879ff"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x68350d559adf571cb37c531f8ff3adbda04575f3",
"balance": "0xafe7d58ad18fa89ee58fdea9b5a6adc39888c1b4b39aa8b9f1a290c88db395baa58ab6a609",
"nonce": "0xd4ccb6cea398a6d238",
"codeType": "0x01",
"codeLen": "0x2d",
"codeHash": {
"nodeType": "0x03",
"data": "0xb8c8feb51d228c6228d812f867798c339f275abb0caa7b287b84d5cda7628190"
},
"storage": [
{
"nodeType": "0x03",
"data": "0xc6a2ab7bdc5aea78bfa5d4e587f7c0581fd5071e154eb0e95df5bf7882de0824"
}
],
"debugDepth": "0x02",
"debugHash": "0xa43857f15eb5ec8feb46411fbfa867e9fd14079f14a8002e5927f320538522e5"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x3d90a6de4db54512c71781c5d69d945034f86a85",
"balance": "0xdb8df2d6a4b590ca86bf80f39e9eb18f94bafecbcad187c6b6c68ca2afe4b7bdf0fcbf9a0d",
"nonce": "0x95dfb8c8cdf9cdbaf101",
"debugDepth": "0x02",
"debugHash": "0x1492b6fd1a6655bb8c6bc0b89b36308316d6d15edb78e0f1edc213dc6d30bb5b"
},
{
"nodeType": "0x00",
"mask": "0x6000",
"debugDepth": "0x01",
"debugHash": "0x50ada0e13e97d062e7c2cf197e0c1e81ab0a07dc2814f999560a3bbcb15c84f7"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x8659163d026652d6e1f7ca0661222619f337e77c",
"balance": "0xdfa4d3a3ffd4eceefe90cda6c3e5a8ddade5b8b192a996e499a8a9d5cabfc3bd8ecbfcf707",
"nonce": "0xaccca8efed91e9a3be01",
"codeType": "0x00",
"codeLen": "0x5a",
"code": "0x361e7dec35956b2930c232cd6eace370710e5699a1ba8149ac1ebe4d6cbeb6a72c7c4563cc02e1779618c9f9b9b60651d70d2c0789b2b2d729582822243a2e31f74f7ec9c2e23ffa9477b73291c913f46a54d70100d420c6a55f",
"storage": [
{
"nodeType": "0x03",
"data": "0x23afb0029e5bb7b18f434cc4f94aecc17f9b0bc535db5dc2fde3b02977456cfd"
}
],
"debugDepth": "0x02",
"debugHash": "0x9b159719b97763ab2592d8200734e3ce78c0bf566e67ea282c3ddf786ae42a11"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0xb2adbc8a2593561d490c3e9ae84971b1805f9458",
"balance": "0xbcc4a198d9f4c4db8add8dad909c9ae6fde8a8dff6ffb78cafcfd8cbb7b6c6faf7d2f1ec05",
"nonce": "0xa695a6d9e6bcbdea8101",
"debugDepth": "0x02",
"debugHash": "0x7d7e4c6477332ec28b116e0e45f64c89a193bc7be23b6f59f3842b0ee9fdbec1"
},
{
"nodeType": "0x00",
"mask": "0x0500",
"debugDepth": "0x01",
"debugHash": "0xa4e9de182f32f89dd9d116e28e4485bda488643e1035c4e9257f4609ac88d58f"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0xc61222cc7e65887ce773e993a802d66d94bba0f9",
"balance": "0xcbdd8ad9b2e0f5b5c0cebaadcf89cef7fafaf1f4ff87b5c9f0c5c4b5f1f5d081eda487a409",
"nonce": "0xf8c0be88fadcbbcd9501",
"codeType": "0x00",
"codeLen": "0x00",
"storage": [
{
"nodeType": "0x02",
"key": "0x4a34ae1657e74becf881a35f189835e9368fbae8516d2859b3fdbeca07aa8f3f",
"value": "0x1cfd3004e237243633ee5fbd6503f938de86530004f08bc249dc1abdc0b35b99",
"debugDepth": "0x00",
"debugHash": "0xe519de5d80c8bbe1330e491b42cc0727fef93531d18f0461edfdf7192947c043"
}
],
"debugDepth": "0x02",
"debugHash": "0x3d8029187f65bb81ea29f2f58531b2b6c9eb585608fbc8fd336a7c8e08ce92b0"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0xe611fcf90e8484fd09f0cfd38bc53c82b006dd9e",
"balance": "0x9cbdbfbcafb9ca84a6d09998d8fca291d29ffff68592c8cdf5dc89b4a88bf386deb9aeaa0f",
"nonce": "0xaac2f898cadb8aac8301",
"codeType": "0x00",
"codeLen": "0x00",
"storage": [
{
"nodeType": "0x03",
"data": "0x4a68a9d749f0ad92cc7227793335f251bd1eeb1fb71feb286b372e64daac227b"
}
],
"debugDepth": "0x02",
"debugHash": "0x7e13c9c259bccdbb16d47ba493b0d4d8f1f6e2dc2add466f5eb196ba7ccce27d"
},
{
"nodeType": "0x00",
"mask": "0x0021",
"debugDepth": "0x01",
"debugHash": "0xe546754c720e62df8f96752d1f6f33c6c0d0112c77795feeaec6c5ae34838dce"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x125324c1125eea8cbfe6c6417b5db7d0213b07d0",
"balance": "0xd38ae7b2a7f9e5bbcfddcde68ca2a5eeec8ba3ddcab29bd8a5e9c99d99c4b8cf95bab4c30b",
"nonce": "0xd9c1a4e99a8797e48301",
"codeType": "0x00",
"codeLen": "0x00",
"storage": [
{
"nodeType": "0x02",
"key": "0x9f81659503482f67f747dd0a25a4e55b84bbe55933f3082be384ab99aa61f6fa",
"value": "0x9971505b88b5b7e20a56df1df54be099f3457751cca98ba43055b38dabc2f7cd",
"debugDepth": "0x00",
"debugHash": "0x9913a588d20876ba9d16aba4272cd364971af214d1a4153784d51d3884b4f815"
}
],
"debugDepth": "0x02",
"debugHash": "0x5c6baec0dfe8badb90634561a7d87645e21c3d8e9e58dfeb62d6fe6bf23a9f31"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0xfb3ead2e001376237f144fb21279ded073a795dc",
"balance": "0xd0fdffaf95c7e5a0c0e6e285858f85f2dbb18d9ecbc68c9981f0b4d598c1ec94dadbc36b",
"nonce": "0xf786fdcab8faf4c307",
"debugDepth": "0x02",
"debugHash": "0xf212c3dc84a139f1a38077a337a3b16da4837d4c0e3e62b7265a08c9040f6dae"
},
{
"nodeType": "0x00",
"mask": "0x4104",
"debugDepth": "0x01",
"debugHash": "0x22d9d7948fa08ceab4c275bba8bf7a21fc522a4c63b85d33f41244dd5f88e217"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x6bfbdf61b0350adf2d9bfb95566b9a44ff8498a3",
"balance": "0xce92abf7e1e987accdfad682a4f0f6eabc9eddd3b2e5e4c6c6ad8db2e6a1f8dd89b1bab10f",
"nonce": "0xac95ecc8c1d7ddbce601",
"debugDepth": "0x02",
"debugHash": "0xc0c71493b2cdf9344b47c525ac7abb6f0f3737dcbd352df4166008f6da889842"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0xf6bdbc998413b9aba0ad47481126f04652f174a9",
"balance": "0xc3c58bd6c693d2ef83a895caabdbd5e5f0d79fb188fb83f1bbcbfecac896ac9eeb8eb9a70f",
"nonce": "0x8de5fdc68ccaf3ebbc01",
"codeType": "0x01",
"codeLen": "0x1e",
"codeHash": {
"nodeType": "0x03",
"data": "0xdc480c80186f0489d6fa64a296dbd719668fa828c2049ba669219cf219a792fb"
},
"storage": [
{
"nodeType": "0x02",
"key": "0x6b382cc3c8c4729021a9d037022b0dbb76222ce3508afc528d08f1526a6dd9f0",
"value": "0x4bd2f8313e0f628860e2a4df80f7127f6ee702490dae207eb4943652d8cfb31b",
"debugDepth": "0x00",
"debugHash": "0x084cfc59a9738a93e43f97ff4a95c75d1b656d44b7494d47e0740b6dd55e8dac"
}
],
"debugDepth": "0x02",
"debugHash": "0x241c229777bbf37aa07fc58013728f97982b4405b091c140383baf5aa55f4938"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0xed0747eab87cddcbcfed24fc0b4efad5f42850aa",
"balance": "0xe2fdf3c19da1a5ce96a584f289c6f9dff5d9b894e39afcbe83c39c83f394be8fd780a173",
"nonce": "0xb7869dd4a18482acca01",
"codeType": "0x01",
"codeLen": "0x00",
"codeHash": {
"nodeType": "0x03",
"data": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
},
"storage": [
{
"nodeType": "0x02",
"key": "0xc2ca9211965601a2d393f576e44497b0ec820d40099a5fb295bb9efef0a14d71",
"value": "0xa6e9d4b25b32bda3dab519b8a2335b47fd4d8ba1261aa1fa4669f9ec92f07205",
"debugDepth": "0x00",
"debugHash": "0x2218c60510cba020a5eb26d98bd3b90d7436844f0d515c247c5ca93937b83e05"
}
],
"debugDepth": "0x02",
"debugHash": "0x9e551d743e6940f98f6dd1569c91969f759da53e3871b7c8e8de96cd1d28c66f"
},
{
"nodeType": "0x00",
"mask": "0x1080",
"debugDepth": "0x01",
"debugHash": "0xf891936886af1bf2c61e9cc813f02b310f9f66290c32c63adc5fb874631963b9"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x6237190cfd2f7a51e4ef8da5dd65b740e7b9d2b0",
"balance": "0xfbaed58ebfaad8a5ddedb1a0d1bea295ecdfd5a9c9f1b4b68f8b8184c9cffdd6b3edd69905",
"nonce": "0xcac9b4a5d9aae79969",
"codeType": "0x00",
"codeLen": "0x00",
"storage": [
{
"nodeType": "0x03",
"data": "0x3c0c419d914676bc52fbf527370bec8c4a9fda5d5cf6029e1535300cbf9cb5fb"
}
],
"debugDepth": "0x02",
"debugHash": "0x35ac5d7a202206c0f02dd464bbf9445f571733f081fe6adb8cb36f5767eab678"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x73d940cb1e6963a1234c2ae1ebae388cbfc6666c",
"balance": "0xb198a8b5d59efb9a9781f295ede3a8bdcb9490f383bce4b4f6ab98ceeddacbccbccb95a50c",
"nonce": "0x96ab91a0f1a490e370",
"debugDepth": "0x02",
"debugHash": "0x044e8b1beeda914bdf5cc888275af44de4517204745111d4feb8f755fdf8ce05"
},
{
"nodeType": "0x00",
"mask": "0x4030",
"debugDepth": "0x01",
"debugHash": "0x2205eac67196e6c0d0be7e4c47b4a9fd0fb668f5496ce6bb3ad57b25680b4631"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x7c55aa59700a5ef1440452f6a6e97af67796fc63",
"balance": "0x91eca584b2dd8896c6a299bae7ade2acacc6eefec8bfedf3eee4a5bfbcf79c8cd2cee1d60c",
"nonce": "0xc3eac180c0dabbdc55",
"debugDepth": "0x02",
"debugHash": "0x33b835c937442c856fdfd5a0f9ca61e57b50359ac4551d70532db20ee3d7aa63"
},
{
"nodeType": "0x00",
"mask": "0x00A0",
"debugDepth": "0x02",
"debugHash": "0x6cc62b401d6fc829a72bd7b4ea5c3a0ca300bcbb248ec3145217416772307a5e"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x66c622e5d6fb2aa939459dd2092f09fdc4a9bc89",
"balance": "0xbbf4829d9ef88093d1a2e2a2c9f7e5f6deb7f0ddc7f99f9eb9b2eac9f3f6f8a3ce8ec237",
"nonce": "0x9db6d2c0f9d9ac9def01",
"codeType": "0x01",
"codeLen": "0x00",
"codeHash": {
"nodeType": "0x03",
"data": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
},
"storage": [
{
"nodeType": "0x03",
"data": "0xf6ae1bfb1bab034c671b20634b07703ec57d7620fe94a3ff1d43319f81359403"
}
],
"debugDepth": "0x03",
"debugHash": "0xfc06383f3e720f7e8c7f811047fe1bf71307cbad113402f749d56f295072e506"
},
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0xfeac1e36a9ea61bfa477edf9193312e11e9211a5",
"balance": "0xc0d7ccee85edd3f3f9e1d4df91b1dbd68ec1dedbcb98b6bca1daa0b5a0ebebb28d9e9ad502",
"nonce": "0x9edf86e5a0d6b8ca73",
"codeType": "0x00",
"codeLen": "0x5c",
"code": "0x2e12ba0c7dbbf09e0ef55fb3e40fcaf5c46d36a0fee73c811443f9a6126e3ea2b8d251dbeb47e5366b7e6e89ce4a7c21026523942f8fc0b707122c6ab170422a2419444ba035d710825b6e2a8a687678dd01fb23fd259020863e155d",
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x03",
"debugHash": "0xc0d68acbd64bc9c645ba6990db6b6ec11a880d3d1ebc3ab11ebbcc89ee67dde3"
},
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x6b786876ea119d95258e9f4b11a08c6f18a20721",
"balance": "0xb7ff8da3eaacdcc7e5d7d9d9c2eddafeb8f1c1d1f4fcf0f2b3df98899bfdfcb18c87808a02",
"nonce": "0x96a290c4f689bced50",
"debugDepth": "0x02",
"debugHash": "0x978e501b6422b28254c8bddb760622c0eea111ee008a915481b48aaa986426a1"
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0xAA0e7dabd304f1acd44786d3ac613a5f2ff66b77",
"balance": "0x8cf8c7f1f3ffad95bce2f996d7e1f5a6d9aa96efce9ccba59789dcd6dce3969cc99bc9c50e",
"nonce": "0xe3f483f981dee9db5e",
"debugDepth": "0x00",
"debugHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4"
}
]
}

View File

@ -1,17 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x080e7dabd304f1acd44786d3ac613a5f2ff66b77",
"balance": "0x8ef8c7f1f3ffad95bce2f996d7e1f5a6d9aa96efce9ccba59789dcd6dce3969cc99bc9c50e",
"nonce": "0xe3f483f981dee9db5e",
"debugDepth": "0x00",
"debugHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4"
}
]
}

View File

@ -1,26 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x3ef071a43e07a7a209d4a67f9edd05477e8e3ac30af64656cfe784961fd2433a",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x720ef0ee74f1b3b8252eb3270d484b223f775810",
"balance": "0xb3c2cee7e2cb9289c8cdd1d9b99ff0e7829fdce2f5afd2fca6a2ff9f9bf8e38493d09bc403",
"nonce": "0xad83abd1899ad9ee56",
"codeType": "0x00",
"codeLen": "0x3d",
"code": "0xefda93a915fe9ac8998e195a5fe0bb85a2474e676551e8978cba5b5ea3af0dc90606fd0e6d4f07b0262ada94b579676f51e4226b2dc456be061e99",
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x3ef071a43e07a7a209d4a67f9edd05477e8e3ac30af64656cfe784961fd2433a"
}
]
}

View File

@ -1,26 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x3ef071a43e07a7a209d4a67f9edd05477e8e3ac30af64656cfe784961fd2433a",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x720ef0ee74f1b3b8252eb3270d484b223f775810",
"balance": "0xb3c2cee7e2cb9289c8cdd1d9b99ff0e7829fdce2f5afd2fca6a2ff9f9bf8e38493d09bc403",
"nonce": "0xad83abd1899ad9ee56",
"codeType": "0x00",
"codeLen": "0xee56",
"code": "0x09ddefda93a915fe9ac8998e195a5fe0bb85a2474e676551e8978cba5b5ea3af0dc90606fd0e6d4f07b0262ada94b579676f51e4226b2dc456be061e99",
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x3ef071a43e07a7a209d4a67f9edd05477e8e3ac30af64656cfe784961fd2433a"
}
]
}

View File

@ -1,17 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x080e7dabd304f1acd44786d3ac613a5f2ff66b77",
"balance": "0x8cf8c7f1f3ffad95bce2f996d7e1f5a6d9aa96efce9ccba59789dcd6dce3969cc99bc9c50e",
"nonce": "0xEEe3f483f981dee9db5e",
"debugDepth": "0x00",
"debugHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4"
}
]
}

View File

@ -1,26 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x3ef071a43e07a7a209d4a67f9edd05477e8e3ac30af64656cfe784961fd2433a",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x720ef0ee74f1b3b8252eb3270d484b223f775810",
"balance": "0xb3c2cee7e2cb9289c8cdd1d9b99ff0e7829fdce2f5afd2fca6a2ff9f9bf8e38493d09bc403",
"nonce": "0xad83abd1899ad9ee56",
"codeType": "0x00",
"codeLen": "0xad9ee56",
"code": "0x09ddefda93a915fe9ac8998e195a5fe0bb85a2474e676551e8978cba5b5ea3af0dc90606fd0e6d4f07b0262ada94b579676f51e4226b2dc456be061e99",
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x3ef071a43e07a7a209d4a67f9edd05477e8e3ac30af64656cfe784961fd2433a"
}
]
}

View File

@ -1,18 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x00",
"accountTypeSub": "0x07",
"address": "0x080e7dabd304f1acd44786d3ac613a5f2ff66b77",
"balance": "0x8cf8c7f1f3ffad95bce2f996d7e1f5a6d9aa96efce9ccba59789dcd6dce3969cc99bc9c50e",
"nonce": "0xe3f483f981dee9db5e",
"debugDepth": "0x00",
"debugHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4"
}
]
}

View File

@ -1,29 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x205aea15c1e739b4acdae0cc3b57c34f55907a73",
"balance": "0x8ca589e2e38294c9899abddfbbe887c9bbc5d296eda1f59b8180d8d88883c88d9a86bdba06",
"nonce": "0xa3e99cc2e5e5e5d6ce01",
"codeType": "0x01",
"codeLen": "0xa3e99cc2e5e5e5d6ce01",
"codeHash": {
"nodeType": "0x03",
"data": "0x8dd74346f58c605477239378ca66f42e8a75b9cc8aea3287ad30c8a5932a92da"
},
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d"
}
]
}

View File

@ -1,29 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x205aea15c1e739b4acdae0cc3b57c34f55907a73",
"balance": "0x8ca589e2e38294c9899abddfbbe887c9bbc5d296eda1f59b8180d8d88883c88d9a86bdba06",
"nonce": "0xa3e99cc2e5e5e5d6ce01",
"codeType": "0x01",
"codeLen": "0xcc2e5e5e5d6ce01",
"codeHash": {
"nodeType": "0x03",
"data": "0x8dd74346f58c605477239378ca66f42e8a75b9cc8aea3287ad30c8a5932a92da"
},
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d"
}
]
}

View File

@ -1,29 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x205aea15c1e739b4acdae0cc3b57c34f55907a73",
"balance": "0x8ca589e2e38294c9899abddfbbe887c9bbc5d296eda1f59b8180d8d88883c88d9a86bdba06",
"nonce": "0xa3e99cc2e5e5e5d6ce01",
"codeType": "0x07",
"codeLen": "0x5e",
"codeHash": {
"nodeType": "0x03",
"data": "0x8dd74346f58c605477239378ca66f42e8a75b9cc8aea3287ad30c8a5932a92da"
},
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d"
}
]
}

View File

@ -1,29 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x205aea15c1e739b4acdae0cc3b57c34f55907a73",
"balance": "0x8ca589e2e38294c9899abddfbbe887c9bbc5d296eda1f59b8180d8d88883c88d9a86bdba06",
"nonce": "0xa3e99cc2e5e5e5d6ce01",
"codeType": "0x01",
"codeLen": "0x5e",
"codeHash": {
"nodeType": "0x04",
"data": "0x8dd74346f58c605477239378ca66f42e8a75b9cc8aea3287ad30c8a5932a92da"
},
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d"
}
]
}

View File

@ -1,17 +0,0 @@
{
"version": "0x01",
"metadata": "0x01",
"rootHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x080e7dabd304f1acd44786d3ac613a5f2ff66b77",
"balance": "0x8cf8c7f1f3ffad95bce2f996d7e1f5a6d9aa96efce9ccba59789dcd6dce3969cc99bc9c50e",
"nonce": "0xe3f483f981dee9db5e",
"debugDepth": "0x00",
"debugHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4"
}
]
}

View File

@ -1,17 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4",
"error": true,
"tree": [
{
"nodeType": "0x06",
"accountType": "0x00",
"address": "0x080e7dabd304f1acd44786d3ac613a5f2ff66b77",
"balance": "0x8cf8c7f1f3ffad95bce2f996d7e1f5a6d9aa96efce9ccba59789dcd6dce3969cc99bc9c50e",
"nonce": "0xe3f483f981dee9db5e",
"debugDepth": "0x00",
"debugHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4"
}
]
}

View File

@ -1,29 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x205aea15c1e739b4acdae0cc3b57c34f55907a73",
"balance": "0x8ca589e2e38294c9899abddfbbe887c9bbc5d296eda1f59b8180d8d88883c88d9a86bdba06",
"nonce": "0xa3e99cc2e5e5e5d6ce01",
"codeType": "0x01",
"codeLen": "0x5e",
"codeHash": {
"nodeType": "0x03",
"data": "0x8dd74346f58c605477239378ca66f42e8a75b9cc8aea3287ad30c8a5932a92da"
},
"storage": [
{
"nodeType": "0x04",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d"
}
]
}

View File

@ -1,17 +0,0 @@
{
"version": "0x02",
"metadata": "0x00",
"rootHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x00",
"address": "0x080e7dabd304f1acd44786d3ac613a5f2ff66b77",
"balance": "0x8cf8c7f1f3ffad95bce2f996d7e1f5a6d9aa96efce9ccba59789dcd6dce3969cc99bc9c50e",
"nonce": "0xe3f483f981dee9db5e",
"debugDepth": "0x00",
"debugHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4"
}
]
}

View File

@ -1,18 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x00",
"accountTypeSub": "0x01",
"address": "0x080e7dabd304f1acd44786d3ac613a5f2ff66b77",
"balance": "0x8cf8c7f1f3ffad95bce2f996d7e1f5a6d9aa96efce9ccba59789dcd6dce3969cc99bc9c50e",
"nonce": "0xe3f483f981dee9db5e",
"debugDepth": "0x00",
"debugHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4"
}
]
}

View File

@ -1,29 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x205aea15c1e739b4acdae0cc3b57c34f55907a73",
"balance": "0x8ca589e2e38294c9899abddfbbe887c9bbc5d296eda1f59b8180d8d88883c88d9a86bdba06",
"nonce": "0xa3e99cc2e5e5e5d6ce01",
"codeType": "0x02",
"codeLen": "0x5e",
"codeHash": {
"nodeType": "0x03",
"data": "0x8dd74346f58c605477239378ca66f42e8a75b9cc8aea3287ad30c8a5932a92da"
},
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d"
}
]
}

View File

@ -1,29 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d",
"error": true,
"tree": [
{
"nodeType": "0x02",
"accountType": "0x01",
"address": "0x205aea15c1e739b4acdae0cc3b57c34f55907a73",
"balance": "0x8ca589e2e38294c9899abddfbbe887c9bbc5d296eda1f59b8180d8d88883c88d9a86bdba06",
"nonce": "0xa3e99cc2e5e5e5d6ce01",
"codeType": "0x01",
"codeLen": "0x5e",
"codeHash": {
"nodeType": "0x02",
"data": "0x8dd74346f58c605477239378ca66f42e8a75b9cc8aea3287ad30c8a5932a92da"
},
"storage": [
{
"nodeType": "0x03",
"data": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
}
],
"debugDepth": "0x00",
"debugHash": "0x12d52947c2ec748f833d7d13d78ffac0594834a5e6d8e4e32831f4717eefc64d"
}
]
}

View File

@ -1,18 +0,0 @@
{
"version": "0x01",
"metadata": "0x00",
"rootHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4",
"error": true,
"tree": [
{
"nodeType": "0x02",
"nodeTypeSub": "0x00",
"accountType": "0x00",
"address": "0x080e7dabd304f1acd44786d3ac613a5f2ff66b77",
"balance": "0x8cf8c7f1f3ffad95bce2f996d7e1f5a6d9aa96efce9ccba59789dcd6dce3969cc99bc9c50e",
"nonce": "0xe3f483f981dee9db5e",
"debugDepth": "0x00",
"debugHash": "0x5b6f632c9fe4ab50cc0f4d09b38235a3a6afbe85048af44bae35297795a932f4"
}
]
}

View File

@ -1,69 +0,0 @@
# Nimbus
# Copyright (c) 2020-2023 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import random, sets, nimcrypto/sysrand
type
RandGen*[T] = object
minVal, maxVal: T
Bytes* = seq[byte]
proc rng*[T](minVal, maxVal: T): RandGen[T] =
doAssert(minVal <= maxVal)
result.minVal = minVal
result.maxVal = maxVal
proc rng*[T](minMax: T): RandGen[T] =
rng(minMax, minMax)
proc getVal*[T](x: RandGen[T]): T =
if x.minVal == x.maxVal: return x.minVal
rand(x.minVal..x.maxVal)
proc randString*(len: int): string =
result = newString(len)
discard randomBytes(result[0].addr, len)
proc randBytes*(len: int): Bytes =
result = newSeq[byte](len)
discard randomBytes(result[0].addr, len)
proc randPrimitives*[T](val: int): T =
type
ByteLike = uint8 | byte | char
when T is string:
randString(val)
elif T is int:
result = val
elif T is ByteLike:
result = T(val)
elif T is Bytes:
result = randBytes(val)
proc randList*(T: typedesc, fillGen: RandGen, listLen: int, unique: static[bool] = true): seq[T] =
result = newSeqOfCap[T](listLen)
when unique:
var set = initHashSet[T]()
for len in 0..<listLen:
while true:
let x = randPrimitives[T](fillGen.getVal())
if x notin set:
result.add x
set.incl x
break
else:
for len in 0..<listLen:
let x = randPrimitives[T](fillGen.getVal())
result.add x
proc randList*(T: typedesc, fillGen, listGen: RandGen, unique: static[bool] = true): seq[T] =
randList(T, fillGen, listGen.getVal(), unique)

View File

@ -1,197 +0,0 @@
# How to build multiproof block witness from state trie
The [block witness spec](https://github.com/ethereum/stateless-ethereum-specs/blob/master/witness.md) define the
binary format in BNF form notation. It will help the trie builder implementer quickly implement a working block
witness parser using simple LL(1) parser.
If you have a working `Hexary Trie` implementation, you'll also probably can quickly implement a working witness
builder for a single proof. You don't need to alter the algorithm, you only need to alter the output.
The output will not an `Account` anymore, but binary block witness containing one proof for single `Account`.
However, the block witness spec does not provide specific implementation algorithms. You might already know
how to generate a single proof block witness, but how to generate a block witness contains multiple proofs?
You can try to read [turbo geth's multiproof algorithm](https://github.com/ledgerwatch/turbo-geth/blob/master/docs/programmers_guide/guide.md).
And I will try to provide an alternative implementation, a simpler to understand algorithm that require only minimum changes
in the single proof generation algorithm and delegate the details into `multi-keys` algorithm.
## Basic single proof
I assume you have basic knowledge of how `Merkle Patricia Trie` works. As you probably already know, `Hexary Trie` have 4 types of node:
* __Leaf Node__
A leaf node is a two elements node: [nibbles, value].
* __Extension Node__
An extension node also a two elements node: [nibbles, hash to next node].
* __Branch Node__
A branch node is a 17 elements node: [0, 1, ..., 16, value]. All of 0th to 16th elements are a hash to next node.
Every time you request a node using a hash key, you'll get one of the 3 types of node above.
### Deviation from yellow paper
* In the Yellow Paper, the `hash to next node` may be replaced by the next node directly if the RLP encoded node bytes count
less than 32. But in a real Ethereum State trie, this never happened for account trie. An empty RLP encoded `Account` will have length of 70.
Combined with the Hex Prefix encoding of nibbles, it will be more than 70 bytes. Short Rlp node only exist in storage trie
with depth >= 9.
* In Yellow Paper, the 17th elem of the `Branch Node` can contains a value. But it always empty in a real Ethereum State trie.
The block witness spec also ignore this 17th elem when encoding or decoding `Branch Node`.
This can happen because in Ethereum `Secure Hexary Trie`, every keys have uniform length of 32 bytes or 64 nibbles.
With the absence of 17th element, a `Branch Node` will never contains leaf value.
* When processing a `Branch Node` you need to emit the `hash to next elem` if the elem is not match for the current path nibble.
* When processing a `Leaf Node` or an `Extension Node` and you meet no match condition, you'll also emit a hash.
If you try to build witness on something else that is not an `Ethereum Account` and using keys with different length,
you will probably need to implement full spec from the Yellow Paper.
## Multi keys
Before we produce multiproof block witness, let us create a multi keys data structure that will help us doing nibbles comparison.
### Sort the keys lexicographically
For example, I have 16 keys. Before sort:
```text
e26f87f8d83b61dbd890cda95c46c74f8d22067c323a89b58e6e8f561f2fb8ea
5e00236babd8b0737512348d0a6bae0ed3e69e76391a8f16085c1c7a4864a098
28d0cacafa7c17f7a9b759289c11908f3ca0783fc1940399b8e8c216dcccab2d
a1ba56edb2cfcd4914d5bfc35965be5b7df3fc289f8c8c4f3987aaf58196119a
5021c9457544d81b9870ab986ba52a1fccedd35df09c66de268ecdf289e1127d
bac9405b4813ac28cc27bc09fb6b27aefa3e341d3ab7f91c63f2482446abb28b
d676c8ea429a4b2e075538475c4cc89cf0251335d167cac2bb516a6cd046fbfd
df3585baa4162db6431f36ea2d70380b855cdb53203c707463b5df2c4ed573dc
903b206fc2b1aed80eecc439e7ce5049e955b1d5e7b784aadf1c424c99bd270a
26eb8904b00d91adf989f5919b71e8bdf96ded347ee25f8cceeb32fb68fb396f
6a52cf44e5d529973c5f8c10e4a88301076065529370776136b08ddf28617634
6c4cb76d2205904095b8ac41e9deb533ced6d3f5cc5c4f5a55d6abd50b21d022
850169badff8c49045afcb92bddaa59bf0aa3bd996d5a9a2f19984659e0df156
1d86f4ba779b3e61f65cd0f1b4eea004ddb1cd42b6294979447579e57bb32e02
b63e59b25dc10e89b04f622ca45cd3da097e1ba41ff2fe202ca0587c53fdbe98
5b0f8a5612111ffbc215a7fb82ee382c1a36f0035653c1f3fa3f520c83bee256
```
After sort:
```
1d86f4ba779b3e61f65cd0f1b4eea004ddb1cd42b6294979447579e57bb32e02
26eb8904b00d91adf989f5919b71e8bdf96ded347ee25f8cceeb32fb68fb396f
28d0cacafa7c17f7a9b759289c11908f3ca0783fc1940399b8e8c216dcccab2d
5021c9457544d81b9870ab986ba52a1fccedd35df09c66de268ecdf289e1127d
5b0f8a5612111ffbc215a7fb82ee382c1a36f0035653c1f3fa3f520c83bee256
5e00236babd8b0737512348d0a6bae0ed3e69e76391a8f16085c1c7a4864a098
6a52cf44e5d529973c5f8c10e4a88301076065529370776136b08ddf28617634
6c4cb76d2205904095b8ac41e9deb533ced6d3f5cc5c4f5a55d6abd50b21d022
850169badff8c49045afcb92bddaa59bf0aa3bd996d5a9a2f19984659e0df156
903b206fc2b1aed80eecc439e7ce5049e955b1d5e7b784aadf1c424c99bd270a
a1ba56edb2cfcd4914d5bfc35965be5b7df3fc289f8c8c4f3987aaf58196119a
b63e59b25dc10e89b04f622ca45cd3da097e1ba41ff2fe202ca0587c53fdbe98
bac9405b4813ac28cc27bc09fb6b27aefa3e341d3ab7f91c63f2482446abb28b
d676c8ea429a4b2e075538475c4cc89cf0251335d167cac2bb516a6cd046fbfd
df3585baa4162db6431f36ea2d70380b855cdb53203c707463b5df2c4ed573dc
e26f87f8d83b61dbd890cda95c46c74f8d22067c323a89b58e6e8f561f2fb8ea
```
### A group
After you have nicely sorted keys, now is the time to make a parent group.
A `group` is a tuple of [first, last] act as index of keys.
A top level parent group will always have `first: 0` and `last: numkeys-1`
Besides sorting, we are not going to produce groups before the actual block witness take place.
We produce the top level group right before entering the block witness generation algorithm.
Top level group always start with `depth: 0`.
### Multi keys and Branch Node
During block witness construction, and you encounter a `Branch Node` you'll grouping the keys together
based on their prefix nibble. We only use a single nibble in this case. Therefore you'll probably end up with
16 groups of keys. __Each of the group consist of the same single nibble prefix__
Assume we are at `depth: 0`, the parent group is: `[0, 15]`, this is the result we have:
```
1d86f4ba779b3e61f65cd0f1b4eea004ddb1cd42b6294979447579e57bb32e02 # group 1: [0, 0]
26eb8904b00d91adf989f5919b71e8bdf96ded347ee25f8cceeb32fb68fb396f # group 2: [1, 2]
28d0cacafa7c17f7a9b759289c11908f3ca0783fc1940399b8e8c216dcccab2d
5021c9457544d81b9870ab986ba52a1fccedd35df09c66de268ecdf289e1127d # group 3: [3, 5]
5021b0f8a5612111ffbc215a7fb82ee382c1a36f0035653c1f3fa3f520c83bee
5e00236babd8b0737512348d0a6bae0ed3e69e76391a8f16085c1c7a4864a098
6a52cf44e5d529973c5f8c10e4a88301076065529370776136b08ddf28617634 # group 4: [6, 7]
6c4cb76d2205904095b8ac41e9deb533ced6d3f5cc5c4f5a55d6abd50b21d022
850169badff8c49045afcb92bddaa59bf0aa3bd996d5a9a2f19984659e0df156 # group 5: [8, 8]
903b206fc2b1aed80eecc439e7ce5049e955b1d5e7b784aadf1c424c99bd270a # group 6: [9, 9]
a1ba56edb2cfcd4914d5bfc35965be5b7df3fc289f8c8c4f3987aaf58196119a # group 7: [10, 10]
b63e59b25dc10e89b04f622ca45cd3da097e1ba41ff2fe202ca0587c53fdbe98 # group 8: [11, 12]
bac9405b4813ac28cc27bc09fb6b27aefa3e341d3ab7f91c63f2482446abb28b
d676c8ea429a4b2e075538475c4cc89cf0251335d167cac2bb516a6cd046fbfd # group 9: [13, 14]
df3585baa4162db6431f36ea2d70380b855cdb53203c707463b5df2c4ed573dc
e26f87f8d83b61dbd890cda95c46c74f8d22067c323a89b58e6e8f561f2fb8ea # group 10: [15, 15]
```
In a `Hexary Trie` you'll only match the current head(nibble) of the path with one elem from `Branch Node`.
In multiproof algorithm, you need to match every elem with as much groups as possible.
If there is no __invalid address__ or the invalid address hiding in one of the group, you will have
branches as much as non empty elements in a `Branch Node` and they will have the same nibble/prefix.
Because the match only involve one nibble, we advance the depth only one.
### Multi keys and Leaf Node and Extension Node
If you encounter a `Leaf Node` or `Extension Node`, they will have the same algorithm to generate groups.
For example, we are at `depth: 1`, and we are processing `group 3: [3, 5]`.
Using the prefix nibbles from `Leaf Node` or `Extension Node`, we produce two groups if our prefix nibbles is `021`:
```
5 021c9457544d81b9870ab986ba52a1fccedd35df09c66de268ecdf289e1127d # group 1: [3, 4]
5 021b0f8a5612111ffbc215a7fb82ee382c1a36f0035653c1f3fa3f520c83bee
5 e00236babd8b0737512348d0a6bae0ed3e69e76391a8f16085c1c7a4864a098 # group 2: [5, 5]
```
At max we will have 3 groups, and every possible combinations will be:
* match(1 group): all keys are matching the prefix nibbles.
* no match(1 group): there is no match.
* not match, match( 2 groups): a non matching group preceding matching group.
* match, not match(2 groups): a matching group before non matching group.
* not match, match, not match(3 groups): a matching group is between two non matching groups.
As you can see, we will only have a single match group or no match at all during constructing these groups.
And we only interested in this match group if it exist and ignore all other not matching groups.
#### A matching group for Extension Node
If we have a matching group for `Extension Node`, we will use this group as parent group
when we move deeper into the trie. We will advance our depth with the length of the prefix nibbles.
Let's say we have a match using nibbles `021`, the matching group is `group 1: [3, 4]`,
we can move deeper after `Extension Node` by adding 3 to our depth.
#### A matching group for Leaf Node
If we move deeper, finally we will encounter a `Leaf Node`.
If you have multiple keys inside your match group, then it is a bug in your multi keys algorithm.
If there is an __invalid address__ hiding in a matching group, you also have bug in your multi keys algorithm.
If you meet with a leaf group and a match group, emit an `Account` or a `Account Storage Leaf`.
```
5 021 c9457544d81b9870ab986ba52a1fccedd35df09c66de268ecdf289e1127d # group 1: [3, 3]
5 021 b0f8a5612111ffbc215a7fb82ee382c1a36f0035653c1f3fa3f520c83bee # group 2: [3, 4]
```
One of this group is a match for a `Leaf Node`, or no match at all.
### Emitting an `Account`
During emitting a `Leaf Node` or an `Account`, and the account have storage trie along with keys and values needs
to be included in the block witness too, we again repeat the algorithm in account storage mode and set the new depth to 0.

View File

@ -1,102 +0,0 @@
# Nimbus
# Copyright (c) 2020-2023 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
proc getBranchStack*(wb: WitnessBuilder; key: openArray[byte]): string =
var
node = wb.db.get(wb.root.data)
stack = @[(node, initNibbleRange(key))]
result.add node.toHex
while stack.len > 0:
let (node, path) = stack.pop()
if node.len == 0: continue
var nodeRlp = rlpFromBytes node
case nodeRlp.listLen
of 2:
let (isLeaf, k) = nodeRlp.extensionNodeKey
let sharedNibbles = sharedPrefixLen(path, k)
if sharedNibbles == k.len:
let value = nodeRlp.listElem(1)
if not isLeaf:
let nextLookup = value.getNode
stack.add((nextLookup, path.slice(sharedNibbles)))
result.add nextLookup.toHex
of 17:
if path.len != 0:
var branch = nodeRlp.listElem(path[0].int)
if not branch.isEmpty:
let nextLookup = branch.getNode
stack.add((nextLookup, path.slice(1)))
result.add nextLookup.toHex
else:
raise newException(CorruptedTrieDatabase,
"HexaryTrie node with an unexpected number of children")
proc getBranch*(wb: WitnessBuilder; key: openArray[byte]): seq[seq[byte]] =
var
node = wb.db.get(wb.root.data)
stack = @[(node, initNibbleRange(key))]
result.add node
while stack.len > 0:
let (node, path) = stack.pop()
if node.len == 0: continue
var nodeRlp = rlpFromBytes node
case nodeRlp.listLen
of 2:
let (isLeaf, k) = nodeRlp.extensionNodeKey
let sharedNibbles = sharedPrefixLen(path, k)
if sharedNibbles == k.len:
let value = nodeRlp.listElem(1)
if not isLeaf:
let nextLookup = value.getNode
stack.add((nextLookup, path.slice(sharedNibbles)))
result.add nextLookup
of 17:
if path.len != 0:
var branch = nodeRlp.listElem(path[0].int)
if not branch.isEmpty:
let nextLookup = branch.getNode
stack.add((nextLookup, path.slice(1)))
result.add nextLookup
else:
raise newException(CorruptedTrieDatabase,
"HexaryTrie node with an unexpected number of children")
proc buildWitness*(wb: var WitnessBuilder; key: openArray[byte]) =
var
node = wb.db.get(wb.root.data)
stack = @[(node, initNibbleRange(key))]
while stack.len > 0:
let (node, path) = stack.pop()
if node.len == 0: continue
var nodeRlp = rlpFromBytes node
case nodeRlp.listLen
of 2:
let (isLeaf, k) = nodeRlp.extensionNodeKey
let sharedNibbles = sharedPrefixLen(path, k)
if sharedNibbles == k.len:
let value = nodeRlp.listElem(1)
if not isLeaf:
let nextLookup = value.getNode
stack.add((nextLookup, path.slice(sharedNibbles)))
of 17:
if path.len != 0:
var branch = nodeRlp.listElem(path[0].int)
if not branch.isEmpty:
let nextLookup = branch.getNode
stack.add((nextLookup, path.slice(1)))
else:
raise newException(CorruptedTrieDatabase,
"HexaryTrie node with an unexpected number of children")

View File

@ -1,149 +0,0 @@
# Nimbus
# Copyright (c) 2020-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
unittest2, os, json, strutils,
eth/[common, rlp], eth/trie/trie_defs,
stew/byteutils,
../tests/[test_helpers, test_config],
../nimbus/db/[ledger, core_db, distinct_tries], ./witness_types,
../stateless/[witness_from_tree, tree_from_witness],
./multi_keys
type
Tester = object
keys: MultiKeysRef
memDB: CoreDbRef
proc testGetBranch(tester: Tester, rootHash: KeccakHash, testStatusIMPL: var TestStatus) =
var trie = initAccountsTrie(tester.memDB, rootHash)
let flags = {wfNoFlag}
try:
var wb = initWitnessBuilder(tester.memDB, rootHash, flags)
var witness = wb.buildWitness(tester.keys)
var db = newCoreDbRef(DefaultDbMemory)
when defined(useInputStream):
var input = memoryInput(witness)
var tb = initTreeBuilder(input, db, flags)
else:
var tb = initTreeBuilder(witness, db, flags)
var root = tb.buildTree()
check root.data == rootHash.data
let newTrie = initAccountsTrie(tb.getDB(), root)
for kd in tester.keys.keys:
let account = rlp.decode(trie.getAccountBytes(kd.address), Account)
let recordFound = newTrie.getAccountBytes(kd.address)
if recordFound.len > 0:
let acc = rlp.decode(recordFound, Account)
doAssert acc == account
else:
doAssert(false, "BUG IN WITNESS/TREE BUILDER")
except ContractCodeError as e:
debugEcho "CONTRACT CODE ERROR: ", e.msg
func parseHash256(n: JsonNode, name: string): Hash256 =
hexToByteArray(n[name].getStr(), result.data)
proc setupStateDB(tester: var Tester, wantedState: JsonNode, stateDB: LedgerRef): Hash256 =
var keys = newSeqOfCap[AccountKey](wantedState.len)
for ac, accountData in wantedState:
let account = ethAddressFromHex(ac)
let slotVals = accountData{"storage"}
var storageKeys = newSeqOfCap[StorageSlot](slotVals.len)
for slotStr, value in slotVals:
let slot = fromHex(UInt256, slotStr)
storageKeys.add(slot.toBytesBE)
stateDB.setStorage(account, slot, fromHex(UInt256, value.getStr))
let nonce = accountData{"nonce"}.getHexadecimalInt.AccountNonce
let code = accountData{"code"}.getStr.safeHexToSeqByte
let balance = UInt256.fromHex accountData{"balance"}.getStr
stateDB.setNonce(account, nonce)
stateDB.setCode(account, code)
stateDB.setBalance(account, balance)
let sKeys = if storageKeys.len != 0: newMultiKeys(storageKeys) else: MultiKeysRef(nil)
let codeTouched = code.len > 0
keys.add(AccountKey(address: account, codeTouched: codeTouched, storageKeys: sKeys))
tester.keys = newMultiKeys(keys)
stateDB.persist()
result = stateDB.rootHash
proc testBlockWitness(node: JsonNode, rootHash: Hash256, testStatusIMPL: var TestStatus) =
var
tester = Tester(memDB: newCoreDbRef(DefaultDbMemory))
ac = LedgerRef.init(tester.memDB, emptyRlpHash)
let root = tester.setupStateDB(node, ac)
if rootHash != emptyRlpHash:
check root == rootHash
tester.testGetBranch(root, testStatusIMPL)
proc testFixtureBC(node: JsonNode, testStatusIMPL: var TestStatus) =
for fixtureName, fixture in node:
let rootHash = parseHash256(fixture["genesisBlockHeader"], "stateRoot")
fixture["pre"].testBlockWitness(rootHash, testStatusIMPL)
proc testFixtureGST(node: JsonNode, testStatusIMPL: var TestStatus) =
var fixture: JsonNode
for fixtureName, child in node:
fixture = child
break
fixture["pre"].testBlockWitness(emptyRlpHash, testStatusIMPL)
proc blockWitnessMain*(debugMode = false) =
const
legacyGSTFolder = "eth_tests" / "LegacyTests" / "Constantinople" / "GeneralStateTests"
newGSTFolder = "eth_tests" / "GeneralStateTests"
newBCFolder = "eth_tests" / "BlockchainTests"
if paramCount() == 0 or not debugMode:
# run all test fixtures
suite "Block Witness":
jsonTest(newBCFolder, "witnessBuilderBC", testFixtureBC)
suite "Block Witness":
jsonTest(newGSTFolder, "witnessBuilderGST", testFixtureGST)
else:
# execute single test in debug mode
let config = getConfiguration()
if config.testSubject.len == 0:
echo "missing test subject"
quit(QuitFailure)
let folder = if config.legacy: legacyGSTFolder else: newGSTFolder
let path = "tests" / "fixtures" / folder
let n = json.parseFile(path / config.testSubject)
var testStatusIMPL: TestStatus
testFixtureGST(n, testStatusIMPL)
when isMainModule:
var message: string
## Processing command line arguments
if processArguments(message) != Success:
echo message
quit(QuitFailure)
else:
if len(message) > 0:
echo message
quit(QuitSuccess)
blockWitnessMain(true)

View File

@ -1,25 +0,0 @@
# Nimbus
# Copyright (c) 2020-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
testutils/fuzzing, ../../nimbus/db/core_db,
./tree_from_witness, ./witness_types
# please read instruction in status-im/nim-testutils/fuzzing/readme.md
# or status-im/nim-testutils/fuzzing/fuzzing_on_windows.md
# if you want to run fuzz test
test:
var db = newCoreDbRef(DefaultDbMemory)
try:
var tb = initTreeBuilder(payload, db, {wfNoFlag})
let root = tb.buildTree()
except ParsingError, ContractCodeError:
debugEcho "Error detected ", getCurrentExceptionMsg()

View File

@ -1,190 +0,0 @@
# Nimbus
# Copyright (c) 2020-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
eth/common, json, os, unittest2,
../nimbus/db/core_db,
./tree_from_witness, parseopt,
./witness_types, stew/byteutils
type
Tester = object
rootHash: KeccakHash
error: bool
output: seq[byte]
proc write(t: var Tester, x: openArray[byte]) =
t.output.add x
proc write(t: var Tester, x: string) =
let len = (x.len - 2) div 2
var buf: array[4096, byte]
hexToByteArray(x, buf, 0, len - 1)
t.write(buf.toOpenArray(0, len - 1))
proc write(t: var Tester, x: JsonNode) =
t.write(x.getStr())
proc processBranchNode(t: var Tester, x: JsonNode) =
t.write(x["mask"])
proc processExtensionNode(t: var Tester, x: JsonNode) =
t.write(x["nibblesLen"])
t.write(x["nibbles"])
proc processNode(t: var Tester, x: JsonNode, storageMode: bool = false)
proc writeSub(t: var Tester, x: JsonNode, name: string): string =
let subName = name & "Sub"
let nodeType = x[name].getStr()
if subName in x:
let subType = x[subName].getStr()
t.write(subType)
else:
t.write(nodeType)
result = nodeType
proc processHashNode(t: var Tester, x: JsonNode) =
discard t.writeSub(x, "nodeType")
t.write(x["data"])
proc processStorage(t: var Tester, tree: JsonNode) =
for x in tree:
t.processNode(x, true)
proc processByteCode(t: var Tester, x: JsonNode) =
let codeType = t.writeSub(x, "codeType")
case codeType
of "0x00":
let codeLen = x["codeLen"].getStr()
t.write(codeLen)
if codeLen != "0x00":
t.write(x["code"])
of "0x01":
t.write(x["codeLen"])
t.processHashNode(x["codeHash"])
else:
raise newException(ParsingError, "wrong bytecode type")
proc processAccountNode(t: var Tester, x: JsonNode) =
let accountType = t.writeSub(x, "accountType")
t.write(x["address"])
t.write(x["balance"])
t.write(x["nonce"])
case accountType:
of "0x00":
discard
of "0x01":
t.processByteCode(x)
t.processStorage(x["storage"])
else:
raise newException(ParsingError, "wrong account type")
proc processStorageLeafNode(t: var Tester, x: JsonNode) =
t.write(x["key"])
t.write(x["value"])
proc processNode(t: var Tester, x: JsonNode, storageMode: bool = false) =
let nodeType = t.writeSub(x, "nodeType")
case nodeType
of "0x00": t.processBranchNode(x)
of "0x01": t.processExtensionNode(x)
of "0x02":
if storageMode:
t.processStorageLeafNode(x)
else:
t.processAccountNode(x)
of "0x03":
t.write(x["data"])
else:
raise newException(ParsingError, "wrong node type")
proc parseRootHash(x: string): KeccakHash =
result.data = hexToByteArray[32](x)
proc parseTester(t: var Tester, n: JsonNode, testStatusIMPL: var TestStatus) =
t.error = n["error"].getBool()
t.rootHash = parseRootHash(n["rootHash"].getStr())
t.write(n["version"])
t.write(n["metadata"])
let tree = n["tree"]
try:
for x in tree:
t.processNode(x)
except ParsingError:
check t.error == true
proc parseTester(filename: string, testStatusIMPL: var TestStatus): Tester =
let n = parseFile(filename)
parseTester(result, n, testStatusIMPL)
proc runTest(filePath, fileName: string) =
test fileName:
let t = parseTester(filePath, testStatusIMPL)
var db = newCoreDbRef(DefaultDbMemory)
try:
var tb = initTreeBuilder(t.output, db, {wfNoFlag})
let root = tb.buildTree()
if t.error:
check root != t.rootHash
else:
check root == t.rootHash
check t.error == false
except ParsingError, ContractCodeError:
# echo "Exception detected ", getCurrentExceptionMsg()
check t.error == true
proc writeFuzzData(filePath, fileName: string) =
var testStatusIMPL: TestStatus
let t = parseTester(filePath, testStatusIMPL)
# this block below check the parsed json
var db = newCoreDbRef(DefaultDbMemory)
var tb = initTreeBuilder(t.output, db, {wfNoFlag})
discard tb.buildTree()
writeFile(fileName, t.output)
proc fuzzTool(): bool {.used.} =
var filename: string
var numArg = 0
for kind, key, val in getopt():
case kind
of cmdArgument:
inc numArg
case numArg
of 1:
if key != "fuzz":
quit(1)
of 2:
filename = key
else:
discard
of cmdLongOption, cmdShortOption:
discard
of cmdEnd: assert(false) # cannot happen
if filename != "":
echo "generate fuzz data"
writeFuzzData(filename, "fuzz.data")
return true
proc witnessJsonMain*() =
suite "test tree builder against json fixtures":
for x in walkDirRec("stateless" / "fixtures"):
let y = splitPath(x)
runTest(x, y.tail)
when isMainModule:
if not fuzzTool():
witnessJsonMain()

View File

@ -1,296 +0,0 @@
# Nimbus
# Copyright (c) 2020-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
randutils, random, unittest2, stew/byteutils, os,
eth/[common, rlp], eth/trie/[trie_defs, nibbles],
faststreams/inputs, nimcrypto/sysrand,
../stateless/[witness_from_tree, tree_from_witness],
../nimbus/db/[core_db, distinct_tries, storage_types], ./witness_types, ./multi_keys
type
DB = CoreDbRef
StorageKeys = tuple[storageRoot: Hash256, keys: MultiKeysRef]
AccountDef = object
storageKeys: MultiKeysRef
account: Account
codeTouched: bool
proc randU256(): UInt256 =
var bytes: array[32, byte]
discard randomBytes(bytes[0].addr, sizeof(result))
result = UInt256.fromBytesBE(bytes)
proc randStorageSlot(): StorageSlot =
discard randomBytes(result[0].addr, sizeof(result))
proc randNonce(): AccountNonce =
discard randomBytes(result.addr, sizeof(result))
proc randCode(db: DB): Hash256 =
if rand(0..1) == 0:
result = blankStringHash
else:
let codeLen = rand(1..150)
let code = randList(byte, rng(0, 255), codeLen, unique = false)
result = keccakHash(code)
db.kvt.put(contractHashKey(result).toOpenArray, code)
proc randStorage(db: DB): StorageKeys =
if rand(0..1) == 0:
result = (emptyRlpHash, MultiKeysRef(nil))
else:
var trie = initStorageTrie(db)
let numPairs = rand(1..10)
var keys = newSeq[StorageSlot](numPairs)
for i in 0..<numPairs:
keys[i] = randStorageSlot()
trie.putSlotBytes(keys[i], rlp.encode(randU256()))
if rand(0..1) == 0:
result = (trie.rootHash, MultiKeysRef(nil))
else:
var m = newMultiKeys(keys)
result = (trie.rootHash, m)
proc randAccount(db: DB): AccountDef =
result.account.nonce = randNonce()
result.account.balance = randU256()
let z = randStorage(db)
result.account.codeHash = randCode(db)
result.account.storageRoot = z.storageRoot
result.storageKeys = z.keys
result.codeTouched = rand(0..1) == 0
proc randAddress(): EthAddress =
discard randomBytes(result.addr, sizeof(result))
proc runTest(numPairs: int, testStatusIMPL: var TestStatus,
addIdenticalKeys: bool = false, addInvalidKeys: static[bool] = false) =
var memDB = newCoreDbRef(DefaultDbMemory)
var trie = initAccountsTrie(memDB)
var addrs = newSeq[AccountKey](numPairs)
var accs = newSeq[Account](numPairs)
for i in 0..<numPairs:
let acc = randAccount(memDB)
addrs[i] = AccountKey(address: randAddress(), codeTouched: acc.codeTouched, storageKeys: acc.storageKeys)
accs[i] = acc.account
trie.putAccountBytes(addrs[i].address, rlp.encode(accs[i]))
when addInvalidKeys:
# invalidAddress should not end up in block witness
let invalidAddress = randAddress()
addrs.add(AccountKey(address: invalidAddress))
if addIdenticalKeys:
let invalidAddress = addrs[0].address
addrs.add(AccountKey(address: invalidAddress))
var mkeys = newMultiKeys(addrs)
let rootHash = trie.rootHash
var wb = initWitnessBuilder(memDB, rootHash, {wfNoFlag})
var witness = wb.buildWitness(mkeys)
var db = newCoreDbRef(DefaultDbMemory)
when defined(useInputStream):
var input = memoryInput(witness)
var tb = initTreeBuilder(input, db, {wfNoFlag})
else:
var tb = initTreeBuilder(witness, db, {wfNoFlag})
let root = tb.buildTree()
check root.data == rootHash.data
let newTrie = initAccountsTrie(tb.getDB(), root)
for i in 0..<numPairs:
let recordFound = newTrie.getAccountBytes(addrs[i].address)
if recordFound.len > 0:
let acc = rlp.decode(recordFound, Account)
check acc == accs[i]
else:
debugEcho "BUG IN WITNESS/TREE BUILDER ", i
check false
when addInvalidKeys:
for kd in mkeys.keys:
if kd.address == invalidAddress:
check kd.visited == false
else:
check kd.visited == true
else:
for kd in mkeys.keys:
check kd.visited == true
proc initMultiKeys(keys: openArray[string], storageMode: bool = false): MultiKeysRef =
result.new
if storageMode:
for i, x in keys:
result.keys.add KeyData(
storageMode: true,
hash: hexToByteArray[32](x)
)
else:
for x in keys:
result.keys.add KeyData(
storageMode: false,
hash: hexToByteArray[32](x)
)
proc parseInvalidInput(payload: openArray[byte]): bool =
var db = newCoreDbRef(DefaultDbMemory)
try:
var tb = initTreeBuilder(payload, db, {wfNoFlag})
discard tb.buildTree()
except ParsingError, ContractCodeError:
result = true
proc witnessKeysMain*() =
suite "random keys block witness roundtrip test":
randomize()
test "random multiple keys":
for i in 0..<100:
runTest(rand(1..30), testStatusIMPL)
test "there is no short node":
let acc = newAccount()
let rlpBytes = rlp.encode(acc)
check rlpBytes.len > 32
test "invalid address ignored":
runTest(rand(1..30), testStatusIMPL, false, addInvalidKeys = true)
test "multiple identical addresses rejected":
expect AssertionDefect:
runTest(rand(5..30), testStatusIMPL, true)
test "case 1: all keys is a match":
let keys = [
"0abc7124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0abccc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606",
"0abca163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6bb"
]
let m = initMultiKeys(keys)
let pg = m.initGroup()
let n = initNibbleRange(hexToByteArray[2]("0abc"))
let mg = m.groups(0, n, pg)
check:
mg.match == true
mg.group.first == 0
mg.group.last == 2
test "case 2: all keys is not a match":
let keys = [
"01237124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0890cc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606",
"0456a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6bb"
]
let m = initMultiKeys(keys)
let pg = m.initGroup()
let n = initNibbleRange(hexToByteArray[2]("0abc"))
let mg = m.groups(0, n, pg)
check:
mg.match == false
test "case 3: not match and match":
let keys = [
"01237124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0890cc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606",
"0abc6a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
"0abc7a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b"
]
let m = initMultiKeys(keys)
let pg = m.initGroup()
let n = initNibbleRange(hexToByteArray[2]("0abc"))
let mg = m.groups(0, n, pg)
check:
mg.match == true
mg.group.first == 2
mg.group.last == 3
test "case 4: match and not match":
let keys = [
"0abc6a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
"0abc7a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
"01237124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0890cc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606"
]
let m = initMultiKeys(keys)
let pg = m.initGroup()
let n = initNibbleRange(hexToByteArray[2]("0abc"))
let mg = m.groups(0, n, pg)
check:
mg.match == true
mg.group.first == 0
mg.group.last == 1
test "case 5: not match, match and not match":
let keys = [
"01237124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0890cc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606",
"0abc6a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
"0abc7a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
"01237124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0890cc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606"
]
let m = initMultiKeys(keys)
let pg = m.initGroup()
let n = initNibbleRange(hexToByteArray[2]("0abc"))
let mg = m.groups(0, n, pg)
check:
mg.match == true
mg.group.first == 2
mg.group.last == 3
test "parse invalid input":
for x in walkDirRec("stateless" / "invalidInput"):
let z = readFile(x)
check parseInvalidInput(z.toOpenArrayByte(0, z.len-1))
test "short rlp test":
let keys = [
"01234567abce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c325",
"01234567b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff5660",
"01234567c140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
]
let m = initMultiKeys(keys, true)
var memDB = newCoreDbRef(DefaultDbMemory)
var trie = initAccountsTrie(memDB)
var acc = randAccount(memDB)
var tt = memDB.mptPrune
for x in m.keys:
tt.put(x.hash, rlp.encode(1.u256))
acc.account.storageRoot = tt.rootHash
let addrs = @[AccountKey(address: randAddress(), codeTouched: acc.codeTouched, storageKeys: m)]
trie.putAccountBytes(addrs[0].address, rlp.encode(acc.account))
var mkeys = newMultiKeys(addrs)
let rootHash = trie.rootHash
var wb = initWitnessBuilder(memDB, rootHash, {wfNoFlag})
var witness = wb.buildWitness(mkeys)
var db = newCoreDbRef(DefaultDbMemory)
var tb = initTreeBuilder(witness, db, {wfNoFlag})
let root = tb.buildTree()
check root.data == rootHash.data
when isMainModule:
witnessKeysMain()

View File

@ -1,102 +0,0 @@
# Nimbus
# Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.push raises: [].}
import
std/os,
unittest2,
results,
eth/[common, trie/trie_defs],
../nimbus/db/[ledger, core_db],
../nimbus/common/chain_config,
./[witness_from_tree, multi_keys, witness_types, witness_verification]
proc getGenesisAlloc(filePath: string): GenesisAlloc =
var cn: NetworkParams
if not loadNetworkParams(filePath, cn):
quit(1)
cn.genesis.alloc
proc setupStateDB(
genAccounts: GenesisAlloc,
stateDB: LedgerRef): (Hash256, MultiKeysRef) =
var keys = newSeqOfCap[AccountKey](genAccounts.len)
for address, genAccount in genAccounts:
var storageKeys = newSeqOfCap[StorageSlot](genAccount.storage.len)
for slotKey, slotValue in genAccount.storage:
storageKeys.add(slotKey.toBytesBE)
stateDB.setStorage(address, slotKey, slotValue)
stateDB.setNonce(address, genAccount.nonce)
stateDB.setCode(address, genAccount.code)
stateDB.setBalance(address, genAccount.balance)
let sKeys = if storageKeys.len != 0: newMultiKeys(storageKeys) else: MultiKeysRef(nil)
let codeTouched = genAccount.code.len > 0
keys.add(AccountKey(address: address, codeTouched: codeTouched, storageKeys: sKeys))
stateDB.persist()
(stateDB.rootHash, newMultiKeys(keys))
proc buildWitness(
genAccounts: GenesisAlloc): (KeccakHash, BlockWitness) {.raises: [CatchableError].} =
let
coreDb = newCoreDbRef(DefaultDbMemory)
accountsCache = LedgerRef.init(coreDb, emptyRlpHash)
(rootHash, multiKeys) = setupStateDB(genAccounts, accountsCache)
var wb = initWitnessBuilder(coreDb, rootHash, {wfNoFlag})
(rootHash, wb.buildWitness(multiKeys))
proc checkWitnessDataMatchesAccounts(
genAccounts: GenesisAlloc,
witnessData: TableRef[EthAddress, AccountData]) {.raises: [CatchableError].} =
for address, genAccount in genAccounts:
let accountData = witnessData[address]
check genAccount.code == accountData.code
check genAccount.storage == accountData.storage
check genAccount.balance == accountData.account.balance
check genAccount.nonce == accountData.account.nonce
proc witnessVerificationMain*() =
suite "Witness verification json tests":
let genesisFiles = ["berlin2000.json", "chainid1.json", "chainid7.json", "merge.json", "devnet4.json", "devnet5.json", "holesky.json"]
test "Block witness verification with valid state root":
for file in genesisFiles:
let
accounts = getGenesisAlloc("tests" / "customgenesis" / file)
(stateRoot, witness) = buildWitness(accounts)
verifyResult = verifyWitness(stateRoot, witness, {wfNoFlag})
check verifyResult.isOk()
checkWitnessDataMatchesAccounts(accounts, verifyResult.get())
test "Block witness verification with invalid state root":
let badStateRoot = toDigest("2cb1b80b285d09e0570fdbbb808e1d14e4ac53e36dcd95dbc268deec2915b3e7")
for file in genesisFiles:
let
accounts = getGenesisAlloc("tests" / "customgenesis" / file)
(_, witness) = buildWitness(accounts)
verifyResult = verifyWitness(badStateRoot, witness, {wfNoFlag})
check verifyResult.isErr()
check verifyResult.error() == "witness stateRoot doesn't match trustedStateRoot"
when isMainModule:
witnessVerificationMain()

View File

@ -1,69 +0,0 @@
# Nimbus
# Copyright (c) 2020-2023 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import stew/bitops2
{.push raises: [].}
type
TrieNodeType* = enum
BranchNodeType
ExtensionNodeType
AccountNodeType
HashNodeType
AccountType* = enum
SimpleAccountType
ExtendedAccountType
BytecodeType* = enum
CodeTouched
CodeUntouched
WitnessFlag* = enum
wfNoFlag
wfEIP170 # fork >= Spurious Dragon
MetadataType* = enum
MetadataNothing
MetadataSomething
WitnessFlags* = set[WitnessFlag]
ContractCodeError* = object of ValueError
ParsingError* = object of ValueError
StorageSlot* = array[32, byte]
const
StorageLeafNodeType* = AccountNodeType
BlockWitnessVersion* = 0x01
ShortRlpPrefix* = 0.byte
proc setBranchMaskBit*(x: var uint, i: int) =
assert(i >= 0 and i < 17)
x = x or (1 shl i).uint
func branchMaskBitIsSet*(x: uint, i: int): bool =
assert(i >= 0 and i < 17)
result = ((x shr i.uint) and 1'u) == 1'u
func constructBranchMask*(b1, b2: byte): uint
{.gcsafe, raises: [ParsingError].} =
result = uint(b1) shl 8 or uint(b2)
if countOnes(result) < 2 or ((result and (not 0x1FFFF'u)) != 0):
raise newException(ParsingError, "Invalid branch mask pattern " & $result)
iterator nonEmpty*(branchMask: uint): int =
for i in 0..<16:
if not branchMask.branchMaskBitIsSet(i):
# we skip an empty elem
continue
yield i

View File

@ -34,10 +34,7 @@ cliBuilder:
./test_transaction_json,
#./test_blockchain_json, -- fails
./test_forkid,
#../stateless/test_witness_keys, -- fails
#../stateless/test_block_witness, -- fails
#../stateless/test_witness_json, -- fails
#../stateless/test_witness_verification, -- fails
./test_multi_keys,
./test_misc,
#./test_graphql, -- fails
./test_pow,
@ -50,6 +47,5 @@ cliBuilder:
./test_overflow,
#./test_getproof_json, -- fails
#./test_rpc_experimental_json, -- fails
#./test_persistblock_witness_json -- fails
./test_aristo,
./test_coredb

View File

@ -17,5 +17,4 @@ export
conversions
createRpcSigsFromNim(RpcClient):
proc exp_getWitnessByBlockNumber(blockId: BlockIdentifier, statePostExecution: bool): seq[byte]
proc exp_getProofsByBlockNumber(blockId: BlockIdentifier, statePostExecution: bool): seq[ProofResponse]
proc exp_getProofsByBlockNumber(blockId: BlockIdentifier, statePostExecution: bool): seq[ProofResponse]

View File

@ -21,7 +21,6 @@ import
../nimbus/evm/tracer/legacy_tracer,
../nimbus/evm/tracer/json_tracer,
../nimbus/core/[validate, chain, pow/header],
../stateless/[tree_from_witness, witness_types],
../tools/common/helpers as chp,
../tools/evmstate/helpers,
../nimbus/common/common,
@ -174,56 +173,23 @@ proc parseTestCtx(fixture: JsonNode, testStatusIMPL: var TestStatus): TestCtx =
result.network = fixture["network"].getStr
proc blockWitness(vmState: BaseVMState, chainDB: CoreDbRef) =
let rootHash = vmState.stateDB.rootHash
let witness = vmState.buildWitness()
if witness.len() == 0:
if vmState.stateDB.makeMultiKeys().keys.len() != 0:
raise newException(ValidationError, "Invalid trie generated from block witness")
return
let fork = vmState.fork
let flags = if fork >= FkSpurious: {wfEIP170} else: {}
# build tree from witness
var db = newCoreDbRef DefaultDbMemory
when defined(useInputStream):
var input = memoryInput(witness)
var tb = initTreeBuilder(input, db, flags)
else:
var tb = initTreeBuilder(witness, db, flags)
let root = tb.buildTree()
# compare the result
if root != rootHash:
raise newException(ValidationError, "Invalid trie generated from block witness")
proc testGetBlockWitness(chain: ChainRef, parentHeader, currentHeader: BlockHeader) =
proc testGetMultiKeys(chain: ChainRef, parentHeader, currentHeader: BlockHeader) =
# check that current state matches current header
let currentStateRoot = chain.vmState.stateDB.rootHash
if currentStateRoot != currentHeader.stateRoot:
raise newException(ValidationError, "Expected currentStateRoot == currentHeader.stateRoot")
let (mkeys, witness) = getBlockWitness(chain.com, currentHeader, false)
let mkeys = getMultiKeys(chain.com, currentHeader, false)
# check that the vmstate hasn't changed after call to getBlockWitness
# check that the vmstate hasn't changed after call to getMultiKeys
if chain.vmState.stateDB.rootHash != currentHeader.stateRoot:
raise newException(ValidationError, "Expected chain.vmstate.stateDB.rootHash == currentHeader.stateRoot")
# check the witnessRoot against the witness tree if the witness isn't empty
if witness.len() > 0:
let fgs = if chain.vmState.fork >= FkSpurious: {wfEIP170} else: {}
var tb = initTreeBuilder(witness, chain.com.db, fgs)
let witnessRoot = tb.buildTree()
if witnessRoot != parentHeader.stateRoot:
raise newException(ValidationError, "Expected witnessRoot == parentHeader.stateRoot")
# use the MultiKeysRef to build the block proofs
let
ac = newAccountStateDB(chain.com.db, currentHeader.stateRoot)
blockProofs = getBlockProofs(state_db.ReadOnlyStateDB(ac), mkeys)
if witness.len() == 0 and blockProofs.len() != 0:
if blockProofs.len() != 0:
raise newException(ValidationError, "Expected blockProofs.len() == 0")
proc setupTracer(ctx: TestCtx): TracerRef =
@ -255,7 +221,7 @@ proc importBlock(ctx: var TestCtx, com: CommonRef,
com,
tracerInst,
)
ctx.vmState.generateWitness = true # Enable saving witness data
ctx.vmState.collectWitnessData = true # Enable saving witness data
let
chain = newChain(com, extraValidation = true, ctx.vmState)
@ -264,8 +230,7 @@ proc importBlock(ctx: var TestCtx, com: CommonRef,
if res.isErr():
raise newException(ValidationError, res.error())
else:
blockWitness(chain.vmState, com.db)
testGetBlockWitness(chain, chain.vmState.parent, tb.header)
testGetMultiKeys(chain, chain.vmState.parent, tb.header)
proc applyFixtureBlockToChain(ctx: var TestCtx, tb: var TestBlock,
com: CommonRef, checkSeal: bool) =

View File

@ -319,21 +319,5 @@ proc configurationMain*() =
check conf.dataDir.string == defaultDataDir()
check conf.keyStore.string == "banana"
test "generate-witness default":
let conf = makeTestConfig()
check conf.generateWitness == false
test "generate-witness enabled":
let conf = makeConfig(@["--generate-witness"])
check conf.generateWitness == true
test "generate-witness equals true":
let conf = makeConfig(@["--generate-witness=true"])
check conf.generateWitness == true
test "generate-witness equals false":
let conf = makeConfig(@["--generate-witness=false"])
check conf.generateWitness == false
when isMainModule:
configurationMain()

119
tests/test_multi_keys.nim Normal file
View File

@ -0,0 +1,119 @@
# Nimbus
# Copyright (c) 2020-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
random, unittest2, stew/byteutils,
eth/trie/nibbles,
../nimbus/stateless/multi_keys
proc initMultiKeys(keys: openArray[string], storageMode: bool = false): MultiKeysRef =
result.new
if storageMode:
for i, x in keys:
result.keys.add KeyData(
storageMode: true,
hash: hexToByteArray[32](x)
)
else:
for x in keys:
result.keys.add KeyData(
storageMode: false,
hash: hexToByteArray[32](x)
)
proc multiKeysMain*() =
suite "random keys block witness roundtrip test":
randomize()
test "case 1: all keys is a match":
let keys = [
"0abc7124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0abccc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606",
"0abca163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6bb"
]
let m = initMultiKeys(keys)
let pg = m.initGroup()
let n = initNibbleRange(hexToByteArray[2]("0abc"))
let mg = m.groups(0, n, pg)
check:
mg.match == true
mg.group.first == 0
mg.group.last == 2
test "case 2: all keys is not a match":
let keys = [
"01237124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0890cc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606",
"0456a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6bb"
]
let m = initMultiKeys(keys)
let pg = m.initGroup()
let n = initNibbleRange(hexToByteArray[2]("0abc"))
let mg = m.groups(0, n, pg)
check:
mg.match == false
test "case 3: not match and match":
let keys = [
"01237124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0890cc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606",
"0abc6a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
"0abc7a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b"
]
let m = initMultiKeys(keys)
let pg = m.initGroup()
let n = initNibbleRange(hexToByteArray[2]("0abc"))
let mg = m.groups(0, n, pg)
check:
mg.match == true
mg.group.first == 2
mg.group.last == 3
test "case 4: match and not match":
let keys = [
"0abc6a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
"0abc7a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
"01237124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0890cc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606"
]
let m = initMultiKeys(keys)
let pg = m.initGroup()
let n = initNibbleRange(hexToByteArray[2]("0abc"))
let mg = m.groups(0, n, pg)
check:
mg.match == true
mg.group.first == 0
mg.group.last == 1
test "case 5: not match, match and not match":
let keys = [
"01237124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0890cc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606",
"0abc6a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
"0abc7a163140158288775c8912aed274fb9d6a3a260e9e95e03e70ba8df30f6b",
"01237124bce7762869be690036144c12c256bdb06ee9073ad5ecca18a47c3254",
"0890cc5b491732f964182ce4bde5e2468318692ed446e008f621b26f8ff56606"
]
let m = initMultiKeys(keys)
let pg = m.initGroup()
let n = initNibbleRange(hexToByteArray[2]("0abc"))
let mg = m.groups(0, n, pg)
check:
mg.match == true
mg.group.first == 2
mg.group.last == 3
when isMainModule:
multiKeysMain()

View File

@ -1,69 +0,0 @@
# Nimbus
# Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
std/[json, os, tables, strutils],
unittest2,
stew/byteutils,
./test_helpers,
../nimbus/core/chain,
../nimbus/common/common,
../stateless/[witness_verification, witness_types]
# use tracerTestGen.nim to generate additional test data
proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus) =
var
blockNumber = UInt256.fromHex(node["blockNumber"].getStr())
memoryDB = newCoreDbRef DefaultDbMemory
config = chainConfigForNetwork(MainNet)
com = CommonRef.new(memoryDB, config)
state = node["state"]
for k, v in state:
let key = hexToSeqByte(k)
let value = hexToSeqByte(v.getStr())
memoryDB.kvt.put(key, value)
let
parentNumber = blockNumber - 1
parent = com.db.getBlockHeader(parentNumber)
header = com.db.getBlockHeader(blockNumber)
headerHash = header.blockHash
blockBody = com.db.getBlockBody(headerHash)
chain = newChain(com)
headers = @[header]
bodies = @[blockBody]
chain.generateWitness = true # Enable code to generate and store witness in the db
# it's ok if setHead fails here because of missing ancestors
discard com.db.setHead(parent, true)
let validationResult = chain.persistBlocks(headers, bodies)
check validationResult.isOk()
let
blockHash = memoryDB.getBlockHash(blockNumber)
witness = memoryDB.getBlockWitness(blockHash).value()
verifyWitnessResult = verifyWitness(parent.stateRoot, witness, {wfNoFlag})
check verifyWitnessResult.isOk()
let witnessData = verifyWitnessResult.value()
if blockBody.transactions.len() > 0:
check:
witness.len() > 0
witnessData.len() > 0
proc persistBlockWitnessJsonMain*() =
suite "persist block json tests":
jsonTest("PersistBlockTests", testFixture)
#var testStatusIMPL: TestStatus
#let n = json.parseFile("tests" / "fixtures" / "PersistBlockTests" / "block420301.json")
#testFixture(n, testStatusIMPL)
when isMainModule:
persistBlockWitnessJsonMain()

View File

@ -6,7 +6,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
std/[json, os, tables],
std/[json, os],
asynctest,
json_rpc/[rpcclient, rpcserver],
stew/byteutils,
@ -14,7 +14,6 @@ import
../nimbus/common/common,
../nimbus/rpc,
../nimbus/db/[ledger, core_db],
../stateless/[witness_verification, witness_types],
./rpc/experimental_rpc_client
type
@ -56,24 +55,17 @@ proc importBlockData(node: JsonNode): (CommonRef, Hash256, Hash256, UInt256) {.
return (com, parent.stateRoot, header.stateRoot, blockNumber)
proc checkAndValidateWitnessAgainstProofs(
proc checkAndValidateProofs(
db: CoreDbRef,
parentStateRoot: KeccakHash,
expectedStateRoot: KeccakHash,
witness: seq[byte],
proofs: seq[ProofResponse]) =
let
stateDB = LedgerRef.init(db, parentStateRoot)
verifyWitnessResult = verifyWitness(expectedStateRoot, witness, {wfNoFlag})
check verifyWitnessResult.isOk()
let witnessData = verifyWitnessResult.value()
check:
witness.len() > 0
proofs.len() > 0
witnessData.len() > 0
for proof in proofs:
let
@ -84,22 +76,10 @@ proc checkAndValidateWitnessAgainstProofs(
storageHash = proof.storageHash.toHash256()
slotProofs = proof.storageProof
if witnessData.contains(address):
let
storageData = witnessData[address].storage
code = witnessData[address].code
check:
witnessData[address].account.balance == balance
witnessData[address].account.nonce == nonce
witnessData[address].account.codeHash == codeHash
for slotProof in slotProofs:
if storageData.contains(slotProof.key):
check storageData[slotProof.key] == slotProof.value
if code.len() > 0:
stateDB.setCode(address, code)
# TODO: Fix this test. Update the code by checking if codeHash has changed
# and calling eth_getCode to set the updated code in the stateDB
# if code.len() > 0:
# stateDB.setCode(address, code)
stateDB.setBalance(address, balance)
stateDB.setNonce(address, nonce)
@ -203,31 +183,27 @@ proc rpcExperimentalJsonMain*() =
waitFor client.connect(RPC_HOST, rpcServer.localAddress[0].port, secure = false)
test "exp_getWitnessByBlockNumber and exp_getProofsByBlockNumber - latest block pre-execution state":
test "exp_getProofsByBlockNumber - latest block pre-execution state":
for file in importFiles:
let (com, parentStateRoot, _, _) = importBlockDataFromFile(file)
setupExpRpc(com, rpcServer)
let
witness = await client.exp_getWitnessByBlockNumber("latest", false)
proofs = await client.exp_getProofsByBlockNumber("latest", false)
let proofs = await client.exp_getProofsByBlockNumber("latest", false)
checkAndValidateWitnessAgainstProofs(com.db, parentStateRoot, parentStateRoot, witness, proofs)
checkAndValidateProofs(com.db, parentStateRoot, parentStateRoot, proofs)
test "exp_getWitnessByBlockNumber and exp_getProofsByBlockNumber - latest block post-execution state":
test "exp_getProofsByBlockNumber - latest block post-execution state":
for file in importFiles:
let (com, parentStateRoot, stateRoot, _) = importBlockDataFromFile(file)
setupExpRpc(com, rpcServer)
let
witness = await client.exp_getWitnessByBlockNumber("latest", true)
proofs = await client.exp_getProofsByBlockNumber("latest", true)
let proofs = await client.exp_getProofsByBlockNumber("latest", true)
checkAndValidateWitnessAgainstProofs(com.db, parentStateRoot, stateRoot, witness, proofs)
checkAndValidateProofs(com.db, parentStateRoot, stateRoot, proofs)
test "exp_getWitnessByBlockNumber and exp_getProofsByBlockNumber - block by number pre-execution state":
test "exp_getProofsByBlockNumber - block by number pre-execution state":
for file in importFiles:
let
(com, parentStateRoot, _, blockNumber) = importBlockDataFromFile(file)
@ -235,13 +211,11 @@ proc rpcExperimentalJsonMain*() =
setupExpRpc(com, rpcServer)
let
witness = await client.exp_getWitnessByBlockNumber(blockNum, false)
proofs = await client.exp_getProofsByBlockNumber(blockNum, false)
let proofs = await client.exp_getProofsByBlockNumber(blockNum, false)
checkAndValidateWitnessAgainstProofs(com.db, parentStateRoot, parentStateRoot, witness, proofs)
checkAndValidateProofs(com.db, parentStateRoot, parentStateRoot, proofs)
test "exp_getWitnessByBlockNumber and exp_getProofsByBlockNumber - block by number post-execution state":
test "exp_getProofsByBlockNumber - block by number post-execution state":
for file in importFiles:
let
(com, parentStateRoot, stateRoot, blockNumber) = importBlockDataFromFile(file)
@ -249,13 +223,11 @@ proc rpcExperimentalJsonMain*() =
setupExpRpc(com, rpcServer)
let
witness = await client.exp_getWitnessByBlockNumber(blockNum, true)
proofs = await client.exp_getProofsByBlockNumber(blockNum, true)
let proofs = await client.exp_getProofsByBlockNumber(blockNum, true)
checkAndValidateWitnessAgainstProofs(com.db, parentStateRoot, stateRoot, witness, proofs)
checkAndValidateProofs(com.db, parentStateRoot, stateRoot, proofs)
test "exp_getWitnessByBlockNumber and exp_getProofsByBlockNumber - block by number that doesn't exist":
test "exp_getProofsByBlockNumber - block by number that doesn't exist":
for file in importFiles:
let
(com, _, _, blockNumber) = importBlockDataFromFile(file)
@ -263,40 +235,12 @@ proc rpcExperimentalJsonMain*() =
setupExpRpc(com, rpcServer)
expect JsonRpcError:
discard await client.exp_getWitnessByBlockNumber(blockNum, false)
expect JsonRpcError:
discard await client.exp_getProofsByBlockNumber(blockNum, false)
expect JsonRpcError:
discard await client.exp_getWitnessByBlockNumber(blockNum, true)
expect JsonRpcError:
discard await client.exp_getProofsByBlockNumber(blockNum, true)
test "Contract storage updated - bytecode should exist in witness":
for file in importFiles:
let
(com, parentStateRoot, _, blockNumber) = importBlockDataFromFile(file)
blockNum = blockId(blockNumber.truncate(uint64))
setupExpRpc(com, rpcServer)
let
witness = await client.exp_getWitnessByBlockNumber(blockNum, false)
proofs = await client.exp_getProofsByBlockNumber(blockNum, true)
verifyWitnessResult = verifyWitness(parentStateRoot, witness, {wfNoFlag})
check verifyWitnessResult.isOk()
let witnessData = verifyWitnessResult.value()
for proof in proofs:
let address = ethAddr(proof.address)
# if the storage was read or updated on an existing contract
if proof.storageProof.len() > 0 and witnessData.contains(address):
check witnessData[address].code.len() > 0
waitFor rpcServer.stop()
waitFor rpcServer.closeWait()

View File

@ -23,7 +23,6 @@
# 3. Start the test.
import
std/tables,
unittest2,
web3/eth_api,
json_rpc/rpcclient,
@ -35,7 +34,6 @@ import
../nimbus/db/core_db,
../nimbus/db/core_db/persistent,
../nimbus/db/state_db/base,
../stateless/[witness_verification, witness_types],
./rpc/experimental_rpc_client
const
@ -57,17 +55,10 @@ template toHash256(hash: untyped): Hash256 =
proc updateStateUsingProofsAndCheckStateRoot(
stateDB: AccountStateDB,
expectedStateRoot: Hash256,
witness: seq[byte],
proofs: seq[ProofResponse]) =
let verifyWitnessResult = verifyWitness(expectedStateRoot, witness, {wfNoFlag})
check verifyWitnessResult.isOk()
let witnessData = verifyWitnessResult.value()
check:
witness.len() > 0
proofs.len() > 0
witnessData.len() > 0
for proof in proofs:
let
@ -78,24 +69,6 @@ proc updateStateUsingProofsAndCheckStateRoot(
storageHash = proof.storageHash.toHash256()
slotProofs = proof.storageProof
if witnessData.contains(address):
let
storageData = witnessData[address].storage
code = witnessData[address].code
check:
witnessData[address].account.balance == balance
witnessData[address].account.nonce == nonce
witnessData[address].account.codeHash == codeHash
for slotProof in slotProofs:
if storageData.contains(slotProof.key):
check storageData[slotProof.key] == slotProof.value
if code.len() > 0:
stateDB.setCode(address, code)
if (balance == 0 and nonce == 0 and codeHash == ZERO_HASH256 and storageHash == ZERO_HASH256):
# Account doesn't exist:
# The account was deleted due to a self destruct and the data no longer exists in the state.
@ -158,13 +131,11 @@ proc rpcGetProofsTrackStateChangesMain*() =
let
blockNum = blockId(i.uint64)
blockHeader: BlockObject = waitFor client.eth_getBlockByNumber(blockNum, false)
witness = waitFor client.exp_getWitnessByBlockNumber(blockNum, true)
proofs = waitFor client.exp_getProofsByBlockNumber(blockNum, true)
updateStateUsingProofsAndCheckStateRoot(
stateDB,
blockHeader.stateRoot.toHash256(),
witness,
proofs)
if i mod 1000 == 0: