2024-01-22 09:11:37 +00:00
|
|
|
# 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,
|
|
|
|
stew/results,
|
|
|
|
eth/[common, trie/trie_defs],
|
2024-02-15 02:57:05 +00:00
|
|
|
../nimbus/db/[ledger, core_db],
|
|
|
|
../nimbus/common/chain_config,
|
2024-01-22 09:11:37 +00:00
|
|
|
./[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,
|
2024-02-21 16:04:59 +00:00
|
|
|
stateDB: LedgerRef): (Hash256, MultiKeysRef) =
|
2024-01-22 09:11:37 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2024-02-21 16:04:59 +00:00
|
|
|
let sKeys = if storageKeys.len != 0: newMultiKeys(storageKeys) else: MultiKeysRef(nil)
|
2024-01-22 09:11:37 +00:00
|
|
|
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(LegacyDbMemory)
|
|
|
|
accountsCache = AccountsCache.init(coreDb, emptyRlpHash, true)
|
|
|
|
(rootHash, multiKeys) = setupStateDB(genAccounts, accountsCache)
|
|
|
|
|
2024-01-24 17:18:45 +00:00
|
|
|
var wb = initWitnessBuilder(coreDb, rootHash, {wfNoFlag})
|
2024-01-22 09:11:37 +00:00
|
|
|
(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)
|
2024-01-24 17:18:45 +00:00
|
|
|
verifyResult = verifyWitness(stateRoot, witness, {wfNoFlag})
|
2024-01-22 09:11:37 +00:00
|
|
|
|
|
|
|
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)
|
2024-01-24 17:18:45 +00:00
|
|
|
verifyResult = verifyWitness(badStateRoot, witness, {wfNoFlag})
|
2024-01-22 09:11:37 +00:00
|
|
|
|
|
|
|
check verifyResult.isErr()
|
|
|
|
check verifyResult.error() == "witness stateRoot doesn't match trustedStateRoot"
|
|
|
|
|
|
|
|
when isMainModule:
|
|
|
|
witnessVerificationMain()
|
|
|
|
|