From 467e6fffa6eea1556c362fca8e070a8f6fbecbf5 Mon Sep 17 00:00:00 2001 From: jangko Date: Fri, 18 Aug 2023 10:12:18 +0700 Subject: [PATCH] Implement EIP-6780: SELFDESTRUCT only in same transaction --- nimbus/db/accounts_cache.nim | 17 +++++++++++++++-- nimbus/evm/computation.nim | 6 +++++- .../evm/interpreter/op_handlers/oph_sysops.nim | 2 +- nimbus/transaction/host_services.nim | 5 ++++- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/nimbus/db/accounts_cache.nim b/nimbus/db/accounts_cache.nim index 322a7883c..67bbc5fd3 100644 --- a/nimbus/db/accounts_cache.nim +++ b/nimbus/db/accounts_cache.nim @@ -29,6 +29,7 @@ type CodeLoaded CodeChanged StorageChanged + NewlyCreated # EIP-6780: self destruct only in same transaction AccountFlags = set[AccountFlag] @@ -76,7 +77,8 @@ const IsNew, Touched, CodeChanged, - StorageChanged + StorageChanged, + NewlyCreated } ripemdAddr* = block: @@ -485,8 +487,11 @@ proc setStorage*(ac: AccountsCache, address: EthAddress, slot, value: UInt256) = acc.flags.incl StorageChanged proc clearStorage*(ac: AccountsCache, address: EthAddress) = + # a.k.a createStateObject. If there is an existing account with + # the given address, it is overwritten. + let acc = ac.getAccount(address) - acc.flags.incl {Alive} + acc.flags.incl {Alive, NewlyCreated} if acc.account.storageRoot != EMPTY_ROOT_HASH: # there is no point to clone the storage since we want to remove it let acc = ac.makeDirty(address, cloneStorage = false) @@ -506,6 +511,14 @@ proc deleteAccount*(ac: AccountsCache, address: EthAddress) = proc selfDestruct*(ac: AccountsCache, address: EthAddress) = ac.savePoint.selfDestruct.incl address +proc selfDestruct6780*(ac: AccountsCache, address: EthAddress) = + let acc = ac.getAccount(address, false) + if acc.isNil: + return + + if NewlyCreated in acc.flags: + ac.selfDestruct(address) + proc selfDestructLen*(ac: AccountsCache): int = ac.savePoint.selfDestruct.len diff --git a/nimbus/evm/computation.nim b/nimbus/evm/computation.nim index b6dec57d4..ad74967e9 100644 --- a/nimbus/evm/computation.nim +++ b/nimbus/evm/computation.nim @@ -350,6 +350,7 @@ proc merge*(c, child: Computation) = proc execSelfDestruct*(c: Computation, beneficiary: EthAddress) {.gcsafe, raises: [CatchableError].} = + c.vmState.mutateStateDB: let localBalance = c.getBalance(c.msg.contractAddress) @@ -362,7 +363,10 @@ proc execSelfDestruct*(c: Computation, beneficiary: EthAddress) db.setBalance(c.msg.contractAddress, 0.u256) # Register the account to be deleted - db.selfDestruct(c.msg.contractAddress) + if c.fork >= FkCancun: + db.selfDestruct6780(c.msg.contractAddress) + else: + db.selfDestruct(c.msg.contractAddress) trace "SELFDESTRUCT", contractAddress = c.msg.contractAddress.toHex, diff --git a/nimbus/evm/interpreter/op_handlers/oph_sysops.nim b/nimbus/evm/interpreter/op_handlers/oph_sysops.nim index d9c47618f..4cddc5cce 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_sysops.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_sysops.nim @@ -150,7 +150,7 @@ const gasCost = gasCost + ColdAccountAccessCost cpt.gasMeter.consumeGas( - gasCost, reason = "SELFDESTRUCT EIP161") + gasCost, reason = "SELFDESTRUCT EIP2929") cpt.selfDestruct(beneficiary) # ------------------------------------------------------------------------------ diff --git a/nimbus/transaction/host_services.nim b/nimbus/transaction/host_services.nim index f2f8839f8..1827e6769 100644 --- a/nimbus/transaction/host_services.nim +++ b/nimbus/transaction/host_services.nim @@ -229,7 +229,10 @@ proc selfDestruct(host: TransactionHost, address, beneficiary: HostAddress) {.sh # This must come after sending to the beneficiary in case the # contract named itself as the beneficiary. db.setBalance(address, 0.u256) - db.selfDestruct(address) + if host.vmState.fork >= FkCancun: + db.selfDestruct6780(address) + else: + db.selfDestruct(address) template call(host: TransactionHost, msg: EvmcMessage): EvmcResult = # `call` is special. The C stack usage must be kept small for deeply nested