Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

go_test_short:
env:
FLAKY_REGEX: "ava-labs/libevm/(triedb/pathdb|eth|eth/tracers/js|eth/tracers/logger|accounts/abi/bind|accounts/keystore|eth/downloader|miner|ethclient|ethclient/gethclient|eth/catalyst)$"
FLAKY_REGEX: "ava-labs/libevm/(triedb/pathdb|eth|eth/tracers/js|eth/tracers/logger|eth/tracers/internal/tracetest|accounts/abi/bind|accounts/keystore|eth/downloader|miner|ethclient|ethclient/gethclient|eth/catalyst)$"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
16 changes: 15 additions & 1 deletion core/state_transition.libevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,24 @@

package core

import (
"github.com/ava-labs/libevm/log"
)

// canExecuteTransaction is a convenience wrapper for calling the
// [params.RulesHooks.CanExecuteTransaction] hook.
func (st *StateTransition) canExecuteTransaction() error {
bCtx := st.evm.Context
rules := st.evm.ChainConfig().Rules(bCtx.BlockNumber, bCtx.Random != nil, bCtx.Time)
return rules.Hooks().CanExecuteTransaction(st.msg.From, st.msg.To, st.state)
if err := rules.Hooks().CanExecuteTransaction(st.msg.From, st.msg.To, st.state); err != nil {
log.Debug(
"Transaction execution blocked by libevm hook",
"from", st.msg.From,
"to", st.msg.To,
"hooks", log.TypeOf(rules.Hooks()),
"reason", err,
)
return err
}
return nil
}
7 changes: 7 additions & 0 deletions core/types/rlp_payload.libevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/ava-labs/libevm/libevm/pseudo"
"github.com/ava-labs/libevm/libevm/register"
"github.com/ava-labs/libevm/libevm/testonly"
"github.com/ava-labs/libevm/log"
"github.com/ava-labs/libevm/rlp"
)

Expand Down Expand Up @@ -84,6 +85,12 @@ func RegisterExtras[
newStateAccount: pseudo.NewConstructor[SA]().Zero,
hooks: extra,
})
log.Info(
"Registered core/types extras",
"Header", log.TypeOf(pseudo.Zero[HPtr]().Value.Get()),
"Block/Body", log.TypeOf(pseudo.Zero[BPtr]().Value.Get()),
"StateAccount", log.TypeOf(pseudo.Zero[SA]().Value.Get()),
)
return extra
}

Expand Down
5 changes: 1 addition & 4 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,7 @@ func init() {
}

