Fix LedgerRef storage iterator and add test (#2458)

This commit is contained in:
andri lim 2024-07-05 17:15:48 +07:00 committed by GitHub
parent 6fe7411ac0
commit c775c906a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 92 additions and 27 deletions

View File

@ -474,14 +474,14 @@ iterator rightPairsStorage*(
db: AristoDbRef; # Database layer db: AristoDbRef; # Database layer
accPath: Hash256; # Account the storage data belong to accPath: Hash256; # Account the storage data belong to
start = low(PathID); # Before or at first value start = low(PathID); # Before or at first value
): (PathID,Blob) = ): (PathID,UInt256) =
## Variant of `rightPairs()` for a storage tree ## Variant of `rightPairs()` for a storage tree
block body: block body:
let stoID = db.fetchStorageID(accPath).valueOr: let stoID = db.fetchStorageID(accPath).valueOr:
break body break body
if stoID.isValid: if stoID.isValid:
for (lty,pyl) in db.rightPairs LeafTie(root: stoID, path: start): for (lty,pyl) in db.rightPairs LeafTie(root: stoID, path: start):
yield (lty.path, pyl.rawBlob) yield (lty.path, pyl.stoData)
# ---------------- # ----------------

View File

@ -75,7 +75,7 @@ iterator pairs*(mpt: CoreDbMptRef): (Blob, Blob) =
raiseAssert: "Unsupported database type: " & $mpt.dbType raiseAssert: "Unsupported database type: " & $mpt.dbType
mpt.ifTrackNewApi: debug newApiTxt, api, elapsed mpt.ifTrackNewApi: debug newApiTxt, api, elapsed
iterator slotPairs*(acc: CoreDbAccRef; accPath: Hash256): (Blob, Blob) = iterator slotPairs*(acc: CoreDbAccRef; accPath: Hash256): (Blob, UInt256) =
## Trie traversal, only supported for `CoreDbMptRef` ## Trie traversal, only supported for `CoreDbMptRef`
## ##
acc.setTrackNewApi AccSlotPairsIt acc.setTrackNewApi AccSlotPairsIt

View File

@ -13,14 +13,15 @@
import import
std/[tables, hashes, sets, typetraits], std/[tables, hashes, sets, typetraits],
chronicles, chronicles,
eth/[common, rlp], eth/common,
results, results,
stew/keyed_queue, stew/keyed_queue,
../../stateless/multi_keys, ../../stateless/multi_keys,
"../.."/[constants, utils/utils], "../.."/[constants, utils/utils],
../access_list as ac_access_list, ../access_list as ac_access_list,
../../evm/code_bytes, ../../evm/code_bytes,
".."/[core_db, storage_types, transient_storage] ".."/[core_db, storage_types, transient_storage],
../aristo/aristo_blobify
export code_bytes export code_bytes
@ -142,12 +143,6 @@ proc resetCoreDbAccount(ac: AccountsLedgerRef, acc: AccountRef) =
acc.statement.balance = emptyEthAccount.balance acc.statement.balance = emptyEthAccount.balance
acc.statement.codeHash = emptyEthAccount.codeHash acc.statement.codeHash = emptyEthAccount.codeHash
template noRlpException(info: static[string]; code: untyped) =
try:
code
except RlpError as e:
raiseAssert info & ", name=\"" & $e.name & "\", msg=\"" & e.msg & "\""
# The AccountsLedgerRef is modeled after TrieDatabase for it's transaction style # The AccountsLedgerRef is modeled after TrieDatabase for it's transaction style
proc init*(x: typedesc[AccountsLedgerRef], db: CoreDbRef, proc init*(x: typedesc[AccountsLedgerRef], db: CoreDbRef,
root: KeccakHash): AccountsLedgerRef = root: KeccakHash): AccountsLedgerRef =
@ -384,7 +379,7 @@ proc persistStorage(acc: AccountRef, ac: AccountsLedgerRef) =
discard discard
let let
key = slot.toBytesBE.keccakHash.data.slotHashToSlotKey key = slot.toBytesBE.keccakHash.data.slotHashToSlotKey
rc = ac.kvt.put(key.toOpenArray, rlp.encode(slot)) rc = ac.kvt.put(key.toOpenArray, blobify(slot).data)
if rc.isErr: if rc.isErr:
warn logTxt "persistStorage()", slot, error=($$rc.error) warn logTxt "persistStorage()", slot, error=($$rc.error)
@ -727,13 +722,16 @@ iterator storage*(
): (UInt256, UInt256) = ): (UInt256, UInt256) =
# beware that if the account not persisted, # beware that if the account not persisted,
# the storage root will not be updated # the storage root will not be updated
noRlpException "storage()":
for (slotHash, value) in ac.ledger.slotPairs eAddr.toAccountKey: for (slotHash, value) in ac.ledger.slotPairs eAddr.toAccountKey:
let rc = ac.kvt.get(slotHashToSlotKey(slotHash).toOpenArray) let rc = ac.kvt.get(slotHashToSlotKey(slotHash).toOpenArray)
if rc.isErr: if rc.isErr:
warn logTxt "storage()", slotHash, error=($$rc.error) warn logTxt "storage()", slotHash, error=($$rc.error)
else: continue
yield (rlp.decode(rc.value, UInt256), rlp.decode(value, UInt256)) let r = deblobify(rc.value, UInt256)
if r.isErr:
warn logTxt "storage.deblobify", slotHash, msg=r.error
continue
yield (r.value, value)
iterator cachedStorage*(ac: AccountsLedgerRef, address: EthAddress): (UInt256, UInt256) = iterator cachedStorage*(ac: AccountsLedgerRef, address: EthAddress): (UInt256, UInt256) =
let acc = ac.getAccount(address, false) let acc = ac.getAccount(address, false)

