mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-08 07:58:40 +00:00
core: do selfdestructs
This commit is contained in:
parent
87641c7265
commit
48d7bf08d7
5 changed files with 67 additions and 21 deletions
22
core/evm.go
22
core/evm.go
|
|
@ -18,7 +18,6 @@ package core
|
|||
|
||||
import (
|
||||
"math/big"
|
||||
"math/bits"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
|
|
@ -91,26 +90,7 @@ func CostPerStateByte(header *types.Header, config *params.ChainConfig) uint64 {
|
|||
if !config.IsAmsterdam(header.Number, header.Time) {
|
||||
return 0
|
||||
}
|
||||
const (
|
||||
blocksPerYear uint64 = 2_628_000 // 7200 * 365
|
||||
offset uint64 = 9578
|
||||
significantBts uint64 = 5
|
||||
)
|
||||
numerator := header.GasLimit * blocksPerYear
|
||||
denominator := uint64(2) * params.TargetStateGrowthPerYear
|
||||
raw := (numerator + denominator - 1) / denominator
|
||||
shifted := raw + offset
|
||||
// bit length of shifted
|
||||
bitLen := uint64(64 - bits.LeadingZeros64(shifted))
|
||||
var shift uint64
|
||||
if bitLen > significantBts {
|
||||
shift = bitLen - significantBts
|
||||
}
|
||||
quantized := (shifted >> shift) << shift
|
||||
if quantized > offset {
|
||||
return quantized - offset
|
||||
}
|
||||
return 1
|
||||
return 1174
|
||||
}
|
||||
|
||||
// NewEVMTxContext creates a new transaction context for a single transaction.
|
||||
|
|
|
|||
|
|
@ -779,6 +779,61 @@ func (s *StateDB) StateChangedBytes(revid int, excludeSubcalls bool) int64 {
|
|||
return s.journal.stateChangedBytes(revid, s.stateObjects, excludeSubcalls)
|
||||
}
|
||||
|
||||
// SelfDestructRefundBytes computes the total state bytes to refund at tx-end
|
||||
// for accounts that were both created and selfdestructed during this
|
||||
// transaction.
|
||||
func (s *StateDB) SelfDestructRefundBytes() int64 {
|
||||
// Collect addresses created and selfdestructed in this tx.
|
||||
targets := make(map[common.Address]*stateObject)
|
||||
for addr, obj := range s.stateObjects {
|
||||
if s.IsNewContract(addr) && s.HasSelfDestructed(addr) {
|
||||
targets[addr] = obj
|
||||
}
|
||||
}
|
||||
if len(targets) == 0 {
|
||||
return 0
|
||||
}
|
||||
// Account creation + code deposit refunds.
|
||||
var bytes int64
|
||||
for _, obj := range targets {
|
||||
bytes += CostPerAccount + int64(len(obj.code))
|
||||
}
|
||||
// For storage slots: walk journal storage entries to find the tx-entry
|
||||
// value of each slot. Count slots where tx-entry was zero and the final
|
||||
// dirty value is non-zero (i.e. the slot was charged as new and not
|
||||
// subsequently cleared).
|
||||
type slotKey struct {
|
||||
addr common.Address
|
||||
key common.Hash
|
||||
}
|
||||
originAtTxEntry := make(map[slotKey]common.Hash)
|
||||
for _, e := range s.journal.entries {
|
||||
sc, ok := e.(storageChange)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := targets[sc.account]; !ok {
|
||||
continue
|
||||
}
|
||||
sk := slotKey{sc.account, sc.key}
|
||||
if _, seen := originAtTxEntry[sk]; !seen {
|
||||
originAtTxEntry[sk] = sc.origvalue
|
||||
}
|
||||
}
|
||||
for sk, orig := range originAtTxEntry {
|
||||
if orig != (common.Hash{}) {
|
||||
continue
|
||||
}
|
||||
obj := targets[sk.addr]
|
||||
cur, dirty := obj.dirtyStorage[sk.key]
|
||||
if !dirty || cur == (common.Hash{}) {
|
||||
continue
|
||||
}
|
||||
bytes += CostPerSlot
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
type removedAccountWithBalance struct {
|
||||
address common.Address
|
||||
balance *uint256.Int
|
||||
|
|
|
|||
|
|
@ -296,3 +296,7 @@ func (s *hookedStateDB) Finalise(deleteEmptyObjects bool) *bal.StateAccessList {
|
|||
func (s *hookedStateDB) StateChangedBytes(revid int, excludeSubcalls bool) int64 {
|
||||
return s.inner.StateChangedBytes(revid, excludeSubcalls)
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SelfDestructRefundBytes() int64 {
|
||||
return s.inner.SelfDestructRefundBytes()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -634,6 +634,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
if rules.IsAmsterdam {
|
||||
if vmerr == nil {
|
||||
outerBytes := st.state.StateChangedBytes(outerSnapshot, false)
|
||||
// Refund state gas for selfdestructed accounts.
|
||||
outerBytes -= st.state.SelfDestructRefundBytes()
|
||||
st.gasRemaining.Charge(vm.GasCosts{StateGas: outerBytes * int64(st.evm.Context.CostPerStateByte)})
|
||||
} else {
|
||||
if execGasUsed.StateGas > 0 {
|
||||
|
|
|
|||
|
|
@ -111,4 +111,9 @@ type StateDB interface {
|
|||
// is true, cached subcall costs are not added to the total. Used by
|
||||
// EIP-8037 for state gas metering.
|
||||
StateChangedBytes(revid int, excludeSubcalls bool) int64
|
||||
|
||||
// SelfDestructRefundBytes returns the total state bytes to refund at
|
||||
// tx-end for accounts that were both created and selfdestructed during
|
||||
// this transaction (per EIP-6780).
|
||||
SelfDestructRefundBytes() int64
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue