Skip to content

Commit

Permalink
fix(libevm/legacy): allow to use all the gas in PrecompiledStatefulCo…
Browse files Browse the repository at this point in the history
…ntract
  • Loading branch information
qdm12 committed Feb 4, 2025
1 parent 8d288b7 commit c130fa0
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 8 deletions.
11 changes: 3 additions & 8 deletions libevm/legacy/legacy.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 the libevm authors.
// Copyright 2024-2025 the libevm authors.
//
// The libevm additions to go-ethereum are free software: you can redistribute
// them and/or modify them under the terms of the GNU Lesser General Public License
Expand All @@ -19,7 +19,6 @@
package legacy

import (
"errors"
"fmt"

"github.com/ava-labs/libevm/core/vm"
Expand All @@ -31,19 +30,15 @@ import (
// gas-management methods as this may result in unexpected behaviour.
type PrecompiledStatefulContract func(env vm.PrecompileEnvironment, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error)

var (
ErrGasRemainingExceedsGasSupplied = errors.New("remaining gas exceeds supplied gas")
)

// Upgrade converts the legacy precompile signature into the now-required form.
func (c PrecompiledStatefulContract) Upgrade() vm.PrecompiledStatefulContract {
return func(env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
gas := env.Gas()
ret, remainingGas, err := c(env, input, gas)
if remainingGas > gas {
return nil, fmt.Errorf("%w: %d > %d", ErrGasRemainingExceedsGasSupplied, remainingGas, gas)
return nil, fmt.Errorf("remaining gas %d exceeds supplied gas %d", remainingGas, gas)
}
if used := gas - remainingGas; used < gas {
if used := gas - remainingGas; used <= gas {
env.UseGas(used)
}
return ret, err
Expand Down
97 changes: 97 additions & 0 deletions libevm/legacy/legacy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package legacy

import (
"errors"
"testing"

"github.com/ava-labs/libevm/core/vm"
"github.com/stretchr/testify/assert"
)

func TestPrecompiledStatefulContract_Upgrade(t *testing.T) {

Check failure on line 11 in libevm/legacy/legacy_test.go

View workflow job for this annotation

GitHub Actions / lint

TestPrecompiledStatefulContract_Upgrade's subtests should call t.Parallel (tparallel)
t.Parallel()

testCases := map[string]struct {
env *stubPrecompileEnvironment
input []byte
cRet []byte
cRemainingGas uint64
cErr error
wantRet []byte
wantErr string
wantEnv *stubPrecompileEnvironment
}{
"call_error": {
env: &stubPrecompileEnvironment{
gasToReturn: 10,
},
input: []byte{1},
cRet: []byte{2},
cRemainingGas: 6,
cErr: errors.New("test error"),
wantRet: []byte{2},
wantErr: "test error",
wantEnv: &stubPrecompileEnvironment{
gasToReturn: 10,
gasUsed: 4,
},
},
"remaining_gas_exceeds_supplied_gas": {
env: &stubPrecompileEnvironment{
gasToReturn: 10,
},
input: []byte{1},
cRet: []byte{2},
cRemainingGas: 11,
wantErr: "remaining gas 11 exceeds supplied gas 10",
wantEnv: &stubPrecompileEnvironment{
gasToReturn: 10,
gasUsed: 0,
},
},
"zero_remaining_gas": {
env: &stubPrecompileEnvironment{
gasToReturn: 10,
},
input: []byte{1},
cRet: []byte{2},
wantRet: []byte{2},
wantEnv: &stubPrecompileEnvironment{
gasToReturn: 10,
gasUsed: 10,
},
},
"used_one_gas": {
env: &stubPrecompileEnvironment{
gasToReturn: 10,
},
input: []byte{1},
cRet: []byte{2},
cRemainingGas: 9,
wantRet: []byte{2},
wantEnv: &stubPrecompileEnvironment{
gasToReturn: 10,
gasUsed: 1,
},
},
}

for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
c := PrecompiledStatefulContract(func(env vm.PrecompileEnvironment, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
return testCase.cRet, testCase.cRemainingGas, testCase.cErr
})

upgraded := c.Upgrade()

ret, err := upgraded(testCase.env, testCase.input)
if testCase.wantErr == "" {
assert.NoError(t, err)

Check failure on line 89 in libevm/legacy/legacy_test.go

View workflow job for this annotation

GitHub Actions / lint

require-error: for error assertions use require (testifylint)
} else {
assert.EqualError(t, err, testCase.wantErr)

Check failure on line 91 in libevm/legacy/legacy_test.go

View workflow job for this annotation

GitHub Actions / lint

require-error: for error assertions use require (testifylint)
}
assert.Equal(t, testCase.wantRet, ret)
assert.Equal(t, testCase.wantEnv, testCase.env)
})
}
}
66 changes: 66 additions & 0 deletions libevm/legacy/stubs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2025 the libevm authors.
//
// The libevm additions to go-ethereum are free software: you can redistribute
// them and/or modify them under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// The libevm additions are distributed in the hope that they will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see
// <http://www.gnu.org/licenses/>.

// Package legacy provides converters between legacy types and their refactored
// equivalents.

package legacy

import (
"math/big"

"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/core/types"
"github.com/ava-labs/libevm/core/vm"
"github.com/ava-labs/libevm/libevm"
"github.com/ava-labs/libevm/params"
"github.com/holiman/uint256"
)

var _ vm.PrecompileEnvironment = (*stubPrecompileEnvironment)(nil)

// stubPrecompileEnvironment implements [vm.PrecompileEnvironment] for testing.
type stubPrecompileEnvironment struct {
gasToReturn uint64
gasUsed uint64
}

// Gas returns the gas supplied to the precompile.
func (s *stubPrecompileEnvironment) Gas() uint64 {
return s.gasToReturn
}

// UseGas records the gas used by the precompile.
func (s *stubPrecompileEnvironment) UseGas(gas uint64) bool {
s.gasUsed += gas
return true
}

func (s *stubPrecompileEnvironment) Call(addr common.Address, input []byte, gas uint64, value *uint256.Int, _ ...vm.CallOption) (ret []byte, _ error) {
return nil, nil
}

func (s *stubPrecompileEnvironment) ChainConfig() *params.ChainConfig { return nil }
func (s *stubPrecompileEnvironment) Rules() params.Rules { return params.Rules{} }
func (s *stubPrecompileEnvironment) StateDB() vm.StateDB { return nil }
func (s *stubPrecompileEnvironment) ReadOnlyState() libevm.StateReader { return nil }
func (s *stubPrecompileEnvironment) IncomingCallType() vm.CallType { return vm.Call }
func (s *stubPrecompileEnvironment) Addresses() *libevm.AddressContext { return nil }
func (s *stubPrecompileEnvironment) ReadOnly() bool { return false }
func (s *stubPrecompileEnvironment) Value() *uint256.Int { return nil }
func (s *stubPrecompileEnvironment) BlockHeader() (h types.Header, err error) { return h, nil }
func (s *stubPrecompileEnvironment) BlockNumber() *big.Int { return nil }
func (s *stubPrecompileEnvironment) BlockTime() uint64 { return 0 }

0 comments on commit c130fa0

Please sign in to comment.