View File

@ -28,7 +28,9 @@ import
const const
genesisFile = "tests/customgenesis/cancun123.json" genesisFile = "tests/customgenesis/cancun123.json"
hexPrivKey = "af1a9be9f1a54421cac82943820a0fe0f601bb5f4f6d0bccc81c613f0ce6ae22" hexPrivKey = "af1a9be9f1a54421cac82943820a0fe0f601bb5f4f6d0bccc81c613f0ce6ae22"
senderAddr = hexToByteArray[20]("73cf19657412508833f618a15e8251306b3e6ee5")
# The above privKey will generate this address
# senderAddr = hexToByteArray[20]("73cf19657412508833f618a15e8251306b3e6ee5")
type type
TestEnv = object TestEnv = object
@ -391,7 +393,7 @@ proc runLedgerTransactionTests(noisy = true) =
let ledger = env.com.getLedger(head) let ledger = env.com.getLedger(head)
env.runTrial4(ledger, n, rollback = true) env.runTrial4(ledger, n, rollback = true)
proc runLedgerBesicOperationsTests() = proc runLedgerBasicOperationsTests() =
suite "Ledger basic operations tests": suite "Ledger basic operations tests":
setup: setup:
const emptyAcc {.used.} = newAccount() const emptyAcc {.used.} = newAccount()
@ -454,7 +456,7 @@ proc runLedgerBesicOperationsTests() =
check x.originalStorage.len == 3 check x.originalStorage.len == 3
check y.originalStorage.len == 3 check y.originalStorage.len == 3
test "accounts cache": test "Ledger various operations":
var ac = LedgerRef.init(memDB, EMPTY_ROOT_HASH) var ac = LedgerRef.init(memDB, EMPTY_ROOT_HASH)
var addr1 = initAddr(1) var addr1 = initAddr(1)
@ -494,8 +496,7 @@ proc runLedgerBesicOperationsTests() =
db.setStorage(addr1, 1.u256, 10.u256) db.setStorage(addr1, 1.u256, 10.u256)
check rootHash == db.rootHash check rootHash == db.rootHash
# accounts cache readonly operations # Ledger readonly operations using previous hash
# use previous hash
var ac2 = LedgerRef.init(memDB, rootHash) var ac2 = LedgerRef.init(memDB, rootHash)
var addr2 = initAddr(2) var addr2 = initAddr(2)
@ -515,7 +516,7 @@ proc runLedgerBesicOperationsTests() =
# state trie at all # state trie at all
check ac2.rootHash == rootHash check ac2.rootHash == rootHash
test "accounts cache code retrieval after persist called": test "Ledger code retrieval after persist called":
var ac = LedgerRef.init(memDB, EMPTY_ROOT_HASH) var ac = LedgerRef.init(memDB, EMPTY_ROOT_HASH)
var addr2 = initAddr(2) var addr2 = initAddr(2)
ac.setCode(addr2, code) ac.setCode(addr2, code)
@ -656,7 +657,7 @@ proc runLedgerBesicOperationsTests() =
check ac.vts(0xcc, 7, 88) == false check ac.vts(0xcc, 7, 88) == false
check ac.vts(0xdd, 2, 66) == false check ac.vts(0xdd, 2, 66) == false
test "accounts cache contractCollision": test "ledger contractCollision":
# use previous hash # use previous hash
var ac = LedgerRef.init(memDB, EMPTY_ROOT_HASH) var ac = LedgerRef.init(memDB, EMPTY_ROOT_HASH)
let addr2 = initAddr(2) let addr2 = initAddr(2)
@ -678,13 +679,79 @@ proc runLedgerBesicOperationsTests() =
ac.setNonce(addr4, 1) ac.setNonce(addr4, 1)
check ac.contractCollision(addr4) == true check ac.contractCollision(addr4) == true
test "Ledger storage iterator":
var ac = LedgerRef.init(memDB, EMPTY_ROOT_HASH)
let addr2 = initAddr(2)
ac.setStorage(addr2, 1.u256, 2.u256)
ac.setStorage(addr2, 2.u256, 3.u256)
var keys: seq[UInt256]
var vals: seq[UInt256]
for k, v in ac.cachedStorage(addr2):
keys.add k
vals.add v
# before persist, there are storages in cache
check keys.len == 2
check vals.len == 2
check 1.u256 in keys
check 2.u256 in keys
# before persist, the values are all original values
check vals == @[0.u256, 0.u256]
keys.reset
vals.reset
for k, v in ac.storage(addr2):
keys.add k
vals.add k
# before persist, there are no storages in db
check keys.len == 0
check vals.len == 0
ac.persist()
for k, v in ac.cachedStorage(addr2):
keys.add k
vals.add v
# after persist, there are storages in cache
check keys.len == 2
check vals.len == 2
check 1.u256 in keys
check 2.u256 in keys
# after persist, the values are what we put into
check 2.u256 in vals
check 3.u256 in vals
keys.reset
vals.reset
for k, v in ac.storage(addr2):
keys.add k
vals.add v
# after persist, there are storages in db
check keys.len == 2
check vals.len == 2
check 1.u256 in keys
check 2.u256 in keys
check 2.u256 in vals
check 3.u256 in vals
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Main function(s) # Main function(s)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc ledgerMain*(noisy = defined(debug)) = proc ledgerMain*(noisy = defined(debug)) =
noisy.runLedgerTransactionTests noisy.runLedgerTransactionTests
runLedgerBesicOperationsTests() runLedgerBasicOperationsTests()
when isMainModule: when isMainModule:
var noisy = defined(debug) var noisy = defined(debug)