nimbus-eth1 icon indicating copy to clipboard operation
nimbus-eth1 copied to clipboard

Storage trie is not removed from database when the account is removed.

Open jangko opened this issue 1 month ago • 0 comments

import
  std/[importutils, tables],
  eth/trie/trie_defs,
  eth/common/eth_types,
  stew/[byteutils, endians2],
  unittest2,
  ../nimbus/db/storage_types,
  ../nimbus/db/core_db,
  ../nimbus/db/ledger,
  ../nimbus/db/ledger/accounts_ledger {.all.} # import all private symbols

func initAddr(z: int): EthAddress =
  const L = sizeof(result)
  result[L-sizeof(uint32)..^1] = toBytesBE(z.uint32)

proc kvtLen(db: CoreDbRef): int =
  let kvt = db.kvt
  for _, _ in kvt:
    inc result

proc mptLen(db: LedgerRef): int =
  let mpt = db.getMpt
  for _, _ in mpt:
    inc result

test "storage trie removed from database":
  let addr1 = initAddr(1)
  let addr2 = initAddr(2)
  let ac = LedgerRef.init(memDB, EMPTY_ROOT_HASH)

  ac.addBalance(addr1, 1.u256)
  ac.setStorage(addr1, 1.u256, 1.u256)
  ac.persist()

  # only one storage trie
  check memDB.kvtLen == 1
  # only one account
  check ac.mptLen == 1

  ac.addBalance(addr2, 1.u256)
  ac.setStorage(addr2, 1.u256, 1.u256)
  ac.persist()
  let root1 = ac.state()

  # both addr1 and addr2 share the same storage trie
  # only one storage trie
  check memDB.kvtLen == 1 # ok # I think this should 2 storage tries, one for each account.
  # now there are two accounts
  check ac.mptLen == 2 # ok

  ac.setStorage(addr2, 2.u256, 1.u256)
  ac.persist()

  # now there will be two storage tries
  check memDB.kvtLen == 2 # ok

  # delete slot 2
  ac.setStorage(addr2, 2.u256, 0.u256)
  ac.persist()

  # the state root should be the same as when there is no slot 2 of addr2
  check ac.state() == root1 # ok
  check memDB.kvtLen == 1 # fails with 2 storage tries in db
      
  ac.deleteAccount(addr2)
  ac.persist()
  check memDB.kvtLen == 1 # fails with 2 storage tries in db
      
  # only one account
  check ac.mptLen == 1 # ok

jangko avatar Jun 04 '24 12:06 jangko