Skip to content

Return multi-gas in execution result #488

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
}
evm.SetTxContext(NewEVMTxContext(msg))
evm.StateDB.AddAddressToAccessList(params.BeaconRootsAddress)
_, _, _ = evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
_, _, _, _ = evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
evm.StateDB.Finalise(true)
}

Expand All @@ -274,7 +274,7 @@ func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) {
}
evm.SetTxContext(NewEVMTxContext(msg))
evm.StateDB.AddAddressToAccessList(params.HistoryStorageAddress)
_, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
_, _, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -313,7 +313,7 @@ func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte
}
evm.SetTxContext(NewEVMTxContext(msg))
evm.StateDB.AddAddressToAccessList(addr)
ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
ret, _, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560)
evm.StateDB.Finalise(true)
if err != nil {
return fmt.Errorf("system call failed to execute: %v", err)
Expand Down
14 changes: 12 additions & 2 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"math"
"math/big"

"github.com/ethereum/go-ethereum/arbitrum/multigas"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/tracing"
Expand All @@ -44,6 +45,8 @@ type ExecutionResult struct {
ScheduledTxes types.Transactions
// Arbitrum: the contract deployed from the top-level transaction, or nil if not a contract creation tx
TopLevelDeployed *common.Address
// Arbitrum: total used multi-dimensional gas
UsedMultiGas *multigas.MultiGas
}

// Unwrap returns the internal evm error which allows us for further
Expand Down Expand Up @@ -554,6 +557,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
Err: err,
ReturnData: returnData,
ScheduledTxes: st.evm.ProcessingHook.ScheduledTxes(),
UsedMultiGas: multigas.ZeroGas(),
}, nil
}

Expand Down Expand Up @@ -583,6 +587,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time, st.evm.Context.ArbOSVersion)
contractCreation = msg.To == nil
floorDataGas uint64
usedMultiGas = multigas.ZeroGas()
)

// Check clauses 4-5, subtract intrinsic gas if everything is correct
Expand Down Expand Up @@ -671,15 +676,16 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
}

// Execute the transaction's call.
ret, st.gasRemaining, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining, value)
ret, st.gasRemaining, usedMultiGas, vmerr = st.evm.Call(msg.From, st.to(), msg.Data, st.gasRemaining, value)
}

// Record the gas used excluding gas refunds. This value represents the actual
// gas allowance required to complete execution.
peakGasUsed := st.gasUsed()

// Compute refund counter, capped to a refund quotient.
st.gasRemaining += st.calcRefund()
refund := st.calcRefund()
st.gasRemaining += refund
if rules.IsPrague && st.evm.ProcessingHook.IsCalldataPricingIncreaseEnabled() {
// After EIP-7623: Data-heavy transactions pay the floor gas.
if st.gasUsed() < floorDataGas {
Expand All @@ -695,6 +701,9 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
}
st.returnGas()

// Arbitrum: set the multigas refunds
usedMultiGas.SetRefund(refund)

effectiveTip := msg.GasPrice
if rules.IsLondon {
effectiveTip = new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee)
Expand Down Expand Up @@ -742,6 +751,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
ReturnData: ret,
ScheduledTxes: st.evm.ProcessingHook.ScheduledTxes(),
TopLevelDeployed: deployedContract,
UsedMultiGas: usedMultiGas,
}, nil
}

Expand Down
15 changes: 10 additions & 5 deletions core/vm/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package vm

import (
"github.com/ethereum/go-ethereum/arbitrum/multigas"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/holiman/uint256"
Expand Down Expand Up @@ -47,6 +48,9 @@ type Contract struct {

Gas uint64
value *uint256.Int

// Arbitrum: total used multi-dimensional gas
UsedMultiGas *multigas.MultiGas
}

// NewContract returns a new contract environment for the execution of EVM.
Expand All @@ -56,11 +60,12 @@ func NewContract(caller common.Address, address common.Address, value *uint256.I
jumpDests = make(map[common.Hash]bitvec)
}
return &Contract{
caller: caller,
address: address,
jumpdests: jumpDests,
Gas: gas,
value: value,
caller: caller,
address: address,
jumpdests: jumpDests,
Gas: gas,
value: value,
UsedMultiGas: multigas.ZeroGas(),
}
}

Expand Down
16 changes: 10 additions & 6 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

"github.com/holiman/uint256"