// ActivePrecompiles returns the precompiles enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) (active []common.Address) {
defer func() {
active = rules.Hooks().ActivePrecompiles(append([]common.Address{}, active...))
}()
func activePrecompiles(rules params.Rules) []common.Address {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than not being exported, this is now identical to the geth@v1.13.14 implementation.

switch {
case rules.IsCancun:
return PrecompiledAddressesCancun
Expand Down
29 changes: 29 additions & 0 deletions core/vm/contracts.libevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,42 @@ import (
"math/big"

"github.com/holiman/uint256"
"golang.org/x/exp/slog"

"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/core/types"
"github.com/ava-labs/libevm/libevm"
"github.com/ava-labs/libevm/libevm/set"
"github.com/ava-labs/libevm/log"
"github.com/ava-labs/libevm/params"
)

// ActivePrecompiles returns the precompiles enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) []common.Address {
orig := activePrecompiles(rules) // original, upstream implementation
active := rules.Hooks().ActivePrecompiles(append([]common.Address{}, orig...))

// As all set computation is done lazily and only when debugging, there is
// some duplication in favour of simplified code.
log.Debug(
"Overriding active precompiles",
"added", log.Lazy(func() slog.Value {
diff := set.From(active...).Sub(set.From(orig...))
return slog.AnyValue(diff.Slice())
}),
"removed", log.Lazy(func() slog.Value {
diff := set.From(orig...).Sub(set.From(active...))
return slog.AnyValue(diff.Slice())
}),
"unchanged", log.Lazy(func() slog.Value {
both := set.From(active...).Intersect(set.From(orig...))
return slog.AnyValue(both.Slice())
}),
)

return active
}

// evmCallArgs mirrors the parameters of the [EVM] methods Call(), CallCode(),
// DelegateCall() and StaticCall(). Its fields are identical to those of the
// parameters, prepended with the receiver name and call type. As
Expand Down
6 changes: 3 additions & 3 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/core/types"
"github.com/ava-labs/libevm/crypto"
"github.com/ava-labs/libevm/libevm"
"github.com/ava-labs/libevm/log"
"github.com/ava-labs/libevm/params"
"github.com/holiman/uint256"
)
Expand All @@ -40,6 +40,7 @@ type (

func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
if p, override := evm.chainRules.Hooks().PrecompileOverride(addr); override {
log.Debug("Overriding precompile", "address", addr, "implementation", log.TypeOf(p))
return p, p != nil
}
var precompiles map[common.Address]PrecompiledContract
Expand Down Expand Up @@ -459,8 +460,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// This check MUST be placed after the caller's nonce is incremented but
// before all other state-modifying behaviour, even if changes may be
// reverted to the snapshot.
addrs := &libevm.AddressContext{Origin: evm.Origin, Caller: caller.Address(), Self: address}
gas, err := evm.chainRules.Hooks().CanCreateContract(addrs, gas, evm.StateDB)
gas, err := evm.canCreateContract(caller, address, gas)
if err != nil {
return nil, common.Address{}, gas, err
}
Expand Down
45 changes: 45 additions & 0 deletions core/vm/evm.libevm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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 vm

import (
"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/libevm"
"github.com/ava-labs/libevm/log"
)

// canCreateContract is a convenience wrapper for calling the
// [params.RulesHooks.CanCreateContract] hook.
func (evm *EVM) canCreateContract(caller ContractRef, contractToCreate common.Address, gas uint64) (remainingGas uint64, _ error) {
addrs := &libevm.AddressContext{Origin: evm.Origin, Caller: caller.Address(), Self: contractToCreate}
gas, err := evm.chainRules.Hooks().CanCreateContract(addrs, gas, evm.StateDB)

// NOTE that this block only performs logging and that all paths propagate
// `(gas, err)` unmodified.
if err != nil {
log.Debug(
"Contract creation blocked by libevm hook",
"origin", addrs.Origin,
"caller", addrs.Caller,
"contract", addrs.Self,
"hooks", log.TypeOf(evm.chainRules.Hooks()),
"reason", err,
)
}

return gas, err
}
59 changes: 59 additions & 0 deletions libevm/set/set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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 set provides a generic implementation of a set.
package set

// A Set is a generic set implementation.
type Set[T comparable] map[T]struct{}

// From returns a Set containing the elements.
func From[T comparable](elements ...T) Set[T] {
s := make(Set[T], len(elements))
for _, e := range elements {
s[e] = struct{}{}
}
return s
}

// Sub returns the elements in `s` that aren't in `t`.
func (s Set[T]) Sub(t Set[T]) Set[T] {
return s.alsoIn(t, false)
}

// Intersect returns the intersection of `s` and `t`.
func (s Set[T]) Intersect(t Set[T]) Set[T] {
return s.alsoIn(t, true)
}

func (s Set[T]) alsoIn(t Set[T], inBoth bool) Set[T] {
res := make(Set[T])
for el := range s {
if _, ok := t[el]; ok == inBoth {
res[el] = struct{}{}
}
}
return res
}

// Slice returns the elements of `s` as a slice.
func (s Set[T]) Slice() []T {
sl := make([]T, 0, len(s))
for el := range s {
sl = append(sl, el)
}
return sl
}
56 changes: 56 additions & 0 deletions libevm/set/set_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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 set

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestSub(t *testing.T) {
for _, tt := range [][3][]int{ // start, sub, want
{{}, {}, {}},
{{0}, {}, {0}},
{{}, {0}, {}},
{{0, 1}, {0}, {1}},
{{0, 1}, {1}, {0}},
} {
in, sub := tt[0], tt[1]
want := tt[2]
got := From(in...).Sub(From(sub...)).Slice()
assert.Equalf(t, want, got, "Set(%v).Sub(%v)", in, sub)
}
}

func TestIntersect(t *testing.T) {
for _, tt := range [][3][]int{ // L, R, intersection
{{}, {}, {}},
{{0}, {}, {}},
{{0}, {0}, {0}},
{{0, 1}, {0}, {0}},
{{0, 1}, {1}, {1}},
} {
want := tt[2]

for i := 0; i <= 1; i++ { // commutativity
lhs, rhs := tt[i], tt[1-i]
got := From(lhs...).Intersect(From(rhs...)).Slice()
assert.Equalf(t, want, got, "Set(%v).Intersect(%v)", lhs, rhs)
}
}
}
41 changes: 41 additions & 0 deletions log/value.libevm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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 log

import (
"fmt"

"golang.org/x/exp/slog"
)

// A Lazy function defers its execution until logging is performed.
type Lazy func() slog.Value

var _ slog.LogValuer = Lazy(nil)

// LogValue implements the [slog.LogValuer] interface.
func (l Lazy) LogValue() slog.Value {
return l()
}

// TypeOf returns a Lazy function that reports the concrete type of `v` as
// determined with the `%T` [fmt] verb.
func TypeOf(v any) Lazy {
return Lazy(func() slog.Value {
return slog.StringValue(fmt.Sprintf("%T", v))
})
}
Loading