mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-08 07:58:40 +00:00
core: apply fixes for 8037
This commit is contained in:
parent
2d708415d7
commit
fa45d1a38f
8 changed files with 122 additions and 10 deletions
|
|
@ -687,6 +687,36 @@ func (s *StateDB) IsNewContract(addr common.Address) bool {
|
||||||
return obj.newContract
|
return obj.newContract
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SameTxSelfDestructs returns the addresses that were both created and
|
||||||
|
// self-destructed in the current transaction (EIP-6780). Used for the
|
||||||
|
// EIP-8037 same-tx selfdestruct state-gas refund.
|
||||||
|
func (s *StateDB) SameTxSelfDestructs() []common.Address {
|
||||||
|
var out []common.Address
|
||||||
|
for addr, obj := range s.stateObjects {
|
||||||
|
if obj.newContract && obj.selfDestructed {
|
||||||
|
out = append(out, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStorageSlotCount returns the number of storage slots that were written
|
||||||
|
// to a non-zero value in the current transaction on the given account. Used
|
||||||
|
// for the EIP-8037 same-tx selfdestruct state-gas refund.
|
||||||
|
func (s *StateDB) NewStorageSlotCount(addr common.Address) int {
|
||||||
|
obj, ok := s.stateObjects[addr]
|
||||||
|
if !ok {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var count int
|
||||||
|
for _, v := range obj.dirtyStorage {
|
||||||
|
if v != (common.Hash{}) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
// Copy creates a deep, independent copy of the state.
|
// Copy creates a deep, independent copy of the state.
|
||||||
// Snapshots of the copied state cannot be applied to the copy.
|
// Snapshots of the copied state cannot be applied to the copy.
|
||||||
func (s *StateDB) Copy() *StateDB {
|
func (s *StateDB) Copy() *StateDB {
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,14 @@ func (s *hookedStateDB) GetCodeSize(addr common.Address) int {
|
||||||
return s.inner.GetCodeSize(addr)
|
return s.inner.GetCodeSize(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *hookedStateDB) SameTxSelfDestructs() []common.Address {
|
||||||
|
return s.inner.SameTxSelfDestructs()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *hookedStateDB) NewStorageSlotCount(addr common.Address) int {
|
||||||
|
return s.inner.NewStorageSlotCount(addr)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *hookedStateDB) AddRefund(u uint64) {
|
func (s *hookedStateDB) AddRefund(u uint64) {
|
||||||
s.inner.AddRefund(u)
|
s.inner.AddRefund(u)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
|
||||||
gas.RegularGas += uint64(len(authList)) * params.TxAuthTupleRegularGas
|
gas.RegularGas += uint64(len(authList)) * params.TxAuthTupleRegularGas
|
||||||
gas.StateGas += uint64(len(authList)) * (params.AuthorizationCreationSize + params.AccountCreationSize) * costPerStateByte
|
gas.StateGas += uint64(len(authList)) * (params.AuthorizationCreationSize + params.AccountCreationSize) * costPerStateByte
|
||||||
} else {
|
} else {
|
||||||
gas.RegularGas += uint64(len(authList)) * params.TxAuthTupleGas
|
gas.RegularGas += uint64(len(authList)) * params.CallNewAccountGas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataLen := uint64(len(data))
|
dataLen := uint64(len(data))
|
||||||
|
|
@ -607,6 +607,42 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
ret, st.gasRemaining, execGasUsed, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining, value)
|
ret, st.gasRemaining, execGasUsed, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On outer level tx failure, no state is written.
|
||||||
|
if rules.IsAmsterdam && vmerr != nil {
|
||||||
|
st.gasRemaining.StateGas += execGasUsed.StateGas
|
||||||
|
execGasUsed.StateGas = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refund costs for selfdestructed accounts and slots.
|
||||||
|
if rules.IsAmsterdam && vmerr == nil {
|
||||||
|
cpsb := st.evm.Context.CostPerGasByte
|
||||||
|
stateGasUsed := execGasUsed.StateGas + cost.StateGas
|
||||||
|
var sdRefund uint64
|
||||||
|
for _, addr := range st.state.SameTxSelfDestructs() {
|
||||||
|
r := params.AccountCreationSize * cpsb
|
||||||
|
r += uint64(st.state.NewStorageSlotCount(addr)) * params.StorageCreationSize * cpsb
|
||||||
|
r += uint64(st.state.GetCodeSize(addr)) * cpsb
|
||||||
|
sdRefund += r
|
||||||
|
}
|
||||||
|
if sdRefund > stateGasUsed {
|
||||||
|
sdRefund = stateGasUsed
|
||||||
|
}
|
||||||
|
if sdRefund > 0 {
|
||||||
|
st.gasRemaining.StateGas += sdRefund
|
||||||
|
if execGasUsed.StateGas >= sdRefund {
|
||||||
|
execGasUsed.StateGas -= sdRefund
|
||||||
|
} else {
|
||||||
|
extra := sdRefund - execGasUsed.StateGas
|
||||||
|
execGasUsed.StateGas = 0
|
||||||
|
if cost.StateGas >= extra {
|
||||||
|
cost.StateGas -= extra
|
||||||
|
} else {
|
||||||
|
cost.StateGas = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Record the gas used excluding gas refunds. This value represents the actual
|
// Record the gas used excluding gas refunds. This value represents the actual
|
||||||
// gas allowance required to complete execution.
|
// gas allowance required to complete execution.
|
||||||
peakGasUsed := st.gasUsed()
|
peakGasUsed := st.gasUsed()
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,18 @@ func (c *Contract) RefundGas(err error, initialRegularGasUsed uint64, gas GasBud
|
||||||
c.GasUsed.RegularGas = initialRegularGasUsed + gasUsed.RegularGas
|
c.GasUsed.RegularGas = initialRegularGasUsed + gasUsed.RegularGas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refunds the account creation state costs if a CREATE/CREATE2 call fails.
|
||||||
|
func (c *Contract) RefundCreateStateGas(refund uint64) {
|
||||||
|
if refund > 0 {
|
||||||
|
c.Gas.StateGas += refund
|
||||||
|
if c.GasUsed.StateGas >= refund {
|
||||||
|
c.GasUsed.StateGas -= refund
|
||||||
|
} else {
|
||||||
|
c.GasUsed.StateGas = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Address returns the contracts address
|
// Address returns the contracts address
|
||||||
func (c *Contract) Address() common.Address {
|
func (c *Contract) Address() common.Address {
|
||||||
return c.address
|
return c.address
|
||||||
|
|
|
||||||
|
|
@ -544,8 +544,10 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
||||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||||
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
|
||||||
}
|
}
|
||||||
|
// Record all burned gas
|
||||||
|
burned := gas.RegularGas
|
||||||
gas.Exhaust()
|
gas.Exhaust()
|
||||||
return nil, common.Address{}, gas, GasCosts{}, ErrContractAddressCollision
|
return nil, common.Address{}, gas, GasUsed{RegularGas: burned}, ErrContractAddressCollision
|
||||||
}
|
}
|
||||||
// Create a new account on the state only if the object was not present.
|
// Create a new account on the state only if the object was not present.
|
||||||
// It might be possible the contract code is deployed to a pre-existent
|
// It might be possible the contract code is deployed to a pre-existent
|
||||||
|
|
|
||||||
|
|
@ -671,12 +671,14 @@ func gasSStore8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
|
||||||
}
|
}
|
||||||
if original == current {
|
if original == current {
|
||||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||||
// EIP-8037: Return both regular and state gas. The interpreter
|
// EIP-8037: Return both regular and state gas. System calls do not charge state gas.
|
||||||
// charges regular gas before state gas, preventing reservoir
|
var stateGas uint64
|
||||||
// inflation when the regular charge OOGs.
|
if !contract.IsSystemCall {
|
||||||
|
stateGas = params.StorageCreationSize * evm.Context.CostPerGasByte
|
||||||
|
}
|
||||||
return GasCosts{
|
return GasCosts{
|
||||||
RegularGas: cost.RegularGas + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929,
|
RegularGas: cost.RegularGas + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929,
|
||||||
StateGas: params.StorageCreationSize * evm.Context.CostPerGasByte,
|
StateGas: stateGas,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
if value == (common.Hash{}) { // delete slot (2.1.2b)
|
if value == (common.Hash{}) { // delete slot (2.1.2b)
|
||||||
|
|
@ -695,9 +697,18 @@ func gasSStore8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
|
||||||
}
|
}
|
||||||
if original == value {
|
if original == value {
|
||||||
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
|
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
|
||||||
// EIP 2200 Original clause:
|
// EIP-8037 point (2): refund state gas directly to the reservoir
|
||||||
//evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200)
|
// at the SSTORE restoration point (0→x→0 in same tx); not to the
|
||||||
evm.StateDB.AddRefund(params.StorageCreationSize*evm.Context.CostPerGasByte + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929)
|
// refund counter, which is capped at gas_used/5.
|
||||||
|
stateRefund := params.StorageCreationSize * evm.Context.CostPerGasByte
|
||||||
|
contract.Gas.StateGas += stateRefund
|
||||||
|
if contract.GasUsed.StateGas >= stateRefund {
|
||||||
|
contract.GasUsed.StateGas -= stateRefund
|
||||||
|
} else {
|
||||||
|
contract.GasUsed.StateGas = 0
|
||||||
|
}
|
||||||
|
// Regular portion of the refund still goes through the refund counter.
|
||||||
|
evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929)
|
||||||
} else { // reset to original existing slot (2.2.2.2)
|
} else { // reset to original existing slot (2.2.2.2)
|
||||||
// EIP 2200 Original clause:
|
// EIP 2200 Original clause:
|
||||||
// evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200)
|
// evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200)
|
||||||
|
|
|
||||||
|
|
@ -682,7 +682,9 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(&stackvalue)
|
scope.Stack.push(&stackvalue)
|
||||||
|
|
||||||
scope.Contract.RefundGas(suberr, regularGasUsed, returnGas, childGasUsed, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
scope.Contract.RefundGas(suberr, regularGasUsed, returnGas, childGasUsed, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||||
|
if evm.chainRules.IsAmsterdam && suberr != nil {
|
||||||
|
scope.Contract.RefundCreateStateGas(params.AccountCreationSize * evm.Context.CostPerGasByte)
|
||||||
|
}
|
||||||
if suberr == ErrExecutionReverted {
|
if suberr == ErrExecutionReverted {
|
||||||
evm.returnData = res // set REVERT data to return data buffer
|
evm.returnData = res // set REVERT data to return data buffer
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
@ -719,6 +721,9 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||||
scope.Stack.push(&stackvalue)
|
scope.Stack.push(&stackvalue)
|
||||||
|
|
||||||
scope.Contract.RefundGas(suberr, regularGasUsed, returnGas, childGasUsed, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
scope.Contract.RefundGas(suberr, regularGasUsed, returnGas, childGasUsed, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||||
|
if evm.chainRules.IsAmsterdam && suberr != nil {
|
||||||
|
scope.Contract.RefundCreateStateGas(params.AccountCreationSize * evm.Context.CostPerGasByte)
|
||||||
|
}
|
||||||
|
|
||||||
if suberr == ErrExecutionReverted {
|
if suberr == ErrExecutionReverted {
|
||||||
evm.returnData = res // set REVERT data to return data buffer
|
evm.returnData = res // set REVERT data to return data buffer
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,14 @@ type StateDB interface {
|
||||||
// during the current transaction.
|
// during the current transaction.
|
||||||
IsNewContract(addr common.Address) bool
|
IsNewContract(addr common.Address) bool
|
||||||
|
|
||||||
|
// SameTxSelfDestructs returns addresses that were created and then
|
||||||
|
// self-destructed in the current transaction.
|
||||||
|
SameTxSelfDestructs() []common.Address
|
||||||
|
|
||||||
|
// NewStorageSlotCount returns the number of storage slots written to a
|
||||||
|
// non-zero value in the current transaction on the given address.
|
||||||
|
NewStorageSlotCount(addr common.Address) int
|
||||||
|
|
||||||
// Empty returns whether the given account is empty. Empty
|
// Empty returns whether the given account is empty. Empty
|
||||||
// is defined according to EIP161 (balance = nonce = code = 0).
|
// is defined according to EIP161 (balance = nonce = code = 0).
|
||||||
Empty(common.Address) bool
|
Empty(common.Address) bool
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue