nimbus-eth1/tests/test_getproof_json.nim

159 lines
5.1 KiB
Nim

# Nimbus
# Copyright (c) 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.
import
std/[os, sequtils],
unittest2,
stew/byteutils,
web3/eth_api,
nimcrypto/[keccak, hash],
eth/[common, rlp, keys, trie/trie_defs, trie/hexary_proof_verification],
../nimbus/db/state_db,
../nimbus/db/[ledger, core_db],
../nimbus/common/chain_config,
../nimbus/rpc/p2p
type
Hash256 = eth_types.Hash256
ReadOnlyStateDB = state_db.ReadOnlyStateDB
func ethAddr*(x: Address): EthAddress =
EthAddress x
func ethAddr(x: string): EthAddress =
hexToByteArray[20](x)
template toHash256(hash: untyped): Hash256 =
fromHex(Hash256, hash.toHex())
proc verifyAccountProof(trustedStateRoot: Hash256, res: ProofResponse): MptProofVerificationResult =
let
key = toSeq(keccakHash(res.address.ethAddr).data)
value = rlp.encode(Account(
nonce: res.nonce.uint64,
balance: res.balance,
storageRoot: res.storageHash.toHash256(),
codeHash: res.codeHash.toHash256()))
verifyMptProof(
seq[seq[byte]](res.accountProof),
trustedStateRoot,
key,
value)
proc verifySlotProof(trustedStorageRoot: Hash256, slot: StorageProof): MptProofVerificationResult =
let
key = toSeq(keccakHash(toBytesBE(slot.key)).data)
value = rlp.encode(slot.value)
verifyMptProof(
seq[seq[byte]](slot.proof),
trustedStorageRoot,
key,
value)
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 =
for address, genAccount in genAccounts:
for slotKey, slotValue in genAccount.storage:
stateDB.setStorage(address, slotKey, slotValue)
stateDB.setNonce(address, genAccount.nonce)
stateDB.setCode(address, genAccount.code)
stateDB.setBalance(address, genAccount.balance)
stateDB.persist()
stateDB.rootHash
proc checkProofsForExistingLeafs(
genAccounts: GenesisAlloc,
accDB: ReadOnlyStateDB,
stateRoot: Hash256) =
for address, account in genAccounts:
var slots = newSeq[UInt256]()
for k in account.storage.keys():
slots.add(k)
let
proofResponse = getProof(accDB, address, slots)
slotProofs = proofResponse.storageProof
check:
proofResponse.balance == account.balance
proofResponse.codeHash.toHash256() == accDB.getCodeHash(address)
proofResponse.storageHash.toHash256() == accDB.getStorageRoot(address)
verifyAccountProof(stateRoot, proofResponse).isValid()
slotProofs.len() == account.storage.len()
for i, slotProof in slotProofs:
check:
slotProof.key == slots[i]
slotProof.value == account.storage[slotProof.key]
verifySlotProof(proofResponse.storageHash.toHash256(), slotProof).isValid()
proc checkProofsForMissingLeafs(
genAccounts: GenesisAlloc,
accDB: ReadOnlyStateDB,
stateRoot: Hash256) =
let
missingAddress = ethAddr("0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E")
proofResponse = getProof(accDB, missingAddress, @[])
check verifyAccountProof(stateRoot, proofResponse).isMissing()
for address, account in genAccounts:
let
missingSlot = u256("987654321123456676466544")
proofResponse2 = getProof(accDB, address, @[missingSlot])
slotProofs = proofResponse2.storageProof
check slotProofs.len() == 1
if account.storage.len() > 0:
check verifySlotProof(proofResponse2.storageHash.toHash256(), slotProofs[0]).isMissing()
proc getProofJsonMain*() =
suite "Get proof json tests":
let genesisFiles = ["berlin2000.json", "chainid1.json", "chainid7.json", "merge.json", "devnet4.json", "devnet5.json", "holesky.json"]
test "Get proofs for existing leafs":
for file in genesisFiles:
let
accounts = getGenesisAlloc("tests" / "customgenesis" / file)
coreDb = newCoreDbRef(LegacyDbMemory)
accountsCache = AccountsCache.init(coreDb, emptyRlpHash, false)
stateRootHash = setupStateDB(accounts, accountsCache)
accountDb = newAccountStateDB(coreDb, stateRootHash, false)
readOnlyDb = ReadOnlyStateDB(accountDb)
checkProofsForExistingLeafs(accounts, readOnlyDb, stateRootHash)
test "Get proofs for missing leafs":
for file in genesisFiles:
let
accounts = getGenesisAlloc("tests" / "customgenesis" / file)
coreDb = newCoreDbRef(LegacyDbMemory)
accountsCache = AccountsCache.init(coreDb, emptyRlpHash, false)
stateRootHash = setupStateDB(accounts, accountsCache)
accountDb = newAccountStateDB(coreDb, stateRootHash, false)
readOnlyDb = ReadOnlyStateDB(accountDb)
checkProofsForMissingLeafs(accounts, readOnlyDb, stateRootHash)
when isMainModule:
getProofJsonMain()