mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-26 16:36:17 +00:00
core: use source-based refund mechanism
This commit is contained in:
parent
0b3dffcf00
commit
906488333c
5 changed files with 78 additions and 78 deletions
|
|
@ -674,11 +674,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
ret []byte
|
||||
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
||||
result vm.GasBudget
|
||||
|
||||
// Capture the forwarded regular-gas amount BEFORE ForwardAll consumes
|
||||
// it, so Absorb can back out state-gas spillover from UsedRegularGas
|
||||
// per EIP-8037.
|
||||
forwarded = st.gasRemaining.RegularGas
|
||||
)
|
||||
if contractCreation {
|
||||
// Check whether the init code size has been exceeded.
|
||||
|
|
@ -688,7 +683,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
// Execute the transaction's creation.
|
||||
var creation bool
|
||||
ret, _, result, creation, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining.ForwardAll(), value)
|
||||
st.gasRemaining.Absorb(result, forwarded)
|
||||
st.gasRemaining.Absorb(result)
|
||||
|
||||
// If the contract creation failed, or the destination was pre-existing,
|
||||
// refund the account-creation state gas pre-charged in IntrinsicGas.
|
||||
|
|
@ -712,7 +707,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
}
|
||||
// Execute the transaction's call.
|
||||
ret, result, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining.ForwardAll(), value)
|
||||
st.gasRemaining.Absorb(result, forwarded)
|
||||
st.gasRemaining.Absorb(result)
|
||||
}
|
||||
|
||||
// Settle down the gas usage and refund the ETH back if any remaining
|
||||
|
|
|
|||
|
|
@ -163,9 +163,9 @@ func (c *Contract) refundState(s uint64, logger *tracing.Hooks, reason tracing.G
|
|||
}
|
||||
|
||||
// refundGas absorbs a sub-call's leftover GasBudget into this contract's gas state.
|
||||
func (c *Contract) refundGas(child GasBudget, forwarded uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) {
|
||||
func (c *Contract) refundGas(child GasBudget, logger *tracing.Hooks, reason tracing.GasChangeReason) {
|
||||
prior := c.Gas
|
||||
c.Gas.Absorb(child, forwarded)
|
||||
c.Gas.Absorb(child)
|
||||
if logger.HasGasHook() && reason != tracing.GasChangeIgnored {
|
||||
logger.EmitGasChange(prior.AsTracing(), c.Gas.AsTracing(), reason)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
|||
if !syscall && !value.IsZero() && !evm.Context.CanTransfer(evm.StateDB, caller, value) {
|
||||
return nil, gas, ErrInsufficientBalance
|
||||
}
|
||||
snapshot, reservoir := evm.StateDB.Snapshot(), gas.StateGas
|
||||
snapshot := evm.StateDB.Snapshot()
|
||||
p, isPrecompile := evm.precompile(addr)
|
||||
if !evm.StateDB.Exist(addr) {
|
||||
if !isPrecompile && evm.chainRules.IsEIP4762 && !isSystemCall(caller) {
|
||||
|
|
@ -279,7 +279,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
|||
wgas := evm.AccessEvents.CodeHashGas(addr, true, gas.RegularGas, false)
|
||||
if _, ok := gas.ChargeRegular(wgas); !ok {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
return nil, gas.ExitHalt(reservoir), ErrOutOfGas
|
||||
return nil, gas.ExitHalt(), ErrOutOfGas
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +314,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
|||
}
|
||||
|
||||
// Calculate the remaining gas at the end of frame
|
||||
exitGas := gas.Exit(err, reservoir)
|
||||
exitGas := gas.Exit(err)
|
||||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
|||
if !evm.Context.CanTransfer(evm.StateDB, caller, value) {
|
||||
return nil, gas, ErrInsufficientBalance
|
||||
}
|
||||
snapshot, reservoir := evm.StateDB.Snapshot(), gas.StateGas
|
||||
snapshot := evm.StateDB.Snapshot()
|
||||
|
||||
// It is allowed to call precompiles, even via delegatecall
|
||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||
|
|
@ -365,7 +365,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
|||
}
|
||||
|
||||
// Calculate the remaining gas at the end of frame
|
||||
exitGas := gas.Exit(err, reservoir)
|
||||
exitGas := gas.Exit(err)
|
||||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
|
||||
|
|
@ -396,7 +396,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
|||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, ErrDepth
|
||||
}
|
||||
snapshot, reservoir := evm.StateDB.Snapshot(), gas.StateGas
|
||||
snapshot := evm.StateDB.Snapshot()
|
||||
|
||||
// It is allowed to call precompiles, even via delegatecall
|
||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||
|
|
@ -409,7 +409,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
|||
}
|
||||
|
||||
// Calculate the remaining gas at the end of frame
|
||||
exitGas := gas.Exit(err, reservoir)
|
||||
exitGas := gas.Exit(err)
|
||||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
|
||||
|
|
@ -443,7 +443,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
|||
// after all empty accounts were deleted, so this is not required. However, if we omit this,
|
||||
// then certain tests start failing; stRevertTest/RevertPrecompiledTouchExactOOG.json.
|
||||
// We could change this, but for now it's left for legacy reasons
|
||||
snapshot, reservoir := evm.StateDB.Snapshot(), gas.StateGas
|
||||
snapshot := evm.StateDB.Snapshot()
|
||||
|
||||
// We do an AddBalance of zero here, just in order to trigger a touch.
|
||||
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
|
||||
|
|
@ -461,7 +461,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
|||
}
|
||||
|
||||
// Calculate the remaining gas at the end of frame
|
||||
exitGas := gas.Exit(err, reservoir)
|
||||
exitGas := gas.Exit(err)
|
||||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
|
|
@ -499,14 +499,13 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
|||
}
|
||||
// Increment the caller's nonce after passing all validations
|
||||
evm.StateDB.SetNonce(caller, nonce+1, tracing.NonceChangeContractCreator)
|
||||
reservoir := gas.StateGas
|
||||
|
||||
// Charge the contract creation init gas in verkle mode
|
||||
if evm.chainRules.IsEIP4762 {
|
||||
statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address, gas.RegularGas)
|
||||
prior, ok := gas.Charge(GasCosts{RegularGas: statelessGas})
|
||||
if !ok {
|
||||
return nil, common.Address{}, gas.ExitHalt(reservoir), false, ErrOutOfGas
|
||||
return nil, common.Address{}, gas.ExitHalt(), false, ErrOutOfGas
|
||||
}
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(prior.AsTracing(), gas.AsTracing(), tracing.GasChangeWitnessContractCollisionCheck)
|
||||
|
|
@ -527,7 +526,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
|||
if evm.StateDB.GetNonce(address) != 0 ||
|
||||
(contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code
|
||||
isEIP7610RejectedAccount(evm.ChainConfig().ChainID, address, evm.chainRules.IsEIP158) {
|
||||
halt := gas.ExitHalt(reservoir)
|
||||
halt := gas.ExitHalt()
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(gas.AsTracing(), halt.AsTracing(), tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
|
|
@ -556,7 +555,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
|||
if evm.chainRules.IsEIP4762 {
|
||||
consumed, wanted := evm.AccessEvents.ContractCreateInitGas(address, gas.RegularGas)
|
||||
if consumed < wanted {
|
||||
return nil, common.Address{}, gas.ExitHalt(reservoir), false, ErrOutOfGas
|
||||
return nil, common.Address{}, gas.ExitHalt(), false, ErrOutOfGas
|
||||
}
|
||||
prior, _ := gas.Charge(GasCosts{RegularGas: consumed})
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
|
|
@ -581,7 +580,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasBudget, value
|
|||
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
|
||||
exit := contract.Gas.Exit(err, reservoir)
|
||||
exit := contract.Gas.Exit(err)
|
||||
if err != ErrExecutionReverted {
|
||||
if evm.Config.Tracer.HasGasHook() {
|
||||
evm.Config.Tracer.EmitGasChange(contract.Gas.AsTracing(), exit.AsTracing(), tracing.GasChangeCallFailedExecution)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ type GasBudget struct {
|
|||
StateGas uint64 // remaining state-gas reservoir (or leftover for caller to absorb)
|
||||
UsedRegularGas uint64 // gross regular gas consumed in this frame
|
||||
UsedStateGas int64 // signed net state-gas consumed in this frame
|
||||
|
||||
// StateGasFromGasLeft tracks how much of this frame's regular gas (gas_left)
|
||||
// has been borrowed to cover state-gas charges that exceeded the reservoir
|
||||
// (the "spillover").
|
||||
StateGasFromGasLeft uint64
|
||||
}
|
||||
|
||||
// NewGasBudget initializes a fresh GasBudget for execution / forwarding,
|
||||
|
|
@ -82,7 +87,7 @@ func (g GasBudget) Used(initial GasBudget) uint64 {
|
|||
|
||||
// String returns a visual representation of the budget.
|
||||
func (g GasBudget) String() string {
|
||||
return fmt.Sprintf("<%v,%v,used=<%v,%v>>", g.RegularGas, g.StateGas, g.UsedRegularGas, g.UsedStateGas)
|
||||
return fmt.Sprintf("<%v,%v,used=<%v,%v>,borrowed=%v>", g.RegularGas, g.StateGas, g.UsedRegularGas, g.UsedStateGas, g.StateGasFromGasLeft)
|
||||
}
|
||||
|
||||
// CanAfford reports whether the running balance can cover the given cost.
|
||||
|
|
@ -117,6 +122,10 @@ func (g *GasBudget) Charge(cost GasCosts) (GasBudget, bool) {
|
|||
spillover := cost.StateGas - g.StateGas
|
||||
g.StateGas = 0
|
||||
g.RegularGas -= spillover
|
||||
|
||||
// Record the regular gas borrowed to cover the overflowing state gas
|
||||
// so a later inline refund can repay it before topping up the reservoir.
|
||||
g.StateGasFromGasLeft += spillover
|
||||
} else {
|
||||
g.StateGas -= cost.StateGas
|
||||
}
|
||||
|
|
@ -146,14 +155,27 @@ func (g *GasBudget) IsZero() bool {
|
|||
}
|
||||
|
||||
// RefundState applies an inline state-gas refund (e.g., SSTORE 0->A->0).
|
||||
// The reservoir is credited and the signed usage counter is decremented
|
||||
// in lockstep, preserving the per-frame invariant:
|
||||
//
|
||||
// StateGas + UsedStateGas == initialStateGas + spillover_so_far
|
||||
// Per EIP-8037, the refund repays the regular gas previously borrowed for
|
||||
// state-gas spillover (tracked by StateGasFromGasLeft) before crediting the
|
||||
// reservoir: it is returned to RegularGas up to the outstanding borrowed
|
||||
// amount, and only the remainder tops up StateGas. This keeps the regular and
|
||||
// state pools from drifting into one another.
|
||||
//
|
||||
// which the revert path relies on for the correct gross refund.
|
||||
// The signed usage counter is decremented by the full refund regardless of the
|
||||
// split, preserving the per-frame invariant:
|
||||
//
|
||||
// StateGas + UsedStateGas == initialStateGas + StateGasFromGasLeft
|
||||
//
|
||||
// which the revert and halt paths rely on for the correct gross refund.
|
||||
func (g *GasBudget) RefundState(s uint64) {
|
||||
g.StateGas += s
|
||||
// Repay the borrowed regular gas first, capped at the outstanding amount.
|
||||
repay := min(s, g.StateGasFromGasLeft)
|
||||
g.RegularGas += repay
|
||||
g.StateGasFromGasLeft -= repay
|
||||
|
||||
// Whatever is left tops up the reservoir.
|
||||
g.StateGas += s - repay
|
||||
g.UsedStateGas -= int64(s)
|
||||
}
|
||||
|
||||
|
|
@ -201,53 +223,46 @@ func (g GasBudget) ExitSuccess() GasBudget {
|
|||
return g
|
||||
}
|
||||
|
||||
// ExitRevert produces the leftover for a REVERT exit. Per EIP-8037, all state
|
||||
// gas charged by the reverted frame is refunded to the caller's reservoir:
|
||||
//
|
||||
// leftover.StateGas = StateGas + UsedStateGas
|
||||
//
|
||||
// UsedStateGas is reset since the frame's state changes are discarded.
|
||||
// ExitRevert produces the leftover for a REVERT exit. The frame's state
|
||||
// changes are discarded, so all state gas it charged is refilled to its origin
|
||||
// (EIP-8037): up to StateGasFromGasLeft is returned to RegularGas (the regular
|
||||
// gas it borrowed), and the remainder restores the reservoir. Because the
|
||||
// borrowed regular gas is repaid first, the reservoir is made whole back to its
|
||||
// start-of-frame value:
|
||||
func (g GasBudget) ExitRevert() GasBudget {
|
||||
reservoir := int64(g.StateGas) + g.UsedStateGas
|
||||
reservoir := int64(g.StateGas) + g.UsedStateGas - int64(g.StateGasFromGasLeft)
|
||||
if reservoir < 0 {
|
||||
// Reservoir should never be negative. By construction it equals
|
||||
// the initial state-gas allocation plus any spillover to regular
|
||||
// gas.
|
||||
// the initial state-gas allocation.
|
||||
reservoir = 0
|
||||
log.Warn("Negative reservoir at revert", "remaining", g.StateGas, "used", g.UsedStateGas)
|
||||
log.Warn("Negative reservoir at revert", "remaining", g.StateGas, "used", g.UsedStateGas, "borrowed", g.StateGasFromGasLeft)
|
||||
}
|
||||
return GasBudget{
|
||||
RegularGas: g.RegularGas,
|
||||
RegularGas: g.RegularGas + g.StateGasFromGasLeft,
|
||||
StateGas: uint64(reservoir),
|
||||
UsedRegularGas: g.UsedRegularGas,
|
||||
UsedStateGas: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// ExitHalt produces the leftover for an exceptional halt.
|
||||
//
|
||||
// - state_gas_reservoir is reset back to its value at the start of the child frame
|
||||
// - the gas_left initially given to the child is consumed (set to zero)
|
||||
func (g GasBudget) ExitHalt(initStateReservoir uint64) GasBudget {
|
||||
reservoir := int64(g.StateGas) + g.UsedStateGas
|
||||
// ExitHalt produces the leftover for an exceptional halt. As with a revert, the
|
||||
// frame's state changes are rolled back and its state gas is refilled to origin
|
||||
// (EIP-8037); the difference is that the frame's gas_left is consumed rather
|
||||
// than returned. The portion refilled to RegularGas is therefore burned along
|
||||
// with the rest of gas_left, leaving only the reservoir portion to survive,
|
||||
// which equals the reservoir's value at the start of the frame.
|
||||
func (g GasBudget) ExitHalt() GasBudget {
|
||||
reservoir := int64(g.StateGas) + g.UsedStateGas - int64(g.StateGasFromGasLeft)
|
||||
if reservoir < 0 {
|
||||
// Reservoir should never be negative. By construction it equals
|
||||
// the initial state-gas allocation plus any spillover to regular
|
||||
// gas.
|
||||
// the initial state-gas allocation.
|
||||
reservoir = 0
|
||||
log.Warn("Negative reservoir at halt", "remaining", g.StateGas, "used", g.UsedStateGas)
|
||||
}
|
||||
// The portion of state gas charged from regular gas is also burned
|
||||
// together with the regular gas, rather than being returned to the
|
||||
// parent's state-gas reservoir.
|
||||
var spilled uint64
|
||||
if uint64(reservoir) > initStateReservoir {
|
||||
spilled = uint64(reservoir) - initStateReservoir
|
||||
log.Warn("Negative reservoir at halt", "remaining", g.StateGas, "used", g.UsedStateGas, "borrowed", g.StateGasFromGasLeft)
|
||||
}
|
||||
return GasBudget{
|
||||
RegularGas: 0,
|
||||
StateGas: initStateReservoir,
|
||||
UsedRegularGas: g.UsedRegularGas + g.RegularGas + spilled,
|
||||
StateGas: uint64(reservoir),
|
||||
UsedRegularGas: g.UsedRegularGas + g.RegularGas + g.StateGasFromGasLeft,
|
||||
UsedStateGas: 0,
|
||||
}
|
||||
}
|
||||
|
|
@ -258,17 +273,14 @@ func (g GasBudget) ExitHalt(initStateReservoir uint64) GasBudget {
|
|||
// - err == nil → ExitSuccess
|
||||
// - err == ErrExecutionReverted → ExitRevert
|
||||
// - any other err → ExitHalt
|
||||
//
|
||||
// Soft validation failures (occurring BEFORE evm.Run) should call Preserved
|
||||
// directly instead of going through this dispatcher.
|
||||
func (g GasBudget) Exit(err error, initStateReservoir uint64) GasBudget {
|
||||
func (g GasBudget) Exit(err error) GasBudget {
|
||||
switch {
|
||||
case err == nil:
|
||||
return g.ExitSuccess()
|
||||
case err == ErrExecutionReverted:
|
||||
return g.ExitRevert()
|
||||
default:
|
||||
return g.ExitHalt(initStateReservoir)
|
||||
return g.ExitHalt()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -276,18 +288,12 @@ func (g GasBudget) Exit(err error, initStateReservoir uint64) GasBudget {
|
|||
// budget. Additionally, it does an EIP-8037 spillover correction:
|
||||
// state-gas that spilled into the regular pool inside the child frame is
|
||||
// excluded from the UsedRegularGas.
|
||||
//
|
||||
// spillover = forwarded - child.RegularGas - child.UsedRegularGas
|
||||
//
|
||||
// forwarded is the regular-gas amount that was passed to the child at call
|
||||
// entry (i.e., the regular initial of the child's GasBudget).
|
||||
func (g *GasBudget) Absorb(child GasBudget, forwarded uint64) {
|
||||
spillover := forwarded - child.RegularGas - child.UsedRegularGas
|
||||
|
||||
func (g *GasBudget) Absorb(child GasBudget) {
|
||||
g.UsedRegularGas -= child.RegularGas
|
||||
g.RegularGas += child.RegularGas
|
||||
g.StateGas = child.StateGas
|
||||
g.UsedStateGas += child.UsedStateGas
|
||||
|
||||
g.UsedRegularGas -= spillover
|
||||
g.UsedRegularGas -= child.StateGasFromGasLeft
|
||||
g.StateGasFromGasLeft += child.StateGasFromGasLeft
|
||||
}
|
||||
|
|
|
|||
|
|
@ -677,7 +677,7 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
scope.Stack.push(&stackvalue)
|
||||
|
||||
// Refund the leftover gas back to current frame
|
||||
scope.Contract.refundGas(result, forward, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
// Refund the state gas of account-creation if creation doesn't happen
|
||||
if evm.GetRules().IsAmsterdam && !creation {
|
||||
|
|
@ -715,7 +715,7 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
scope.Stack.push(&stackvalue)
|
||||
|
||||
// Refund the leftover gas back to current frame
|
||||
scope.Contract.refundGas(result, forward, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
// Refund the state gas of account-creation if creation doesn't happen
|
||||
if evm.GetRules().IsAmsterdam && !creation {
|
||||
|
|
@ -764,7 +764,7 @@ func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
if err == nil || err == ErrExecutionReverted {
|
||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
scope.Contract.refundGas(result, gas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
// If the call frame reverts or halts exceptionally, the charged state-gas
|
||||
// is refilled back to the state reservoir in Amsterdam.
|
||||
|
|
@ -805,7 +805,7 @@ func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
|
||||
scope.Contract.refundGas(result, gas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
evm.returnData = ret
|
||||
return ret, nil
|
||||
|
|
@ -837,7 +837,7 @@ func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
if err == nil || err == ErrExecutionReverted {
|
||||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
scope.Contract.refundGas(result, gas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
evm.returnData = ret
|
||||
return ret, nil
|
||||
|
|
@ -870,7 +870,7 @@ func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
|
||||
scope.Contract.refundGas(result, gas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.refundGas(result, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
evm.returnData = ret
|
||||
return ret, nil
|
||||
|
|
|
|||
Loading…
Reference in a new issue