diff --git a/fvm/evm/emulator/emulator.go b/fvm/evm/emulator/emulator.go index b86821e9f7f..a6a3b2bfbbd 100644 --- a/fvm/evm/emulator/emulator.go +++ b/fvm/evm/emulator/emulator.go @@ -236,9 +236,21 @@ func (bl *BlockView) DryRunTransaction( // return without commiting the state txResult, err := proc.run(msg, tx.Hash(), 0, tx.Type()) if txResult.Successful() { + // As mentioned in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md#specification + // Define "all but one 64th" of N as N - floor(N / 64). + // If a call asks for more gas than the maximum allowed amount + // (i.e. the total amount of gas remaining in the parent after subtracting + // the gas cost of the call and memory expansion), do not return an OOG error; + // instead, if a call asks for more gas than all but one 64th of the maximum + // allowed amount, call with all but one 64th of the maximum allowed amount of + // gas (this is equivalent to a version of EIP-901 plus EIP-1142). + // CREATE only provides all but one 64th of the parent gas to the child call. + txResult.GasConsumed = AddOne64th(txResult.GasConsumed) + // Adding `gethParams.SstoreSentryGasEIP2200` is needed for this condition: // https://github.com/onflow/go-ethereum/blob/master/core/vm/operations_acl.go#L29-L32 txResult.GasConsumed += gethParams.SstoreSentryGasEIP2200 + // Take into account any gas refunds, which are calculated only after // transaction execution. txResult.GasConsumed += txResult.GasRefund @@ -557,3 +569,8 @@ func (proc *procedure) run( } return &res, nil } + +func AddOne64th(n uint64) uint64 { + // NOTE: Go's integer division floors, but that is desirable here + return n + (n / 64) +} diff --git a/fvm/evm/evm_test.go b/fvm/evm/evm_test.go index 3346238a30a..971e7b99fdb 100644 --- a/fvm/evm/evm_test.go +++ b/fvm/evm/evm_test.go @@ -25,6 +25,7 @@ import ( "github.com/onflow/flow-go/fvm/crypto" envMock "github.com/onflow/flow-go/fvm/environment/mock" "github.com/onflow/flow-go/fvm/evm" + "github.com/onflow/flow-go/fvm/evm/emulator" "github.com/onflow/flow-go/fvm/evm/stdlib" "github.com/onflow/flow-go/fvm/evm/testutils" . "github.com/onflow/flow-go/fvm/evm/testutils" @@ -1534,9 +1535,10 @@ func TestDryRun(t *testing.T) { // Make sure that gas consumed from `EVM.dryRun` is bigger // than the actual gas consumption of the equivalent // `EVM.run`. + totalGas := emulator.AddOne64th(res.GasConsumed) + gethParams.SstoreSentryGasEIP2200 require.Equal( t, - res.GasConsumed+gethParams.SstoreSentryGasEIP2200, + totalGas, dryRunResult.GasConsumed, ) }) @@ -1667,9 +1669,10 @@ func TestDryRun(t *testing.T) { // Make sure that gas consumed from `EVM.dryRun` is bigger // than the actual gas consumption of the equivalent // `EVM.run`. + totalGas := emulator.AddOne64th(res.GasConsumed) + gethParams.SstoreSentryGasEIP2200 require.Equal( t, - res.GasConsumed+gethParams.SstoreSentryGasEIP2200, + totalGas, dryRunResult.GasConsumed, ) }) @@ -1798,9 +1801,10 @@ func TestDryRun(t *testing.T) { // Make sure that gas consumed from `EVM.dryRun` is bigger // than the actual gas consumption of the equivalent // `EVM.run`. + totalGas := emulator.AddOne64th(res.GasConsumed) + gethParams.SstoreSentryGasEIP2200 + gethParams.SstoreClearsScheduleRefundEIP3529 require.Equal( t, - res.GasConsumed+gethParams.SstoreSentryGasEIP2200+gethParams.SstoreClearsScheduleRefundEIP3529, + totalGas, dryRunResult.GasConsumed, ) })