"github.com/ethereum/go-ethereum/arbitrum/multigas"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing"
Expand Down Expand Up @@ -198,7 +199,7 @@ func isSystemCall(caller common.Address) bool {
// parameters. It also handles any necessary value transfer required and takse
// the necessary steps to create accounts and reverses the state in case of an
// execution error or failed value transfer.
func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, usedMultiGas *multigas.MultiGas, err error) {
// Capture the tracer start/end events in debug mode
if evm.Config.Tracer != nil {
evm.captureBegin(evm.depth, CALL, caller, addr, input, gas, value.ToBig())
Expand All @@ -208,29 +209,30 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
}
// Fail if we're trying to execute above the call depth limit
if evm.depth > int(params.CallCreateDepth) {
return nil, gas, ErrDepth
return nil, gas, multigas.ZeroGas(), ErrDepth
}
// Fail if we're trying to transfer more than the available balance
if !value.IsZero() && !evm.Context.CanTransfer(evm.StateDB, caller, value) {
return nil, gas, ErrInsufficientBalance
return nil, gas, multigas.ZeroGas(), ErrInsufficientBalance
}
snapshot := evm.StateDB.Snapshot()
p, isPrecompile := evm.precompile(addr)
usedMultiGas = multigas.ZeroGas()

if !evm.StateDB.Exist(addr) {
if !isPrecompile && evm.chainRules.IsEIP4762 && !isSystemCall(caller) {
// add proof of absence to witness
wgas := evm.AccessEvents.AddAccount(addr, false)
if gas < wgas {
evm.StateDB.RevertToSnapshot(snapshot)
return nil, 0, ErrOutOfGas
return nil, 0, multigas.ZeroGas(), ErrOutOfGas
}
gas -= wgas
}

if !isPrecompile && evm.chainRules.IsEIP158 && value.IsZero() {
// Calling a non-existing account, don't do anything.
return nil, gas, nil
return nil, gas, usedMultiGas, nil
}
evm.StateDB.CreateAccount(addr)
}
Expand Down Expand Up @@ -258,6 +260,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
contract.SetCallCode(evm.resolveCodeHash(addr), code)
ret, err = evm.interpreter.Run(contract, input, false)
gas = contract.Gas
usedMultiGas, _ = usedMultiGas.SafeAdd(usedMultiGas, contract.UsedMultiGas)
}
}
// When an error was returned by the EVM or when setting the creation code
Expand All @@ -270,13 +273,14 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
}

usedMultiGas.SafeIncrement(multigas.ResourceKindComputation, gas)
gas = 0
}
// TODO: consider clearing up unused snapshots:
//} else {
// evm.StateDB.DiscardSnapshot(snapshot)
}
return ret, gas, err
return ret, gas, usedMultiGas, err
}

// CallCode executes the contract associated with the addr with the given input
Expand Down
4 changes: 2 additions & 2 deletions core/vm/gas_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func TestEIP2200(t *testing.T) {
}
evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}})

_, gas, err := evm.Call(common.Address{}, address, nil, tt.gaspool, new(uint256.Int))
_, gas, _, err := evm.Call(common.Address{}, address, nil, tt.gaspool, new(uint256.Int))
if !errors.Is(err, tt.failure) {
t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
}
Expand Down Expand Up @@ -153,7 +153,7 @@ func TestCreateGas(t *testing.T) {

evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, config)
var startGas = uint64(testGas)
ret, gas, err := evm.Call(common.Address{}, address, nil, startGas, new(uint256.Int))
ret, gas, _, err := evm.Call(common.Address{}, address, nil, startGas, new(uint256.Int))
if err != nil {
return false
}
Expand Down
2 changes: 1 addition & 1 deletion core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
if !value.IsZero() {
gas += params.CallStipend
}
ret, returnGas, err := interpreter.evm.Call(scope.Contract.Address(), toAddr, args, gas, &value)
ret, returnGas, _, err := interpreter.evm.Call(scope.Contract.Address(), toAddr, args, gas, &value)

if err != nil {
temp.Clear()
Expand Down
6 changes: 5 additions & 1 deletion core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package vm
import (
"fmt"

"github.com/ethereum/go-ethereum/arbitrum/multigas"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/state"
Expand Down Expand Up @@ -267,6 +268,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
} else {
contract.Gas -= cost
}
contract.UsedMultiGas.SafeIncrement(multigas.ResourceKindComputation, cost)

// All ops with a dynamic memory usage also has a dynamic gas cost.
var memorySize uint64
Expand All @@ -289,7 +291,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// Consume the gas and return an error if not enough gas is available.
// cost is explicitly set so that the capture state defer method can get the proper cost
var dynamicCost uint64
_, dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
var multigasDynamicCost *multigas.MultiGas
multigasDynamicCost, dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
cost += dynamicCost // for tracing
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
Expand All @@ -300,6 +303,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
} else {
contract.Gas -= dynamicCost
}
contract.UsedMultiGas, _ = contract.UsedMultiGas.SafeAdd(contract.UsedMultiGas, multigasDynamicCost)
}

// Do tracing before potential memory expansion
Expand Down
2 changes: 1 addition & 1 deletion core/vm/interpreter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestLoopInterrupt(t *testing.T) {
timeout := make(chan bool)

go func(evm *EVM) {
_, _, err := evm.Call(common.Address{}, address, nil, math.MaxUint64, new(uint256.Int))
_, _, _, err := evm.Call(common.Address{}, address, nil, math.MaxUint64, new(uint256.Int))
errChannel <- err
}(evm)

Expand Down
4 changes: 2 additions & 2 deletions core/vm/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
// set the receiver's (the executing contract) code for execution.
cfg.State.SetCode(address, code)
// Call the code with the given configuration.
ret, leftOverGas, err := vmenv.Call(
ret, leftOverGas, _, err := vmenv.Call(
cfg.Origin,
common.BytesToAddress([]byte("contract")),
input,
Expand Down Expand Up @@ -210,7 +210,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)

// Call the code with the given configuration.
ret, leftOverGas, err := vmenv.Call(
ret, leftOverGas, _, err := vmenv.Call(
cfg.Origin,
address,
input,
Expand Down
2 changes: 1 addition & 1 deletion tests/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
start := time.Now()

// Execute the message.
_, leftOverGas, err := evm.Call(sender.Address(), *msg.To, msg.Data, msg.GasLimit, uint256.MustFromBig(msg.Value))
_, leftOverGas, _, err := evm.Call(sender.Address(), *msg.To, msg.Data, msg.GasLimit, uint256.MustFromBig(msg.Value))
if err != nil {
b.Error(err)
return
Expand Down
Loading