diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 701fe6b4cd2..33d927de198 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -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
@@ -43,6 +43,8 @@ jobs:
defaults:
run:
working-directory: ./libevm/tooling
+ env:
+ TARGET_BRANCH: ${{ github.event_name == 'pull_request' && github.base_ref || github.ref }}
steps:
- uses: actions/checkout@v4
with:
@@ -51,7 +53,8 @@ jobs:
uses: actions/setup-go@v5
with:
go-version-file: "./libevm/tooling/go.mod"
- - run: go test ./...
+ - run: git branch main origin/main
+ - run: go test -v ./... --target_branch="${{ env.TARGET_BRANCH }}"
go_generate:
env:
diff --git a/.github/workflows/rename-module.yml b/.github/workflows/rename-module.yml
index e7d356eca4c..3a604a0270f 100644
--- a/.github/workflows/rename-module.yml
+++ b/.github/workflows/rename-module.yml
@@ -3,11 +3,15 @@ name: Rename Go module
on:
workflow_dispatch:
inputs:
- source_commit:
- description: "Upstream commit on which to base module renaming"
+ source:
+ description: "Reference or commit on which to base module renaming"
required: true
type: string
- default: "2bd6bd01d2e8561dd7fc21b631f4a34ac16627a1"
+ default: "main"
+ branch:
+ description: "Branch to which a commit of the changes is pushed; leave blank for auto-naming. If non-existent, the branch is created."
+ type: string
+ default: ""
jobs:
rename-module:
@@ -17,71 +21,97 @@ jobs:
with:
fetch-depth: 0 # everything
+ - run: git fetch --tags https://github.com/ethereum/go-ethereum.git
+
+ - run: git checkout ${{ inputs.source }}
+
+ - name: References pointing to source
+ # NOTE: This step assumes that the source has been checked out, which
+ # might not hold if reordered.
+ run: |
+ git branch --points-at HEAD;
+ git tag --points-at HEAD;
+
+ - name: Set up Go
+ uses: actions/setup-go@v5
+ with:
+ go-version-file: "go.mod"
+
+ - name: Detect Go module
+ id: go
+ run: |
+ echo "MODULE=$(go list -m)" >> "$GITHUB_OUTPUT";
+ echo "MODULE_SUFFIX=$(go list -m | cut -b 12-)" >> "$GITHUB_OUTPUT"; # Strip github.com/
+
+ - name: Validate Go module
+ if: ${{ steps.go.outputs.MODULE != 'github.com/ava-labs/libevm' && steps.go.outputs.MODULE != 'github.com/ethereum/go-ethereum' }}
+ run: echo "Unexpected Go module ${{ steps.go.outputs.MODULE }}" && exit 1;
+
- name: Set variables
id: vars
- # Including hashes of both the source commit and the workflow file makes
- # this idempotent.
env:
- WORKFLOW_HASH: ${{ hashFiles('.github/workflows/rename-module.yml') }}
+ # `cond && ifTrue || ifFalse` is effectively a ternary operator, based on short-circuiting Boolean logic (assumes `ifTrue` is truthy)
+ RENAME_TO: ${{ steps.go.outputs.MODULE_SUFFIX == 'ava-labs/libevm' && 'ethereum/go-ethereum' || 'ava-labs/libevm' }}
run: |
+ echo "RENAME_FROM=${{ steps.go.outputs.MODULE_SUFFIX}}" >> "$GITHUB_OUTPUT";
+ echo "RENAME_TO=${RENAME_TO}" >> "$GITHUB_OUTPUT";
echo "WORKFLOW_HASH=${WORKFLOW_HASH}" >> "$GITHUB_OUTPUT";
- echo "DEST_BRANCH=auto-rename-module_source-${{ inputs.source_commit }}_workflow-${WORKFLOW_HASH}-${{ github.ref_name }}" \
+ echo "SOURCE_COMMIT=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT";
+ echo "AUTO_BRANCH_NAME=auto/rename-module/to=${RENAME_TO}/src=$(git rev-parse HEAD)/workflow_sha=${{ github.workflow_sha }}/run=${{ github.run_id }}" \
>> "$GITHUB_OUTPUT";
- - name: Fetch tags from ethereum/go-ethereum
- run: git fetch --tags https://github.com/ethereum/go-ethereum.git
-
- - name: Tags pointing to source commit
- run: git tag --points-at ${{ inputs.source_commit }}
-
- - name: Check out source commit
- run: git checkout ${{ inputs.source_commit }}
-
- - name: Globally update module name
+ - name: Globally rename module from ${{ steps.vars.outputs.RENAME_FROM }} to ${{ steps.vars.outputs.RENAME_TO }}
run: |
- go mod edit -module github.com/ava-labs/libevm;
+ go mod edit -module github.com/${{ steps.vars.outputs.RENAME_TO }};
find . \
-iname '*.go' \
-o -iname '*.txt' \
-o -iname '*.go.tpl' \
- -o -iname '*.proto' | xargs \
- sed -i -E 's|(["`]github\.com/)ethereum/go-ethereum|\1ava-labs/libevm|g';
+ -o -iname '*.proto' \
+ -not -wholename '*/libevm/tooling/*' | xargs \
+ sed -i -E 's|(["`]github\.com/)${{ steps.vars.outputs.RENAME_FROM }}|\1${{ steps.vars.outputs.RENAME_TO }}|g';
- name: Remnant references
run: |
find . -type f | \
- xargs grep -In github.com/ethereum/go-ethereum | \
- grep -v "https://github.com/ethereum/go-ethereum"
-
- - name: Set up Go
- uses: actions/setup-go@v5
- with:
- go-version-file: "go.mod"
+ xargs grep -In github.com/${{ steps.vars.outputs.RENAME_FROM }} | \
+ grep -v "https://github.com/${{ steps.vars.outputs.RENAME_FROM }}"
- name: Smoke tests
- # `go list` shows us the module name and grep will non-zero exit on mismatch
+ # `go list -m` shows us the module name and grep will non-zero exit on mismatch
# `go build` is a rudimentary but broad test of correctness
# The explicitly tested packages are edge cases:
# - bind generates tests and a go.mod on the fly
# - rlpgen has testdata with imports that need updating
run: |
- go list . | grep ava-labs/libevm;
+ go list -m | grep github.com/${{ steps.vars.outputs.RENAME_TO }};
go build ./...;
go test ./accounts/abi/bind ./rlp/rlpgen
- - name: Create new branch
+ - name: Set branch name
+ id: branch
env:
- BRANCH: ${{ steps.vars.outputs.DEST_BRANCH }}
+ BRANCH: ${{ inputs.branch || steps.vars.outputs.AUTO_BRANCH_NAME }}
+ run: echo "NAME=${BRANCH}" >> "$GITHUB_OUTPUT";
+
+ - name: Check out branch (create if non-existent)
+ env:
+ BRANCH: ${{ steps.branch.outputs.NAME }}
run: |
- git checkout -b "${BRANCH}";
- git push origin "${BRANCH}";
+ git checkout "${BRANCH}" 2>/dev/null || \
+ (git checkout -b "${BRANCH}" && git push origin "${BRANCH}");
- - name: Commit to new branch
+ - name: Commit to branch
uses: planetscale/ghcommit-action@d4176bfacef926cc2db351eab20398dfc2f593b5 # v0.2.0
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
with:
# WARNING: mirror any change to the commit_message value below in libevm-delta.yml
- commit_message: "[AUTO] rename Go module + update internal import paths\n\nWorkflow: ${{ steps.vars.outputs.WORKFLOW_HASH }} on branch ${{ github.ref_name }}"
+ commit_message: |
+ [AUTO] rename Go module to ${{ steps.vars.outputs.RENAME_TO }}
+
+ Source: ${{ steps.vars.outputs.SOURCE_COMMIT }} (${{ inputs.source }})
+ Workflow: ${{ github.workflow_sha }} (${{ github.workflow_ref }})
+ Run ID: ${{ github.run_id }}
repo: ${{ github.repository }}
- branch: ${{ steps.vars.outputs.DEST_BRANCH }}
+ branch: ${{ steps.branch.outputs.NAME }}
diff --git a/core/state_transition.libevm.go b/core/state_transition.libevm.go
index 49e509d5637..701cc4d5ee7 100644
--- a/core/state_transition.libevm.go
+++ b/core/state_transition.libevm.go
@@ -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
}
diff --git a/core/types/rlp_payload.libevm.go b/core/types/rlp_payload.libevm.go
index 98aebe1cc4b..ff3530d1692 100644
--- a/core/types/rlp_payload.libevm.go
+++ b/core/types/rlp_payload.libevm.go
@@ -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"
)
@@ -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
}
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index a869debebba..ff1f3a0ca79 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -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 {
switch {
case rules.IsCancun:
return PrecompiledAddressesCancun
diff --git a/core/vm/contracts.libevm.go b/core/vm/contracts.libevm.go
index 66e3c91783a..12271874602 100644
--- a/core/vm/contracts.libevm.go
+++ b/core/vm/contracts.libevm.go
@@ -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
diff --git a/core/vm/evm.go b/core/vm/evm.go
index ae56d5a69ed..ca3f5d21037 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -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"
)
@@ -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
@@ -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
}
diff --git a/core/vm/evm.libevm.go b/core/vm/evm.libevm.go
new file mode 100644
index 00000000000..48278c28c37
--- /dev/null
+++ b/core/vm/evm.libevm.go
@@ -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
+// .
+
+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
+}
diff --git a/libevm/set/set.go b/libevm/set/set.go
new file mode 100644
index 00000000000..4f055434e19
--- /dev/null
+++ b/libevm/set/set.go
@@ -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
+// .
+
+// 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
+}
diff --git a/libevm/set/set_test.go b/libevm/set/set_test.go
new file mode 100644
index 00000000000..888dbbe3d0e
--- /dev/null
+++ b/libevm/set/set_test.go
@@ -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
+// .
+
+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)
+ }
+ }
+}
diff --git a/libevm/tooling/go.mod b/libevm/tooling/go.mod
index 05c4f92d52d..a0edc3e00ae 100644
--- a/libevm/tooling/go.mod
+++ b/libevm/tooling/go.mod
@@ -1,37 +1,40 @@
module github.com/ava-labs/libevm/libevm/tooling
-go 1.23
+go 1.23.0
+
+replace github.com/ava-labs/libevm => ../../
require (
- github.com/go-git/go-git/v5 v5.13.2
- github.com/google/go-cmp v0.6.0
+ github.com/ava-labs/libevm v0.0.0-00010101000000-000000000000
+ github.com/go-git/go-git/v5 v5.14.0
+ github.com/google/go-cmp v0.7.0
github.com/stretchr/testify v1.10.0
)
require (
dario.cat/mergo v1.0.0 // indirect
- github.com/Microsoft/go-winio v0.6.1 // indirect
+ github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.1.5 // indirect
- github.com/cloudflare/circl v1.3.7 // indirect
- github.com/cyphar/filepath-securejoin v0.3.6 // indirect
+ github.com/cloudflare/circl v1.6.0 // indirect
+ github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.6.2 // indirect
- github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+ github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
+ github.com/holiman/uint256 v1.2.4 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
- github.com/skeema/knownhosts v1.3.0 // indirect
+ github.com/skeema/knownhosts v1.3.1 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
- golang.org/x/crypto v0.32.0 // indirect
- golang.org/x/mod v0.17.0 // indirect
- golang.org/x/net v0.34.0 // indirect
+ golang.org/x/crypto v0.35.0 // indirect
+ golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
+ golang.org/x/net v0.35.0 // indirect
golang.org/x/sync v0.10.0 // indirect
- golang.org/x/sys v0.29.0 // indirect
- golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
+ golang.org/x/sys v0.30.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/libevm/tooling/go.sum b/libevm/tooling/go.sum
index e4eba040730..5c5b9eb6a50 100644
--- a/libevm/tooling/go.sum
+++ b/libevm/tooling/go.sum
@@ -1,25 +1,67 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
+github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
-github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
-github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
+github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
+github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
+github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
+github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
+github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
-github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
-github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
-github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88=
+github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
+github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
+github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
+github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
+github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y=
+github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac=
+github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
+github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
+github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A=
+github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo=
+github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw=
+github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
+github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM=
+github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ=
+github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
+github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
+github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
+github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
+github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
+github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
+github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ=
+github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
+github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA=
+github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc=
+github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
+github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
-github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ=
+github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI=
+github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
+github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
+github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
+github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY=
+github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
+github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE=
+github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
@@ -28,16 +70,34 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
-github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
-github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
-github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60=
+github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k=
+github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
+github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
+github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
+github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
+github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
+github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
+github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
+github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
+github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
+github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -45,6 +105,14 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
+github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
+github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
@@ -53,30 +121,50 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg=
+github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y=
+github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
+github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
+github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
+github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
+github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
+github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
+github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
-github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
+github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
+github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
+github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
+github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
+github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
+github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
+github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
+github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
+github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
-golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
+golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
+golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
+golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
-golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
+golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
+golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -85,17 +173,17 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
-golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
-golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
+golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
+golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@@ -106,3 +194,5 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
+rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
diff --git a/libevm/tooling/release/cherrypicks b/libevm/tooling/release/cherrypicks
index 9b416f01d4e..58eeb1b0287 100644
--- a/libevm/tooling/release/cherrypicks
+++ b/libevm/tooling/release/cherrypicks
@@ -11,6 +11,5 @@
69f815f6f5791e0e48160bdad284773d0ffb1ba9 # params: print time value instead of pointer in ConfigCompatError (#29514)
e4b8058d5a5832cdebdac7da385cf6d829c0d433 # eth/gasprice: add query limit for FeeHistory to defend DDOS attack (#29644)
34b46a2f756da71595ac84eb7f25441f2a5b6ebb # core/state/snapshot: add a missing lock (#30001)
-e4675771eda550e7eeb63a8884816982c1980644 # internal/debug: remove memsize (#30253)
159fb1a1db551c544978dc16a5568a4730b4abf3 # crypto: add IsOnCurve check (#31100)
da71839a270a353bac92e3108e4b74fb0eefec29 # internal/ethapi: fix panic in debug methods (#31157)
diff --git a/libevm/tooling/release/release_test.go b/libevm/tooling/release/release_test.go
index 10aba8613cf..79c54507616 100644
--- a/libevm/tooling/release/release_test.go
+++ b/libevm/tooling/release/release_test.go
@@ -18,36 +18,46 @@ package release
import (
"errors"
+ "flag"
"fmt"
+ "os"
+ "path/filepath"
"regexp"
+ "slices"
"sort"
"strings"
"testing"
+ "time"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/google/go-cmp/cmp"
+ "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "github.com/ava-labs/libevm/params"
+
_ "embed"
)
+func TestMain(m *testing.M) {
+ flag.Parse()
+ os.Exit(m.Run())
+}
+
var (
//go:embed cherrypicks
cherryPicks string
lineFormatRE = regexp.MustCompile(`^([a-fA-F0-9]{40}) # (.*)$`)
)
-func TestCherryPicksFormat(t *testing.T) {
- type parsedLine struct {
- hash, commitMsg string
- }
- var (
- rawLines []string
- lines []parsedLine
- )
+type parsedLine struct {
+ hash, commitMsg string
+}
+func parseCherryPicks(t *testing.T) (rawLines []string, lines []parsedLine) {
+ t.Helper()
for i, line := range strings.Split(cherryPicks, "\n") {
if line == "" || strings.HasPrefix(line, "#") {
continue
@@ -65,27 +75,21 @@ func TestCherryPicksFormat(t *testing.T) {
t.Errorf("Line %d is improperly formatted: %s", i, line)
}
}
+ return rawLines, lines
+}
+
+func TestCherryPicksFormat(t *testing.T) {
+ rawLines, lines := parseCherryPicks(t)
if t.Failed() {
t.Fatalf("Required line regexp: %s", lineFormatRE.String())
}
- opts := &git.PlainOpenOptions{DetectDotGit: true}
- repo, err := git.PlainOpenWithOptions("./", opts)
- require.NoErrorf(t, err, "git.PlainOpenWithOptions(./, %+v", opts)
-
- fetch := &git.FetchOptions{
- RemoteURL: "https://github.com/ethereum/go-ethereum.git",
- }
- err = repo.Fetch(fetch)
- if err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) {
- t.Fatalf("%T.Fetch(%+v) error %v", repo, fetch, err)
- }
-
commits := make([]struct {
obj *object.Commit
line parsedLine
}, len(lines))
+ repo := openGitRepo(t)
for i, line := range lines {
obj, err := repo.CommitObject(plumbing.NewHash(line.hash))
require.NoErrorf(t, err, "%T.CommitObject(%q)", repo, line.hash)
@@ -111,3 +115,252 @@ func TestCherryPicksFormat(t *testing.T) {
t.Logf("To fix, copy:\n%s", strings.Join(want, "\n"))
}
}
+
+const (
+ defaultBranch = "main"
+ releaseBranchPrefix = "release/"
+)
+
+var triggerOrPRTargetBranch = flag.String(
+ "target_branch",
+ defaultBranch,
+ "Target branch if triggered by a PR (github.base_ref), otherwise triggering branch (github.ref)",
+)
+
+func TestBranchProperties(t *testing.T) {
+ branch := strings.TrimPrefix(*triggerOrPRTargetBranch, "refs/heads/")
+
+ switch {
+ case branch == defaultBranch:
+ if rt := params.LibEVMReleaseType; rt.ForReleaseBranch() {
+ t.Errorf("On default branch; params.LibEVMReleaseType = %q, which is reserved for release branches", rt)
+ }
+
+ case strings.HasPrefix(branch, releaseBranchPrefix):
+ testReleaseBranch(t, branch)
+
+ default:
+ t.Logf("Branch %q is neither default nor release branch", branch)
+ }
+}
+
+// testReleaseBranch asserts invariant properties of release branches:
+//
+// 1. They are named release/v${libevm-version};
+// 2. The libevm version's [params.ReleaseType] is appropriate for a release
+// branch; and
+// 3. The commit history is a "linear fork" off the default branch, with only
+// certain allowable commits.
+//
+// We define a "linear fork" as there being a single ancestral commit at which
+// the release branch diverged from the default branch, with no merge commits
+// after this divergence:
+//
+// ______________ main
+// \___ release/*
+//
+// The commits in the release branch that are not in the default branch MUST be:
+//
+// 1. The cherry-pick commits embedded as [cherryPicks], in order; then
+// 2. A single, final commit to change the libevm version.
+//
+// testReleaseBranch assumes that the git HEAD currently points at either
+// `targetBranch` itself, or at a candidate (i.e. PR source) for said branch.
+func testReleaseBranch(t *testing.T, targetBranch string) {
+ t.Run("branch_name", func(t *testing.T) {
+ want := fmt.Sprintf("%sv%s", releaseBranchPrefix, params.LibEVMVersion) // prefix already includes /
+ assert.Equal(t, want, targetBranch)
+
+ if rt := params.LibEVMReleaseType; !rt.ForReleaseBranch() {
+ t.Errorf("On release branch; params.LibEVMReleaseType = %q, which is unsuitable for release branches", rt)
+ }
+ })
+
+ t.Run("commit_history", func(t *testing.T) {
+ repo := openGitRepo(t)
+ headRef, err := repo.Head()
+ require.NoErrorf(t, err, "%T.Head()", repo)
+
+ head := commitFromRef(t, repo, headRef)
+ main := commitFromBranchName(t, repo, defaultBranch)
+
+ closestCommonAncestors, err := head.MergeBase(main)
+ require.NoError(t, err)
+ require.Lenf(t, closestCommonAncestors, 1, `number of "best common ancestors" of HEAD (%v) and %q (%v)`, head.Hash, defaultBranch, main.Hash)
+ // Not to be confused with the GitHub concept of a (repo) fork.
+ fork := closestCommonAncestors[0]
+ t.Logf("Forked from %q at commit %v (%s)", defaultBranch, fork.Hash, commitMsgFirstLine(fork))
+
+ history, err := repo.Log(&git.LogOptions{
+ Order: git.LogOrderDFS,
+ })
+ require.NoErrorf(t, err, "%T.Log()", repo)
+ newCommits := linearCommitsSince(t, history, fork)
+ logCommits(t, "History since fork from default branch", newCommits)
+
+ t.Run("cherry_picked_commits", func(t *testing.T) {
+ _, cherryPick := parseCherryPicks(t)
+ wantCommits := commitsFromHashes(t, repo, cherryPick, fork)
+ logCommits(t, "Expected cherry-picks", wantCommits)
+ require.Len(t, newCommits, len(wantCommits)+1, "Commits since fork from default branch MUST be number cherry-picked plus one")
+
+ opt := compareCherryPickedCommits()
+ if diff := cmp.Diff(wantCommits, newCommits[:len(wantCommits)], opt); diff != "" {
+ t.Fatalf("Cherry-picked commits for release branch (-want +got):\n%s", diff)
+ }
+ })
+
+ t.Run("final_commit", func(t *testing.T) {
+ n := len(newCommits)
+ last, penultimate := newCommits[n-1], newCommits[n-2]
+ lastCommitDiffs, err := object.DiffTree(
+ treeFromCommit(t, last),
+ treeFromCommit(t, penultimate),
+ )
+ require.NoErrorf(t, err, "object.DiffTree(commits = [%v, %v])", last.Hash, penultimate.Hash)
+
+ allowedFileModifications := map[string]struct{}{
+ "version.libevm.go": {},
+ "version.libevm_test.go": {},
+ }
+ for _, name := range changedFilesByName(t, lastCommitDiffs) {
+ if _, ok := allowedFileModifications[name]; !ok {
+ t.Errorf("Last commit on release branch modified disallowed file %q", name)
+ }
+ }
+ })
+ })
+}
+
+func openGitRepo(t *testing.T) *git.Repository {
+ t.Helper()
+
+ opts := &git.PlainOpenOptions{DetectDotGit: true}
+ repo, err := git.PlainOpenWithOptions("./", opts)
+ require.NoErrorf(t, err, "git.PlainOpenWithOptions(./, %+v", opts)
+
+ fetch := &git.FetchOptions{
+ RemoteURL: "https://github.com/ethereum/go-ethereum.git",
+ }
+ err = repo.Fetch(fetch)
+ if err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) {
+ t.Fatalf("%T.Fetch(%+v) error %v", repo, fetch, err)
+ }
+
+ return repo
+}
+
+func commitFromRef(t *testing.T, repo *git.Repository, ref *plumbing.Reference) *object.Commit {
+ t.Helper()
+ c, err := repo.CommitObject(ref.Hash())
+ require.NoErrorf(t, err, "%T.CommitObject(%v)", repo, ref.Hash())
+ return c
+}
+
+func commitFromBranchName(t *testing.T, repo *git.Repository, name string) *object.Commit {
+ t.Helper()
+
+ branch, err := repo.Branch(name)
+ require.NoErrorf(t, err, "%T.Branch(%q)", repo, name)
+ ref, err := repo.Reference(branch.Merge, false)
+ require.NoErrorf(t, err, "%T.Reference(%v)", repo, branch.Merge)
+ return commitFromRef(t, repo, ref)
+}
+
+func linearCommitsSince(t *testing.T, iter object.CommitIter, since *object.Commit) []*object.Commit {
+ t.Helper()
+
+ var commits []*object.Commit
+ errReachedSince := fmt.Errorf("%T reached terminal commit %v", iter, since)
+
+ err := iter.ForEach(func(c *object.Commit) error {
+ if c.Hash == since.Hash {
+ return errReachedSince
+ }
+ if n := len(c.ParentHashes); false && n != 1 {
+ return fmt.Errorf("Non-linear history; commit %v has %d parents", c.Hash, n)
+ }
+ commits = append(commits, c)
+ return nil
+ })
+ require.ErrorIs(t, err, errReachedSince)
+
+ slices.Reverse(commits)
+ return commits
+}
+
+func commitsFromHashes(t *testing.T, repo *git.Repository, lines []parsedLine, skipAncestorsOf *object.Commit) []*object.Commit {
+ t.Helper()
+
+ var commits []*object.Commit
+ for _, l := range lines {
+ c, err := repo.CommitObject(plumbing.NewHash(l.hash))
+ require.NoError(t, err)
+
+ skip, err := c.IsAncestor(skipAncestorsOf)
+ require.NoError(t, err)
+ if skip || c.Hash == skipAncestorsOf.Hash {
+ continue
+ }
+ commits = append(commits, c)
+ }
+
+ return commits
+}
+
+func commitMsgFirstLine(c *object.Commit) string {
+ return strings.Split(c.Message, "\n")[0]
+}
+
+func logCommits(t *testing.T, header string, commits []*object.Commit) {
+ t.Logf("### %s (%d commits):", header, len(commits))
+ for _, c := range commits {
+ t.Logf("%s by %s", commitMsgFirstLine(c), c.Author.String())
+ }
+}
+
+// compareCherryPickedCommits returns a [cmp.Transformer] that converts
+// [object.Commit] instances into structs carrying only the pertinent commit
+// properties that remain stable when cherry-picked. Note, however, that this
+// does not include the actual diffs induced by cherry-picking.
+func compareCherryPickedCommits() cmp.Option {
+ type comparableCommit struct {
+ MessageFirstLine, Author string
+ Authored time.Time
+ }
+
+ return cmp.Transformer("gitCommit", func(c *object.Commit) comparableCommit {
+ return comparableCommit{
+ MessageFirstLine: commitMsgFirstLine(c),
+ Author: c.Author.String(),
+ Authored: c.Author.When,
+ }
+ })
+}
+
+func treeFromCommit(t *testing.T, c *object.Commit) *object.Tree {
+ t.Helper()
+ tree, err := c.Tree()
+ require.NoErrorf(t, err, "%T.Tree()", c)
+ return tree
+}
+
+func changedFilesByName(t *testing.T, changes object.Changes) []string {
+ t.Helper()
+
+ var files []string
+ for _, c := range changes {
+ from, to, err := c.Files()
+ require.NoErrorf(t, err, "%T.Files()", c)
+ require.NotNilf(t, from, "file %q inserted", to.Name)
+ require.NotNilf(t, to, "file %q deleted", from.Name)
+ require.Equalf(t, from.Name, to.Name, "file renamed; expect modified file's name to equal original")
+
+ // [object.File.Name] is documented as being either the name or a path,
+ // depending on how it was generated. We only need to protect against
+ // accidental changes to the wrong files, so it's sufficient to just
+ // check the names.
+ files = append(files, filepath.Base(from.Name))
+ }
+ return files
+}
diff --git a/log/value.libevm.go b/log/value.libevm.go
new file mode 100644
index 00000000000..8c4ab0aaf36
--- /dev/null
+++ b/log/value.libevm.go
@@ -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
+// .
+
+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))
+ })
+}
diff --git a/log/value.libevm_test.go b/log/value.libevm_test.go
new file mode 100644
index 00000000000..c8f15d46b30
--- /dev/null
+++ b/log/value.libevm_test.go
@@ -0,0 +1,67 @@
+// 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
+// .
+
+package log
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "golang.org/x/exp/slog"
+)
+
+func TestTypeOf(t *testing.T) {
+ type foo struct{}
+
+ tests := map[any]string{
+ nil: "",
+ int(0): "int",
+ int(1): "int",
+ uint(0): "uint",
+ foo{}: "log.foo",
+ (*foo)(nil): "*log.foo",
+ }
+
+ for in, want := range tests {
+ got := TypeOf(in).LogValue()
+ assert.Equalf(t, want, got.String(), "TypeOf(%T(%[1]v))", in, in)
+ }
+}
+
+func TestLazy(t *testing.T) {
+ const (
+ key = "theKey"
+ val = "theVal"
+ wantLogged = key + "=" + val
+ )
+
+ var gotNumEvaluations int
+ fn := Lazy(func() slog.Value {
+ gotNumEvaluations++
+ return slog.StringValue(val)
+ })
+
+ var out bytes.Buffer
+ log := slog.New(slog.NewTextHandler(&out, &slog.HandlerOptions{
+ Level: slog.LevelInfo,
+ }))
+ log.Info("", key, fn)
+ log.Debug("", "not evaluated", fn)
+
+ assert.Containsf(t, out.String(), wantLogged, "evaluation of %T function is logged", fn)
+ assert.Equalf(t, 1, gotNumEvaluations, "number of evaluations of %T function", fn)
+}
diff --git a/params/config.libevm.go b/params/config.libevm.go
index f8a153f3d98..127f5febef0 100644
--- a/params/config.libevm.go
+++ b/params/config.libevm.go
@@ -23,6 +23,7 @@ import (
"github.com/ava-labs/libevm/libevm/pseudo"
"github.com/ava-labs/libevm/libevm/register"
+ "github.com/ava-labs/libevm/log"
)
// Extras are arbitrary payloads to be added as extra fields in [ChainConfig]
@@ -79,6 +80,12 @@ func RegisterExtras[C ChainConfigHooks, R RulesHooks](e Extras[C, R]) ExtraPaylo
newForRules: e.newForRules,
payloads: payloads,
})
+ log.Info(
+ "Registered params extras",
+ "ChainConfig", log.TypeOf(pseudo.Zero[C]().Value.Get()),
+ "Rules", log.TypeOf(pseudo.Zero[R]().Value.Get()),
+ "ReuseJSONRoot", e.ReuseJSONRoot,
+ )
return payloads
}
diff --git a/params/version.libevm.go b/params/version.libevm.go
index 7187acffb11..8300af7449c 100644
--- a/params/version.libevm.go
+++ b/params/version.libevm.go
@@ -23,8 +23,8 @@ const (
LibEVMVersionMinor = 1
LibEVMVersionPatch = 0
- libEVMReleaseType releaseType = releaseCandidate
- libEVMReleaseCandidate uint = 3 // ignored unless [libEVMReleaseType] == [releaseCandidate]
+ LibEVMReleaseType ReleaseType = BetaRelease
+ libEVMReleaseCandidate uint = 3 // ignored unless [LibEVMReleaseType] == [ReleaseCandidate]
)
// LibEVMVersion holds the textual version string of `libevm` modifications.
@@ -54,7 +54,7 @@ var LibEVMVersion = func() string {
v := libEVMSemver{
geth: semverTriplet{VersionMajor, VersionMinor, VersionPatch},
libEVM: semverTriplet{LibEVMVersionMajor, LibEVMVersionMinor, LibEVMVersionPatch},
- typ: libEVMReleaseType,
+ typ: LibEVMReleaseType,
rc: libEVMReleaseCandidate,
}
return v.String()
@@ -68,26 +68,35 @@ func (t semverTriplet) String() string {
return fmt.Sprintf("%d.%d.%d", t.major, t.minor, t.patch)
}
-type releaseType string
+// A ReleaseType is a suffix for [LibEVMVersion].
+type ReleaseType string
const (
- // betaRelease MUST be used on `main` branch
- betaRelease = releaseType("beta")
- // Reserved for `release/*` branches
- releaseCandidate = releaseType("rc")
- productionRelease = releaseType("release")
+ // BetaRelease MUST be used on `main` branch.
+ BetaRelease = ReleaseType("beta")
+ // Reserved for `release/*` branches.
+ ReleaseCandidate = ReleaseType("rc")
+ ProductionRelease = ReleaseType("release")
)
+// ForReleaseBranch returns true i.f.f. `t` is suitable for use on a release
+// branch. The sets of [ReleaseType] values suitable for release vs default
+// branches is disjoint so the negation of the return value is equivalent to
+// "ForDefaultBranch".
+func (t ReleaseType) ForReleaseBranch() bool {
+ return t == ReleaseCandidate || t == ProductionRelease
+}
+
type libEVMSemver struct {
geth, libEVM semverTriplet
- typ releaseType
+ typ ReleaseType
rc uint
}
func (v libEVMSemver) String() string {
suffix := v.typ
- if suffix == releaseCandidate {
- suffix = releaseType(fmt.Sprintf("%s.%d", suffix, v.rc))
+ if suffix == ReleaseCandidate {
+ suffix = ReleaseType(fmt.Sprintf("%s.%d", suffix, v.rc))
}
return fmt.Sprintf("%s-%s.%s", v.geth, v.libEVM, suffix)
}
diff --git a/params/version.libevm_test.go b/params/version.libevm_test.go
index e154713fa8a..5a6acb01709 100644
--- a/params/version.libevm_test.go
+++ b/params/version.libevm_test.go
@@ -38,39 +38,39 @@ func TestLibEVMVersioning(t *testing.T) {
{
semverTriplet{1, 13, 14},
semverTriplet{0, 1, 0},
- betaRelease,
+ BetaRelease,
0, // ignored
},
{
semverTriplet{1, 13, 14},
semverTriplet{0, 1, 0},
- releaseCandidate, 1,
+ ReleaseCandidate, 1,
},
{
semverTriplet{1, 13, 14},
semverTriplet{0, 1, 0},
- releaseCandidate, 2,
+ ReleaseCandidate, 2,
},
{
semverTriplet{1, 13, 14},
semverTriplet{0, 1, 0},
- productionRelease,
+ ProductionRelease,
0, // ignored,
},
{
semverTriplet{1, 13, 14},
semverTriplet{0, 1, 1}, // bump takes precedence
- betaRelease, 0,
+ BetaRelease, 0,
},
{
semverTriplet{1, 13, 14},
semverTriplet{0, 1, 1},
- productionRelease, 0,
+ ProductionRelease, 0,
},
{
semverTriplet{1, 13, 15}, // bump takes precedence
semverTriplet{0, 1, 1},
- betaRelease, 0,
+ BetaRelease, 0,
},
}
diff --git a/rlp/rlpgen/gen.go b/rlp/rlpgen/gen.go
index 150797c7aa5..7ec38a4c38f 100644
--- a/rlp/rlpgen/gen.go
+++ b/rlp/rlpgen/gen.go
@@ -673,7 +673,7 @@ func (op sliceOp) genDecode(ctx *genContext) (string, string) {
}
func (bctx *buildContext) makeOp(name *types.Named, typ types.Type, tags rlpstruct.Tags) (op, error) {
- switch typ := typ.(type) {
+ switch typ := types.Unalias(typ).(type) {
case *types.Named:
if isBigInt(typ) {
return bigIntOp{}, nil
diff --git a/rlp/rlpgen/gen_test.go b/rlp/rlpgen/gen_test.go
index 3b4f5df2876..be439902610 100644
--- a/rlp/rlpgen/gen_test.go
+++ b/rlp/rlpgen/gen_test.go
@@ -47,7 +47,7 @@ func init() {
}
}
-var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256"}
+var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256", "alias"}
func TestOutput(t *testing.T) {
for _, test := range tests {
diff --git a/rlp/rlpgen/testdata/alias.in.txt b/rlp/rlpgen/testdata/alias.in.txt
new file mode 100644
index 00000000000..c7aa8a3106f
--- /dev/null
+++ b/rlp/rlpgen/testdata/alias.in.txt
@@ -0,0 +1,22 @@
+// -*- mode: go -*-
+
+package test
+
+import (
+ "math/big"
+ "github.com/holiman/uint256"
+)
+
+// Alias types chosen because their originals have special handling that is easy
+// to spot when inspecting generated output.
+type (
+ Big = big.Int
+ // Demonstrate recursive unaliasing
+ intermediate = uint256.Int
+ Uint256 = intermediate
+)
+
+type Test struct {
+ BigAlias Big
+ Uint256Alias Uint256
+}
diff --git a/rlp/rlpgen/testdata/alias.out.txt b/rlp/rlpgen/testdata/alias.out.txt
new file mode 100644
index 00000000000..0746f974946
--- /dev/null
+++ b/rlp/rlpgen/testdata/alias.out.txt
@@ -0,0 +1,43 @@
+package test
+
+import "github.com/ava-labs/libevm/rlp"
+import "github.com/holiman/uint256"
+import "io"
+
+func (obj *Test) EncodeRLP(_w io.Writer) error {
+ w := rlp.NewEncoderBuffer(_w)
+ _tmp0 := w.List()
+ if obj.BigAlias.Sign() == -1 {
+ return rlp.ErrNegativeBigInt
+ }
+ w.WriteBigInt(&obj.BigAlias)
+ w.WriteUint256(&obj.Uint256Alias)
+ w.ListEnd(_tmp0)
+ return w.Flush()
+}
+
+func (obj *Test) DecodeRLP(dec *rlp.Stream) error {
+ var _tmp0 Test
+ {
+ if _, err := dec.List(); err != nil {
+ return err
+ }
+ // BigAlias:
+ _tmp1, err := dec.BigInt()
+ if err != nil {
+ return err
+ }
+ _tmp0.BigAlias = (*_tmp1)
+ // Uint256Alias:
+ var _tmp2 uint256.Int
+ if err := dec.ReadUint256(&_tmp2); err != nil {
+ return err
+ }
+ _tmp0.Uint256Alias = _tmp2
+ if err := dec.ListEnd(); err != nil {
+ return err
+ }
+ }
+ *obj = _tmp0
+ return nil
+}