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 +}