diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1dc750fb60..c53c8ab6ae 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -27,6 +27,40 @@ guidelines: - Commit messages should be prefixed with the package(s) they modify. - E.g. "eth, rpc: make trace configs optional" +### Mocks + +Mocks are auto-generated using [mockgen](https://pkg.go.dev/go.uber.org/mock/mockgen) and `//go:generate` commands in the code. + +- To **re-generate all mocks**, use the command below from the root of the project: + + ```sh + go generate -run "go.uber.org/mock/mockgen" ./... + ``` + +- To **add** an interface that needs a corresponding mock generated: + - if the file `mocks_generate_test.go` exists in the package where the interface is located, either: + - modify its `//go:generate go run go.uber.org/mock/mockgen` to generate a mock for your interface (preferred); or + - add another `//go:generate go run go.uber.org/mock/mockgen` to generate a mock for your interface according to specific mock generation settings + - if the file `mocks_generate_test.go` does not exist in the package where the interface is located, create it with content (adapt as needed): + + ```go + // Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. + // See the file LICENSE for licensing terms. + + package mypackage + + //go:generate go run go.uber.org/mock/mockgen -package=${GOPACKAGE} -destination=mocks_test.go . YourInterface + ``` + + Notes: + 1. Ideally generate all mocks to `mocks_test.go` for the package you need to use the mocks for and do not export mocks to other packages. This reduces package dependencies, reduces production code pollution and forces to have locally defined narrow interfaces. + 1. Prefer using reflect mode to generate mocks than source mode, unless you need a mock for an unexported interface, which should be rare. +- To **remove** an interface from having a corresponding mock generated: + 1. Edit the `mocks_generate_test.go` file in the directory where the interface is defined + 1. If the `//go:generate` mockgen command line: + - generates a mock file for multiple interfaces, remove your interface from the line + - generates a mock file only for the interface, remove the entire line. If the file is empty, remove `mocks_generate_test.go` as well. + ## Documentation guidelines - Code should be well commented, so it is easier to read and maintain. @@ -35,7 +69,7 @@ guidelines: [commentary](https://go.dev/doc/effective_go#commentary) guidelines. - Changes with user facing impact (e.g., addition or modification of flags and options) should be accompanied by a link to a pull request to the [avalanche-docs](https://github.com/ava-labs/avalanche-docs) - repository. [example](https://github.com/ava-labs/avalanche-docs/pull/1119/files). + repository. [example](https://github.com/ava-labs/avalanche-docs/pull/1119/files). - Changes that modify a package significantly or add new features should either update the existing or include a new `README.md` file in that package. diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 7c7c833eb6..71f2fc2135 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -12,7 +12,6 @@ jobs: - uses: actions/setup-go@v4 with: go-version: "~1.22.8" - check-latest: true - run: go mod download shell: bash - run: ./scripts/build_bench_precompiles.sh diff --git a/.github/workflows/check-clean-branch.sh b/.github/workflows/check-clean-branch.sh deleted file mode 100755 index 1eec74803a..0000000000 --- a/.github/workflows/check-clean-branch.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# Exits if any uncommitted changes are found. - -set -o errexit -set -o nounset -set -o pipefail - -git update-index --really-refresh >> /dev/null -git diff-index --quiet HEAD diff --git a/.github/workflows/publish_docker.yml b/.github/workflows/publish_docker.yml index 5a16349cf5..d1764edc66 100644 --- a/.github/workflows/publish_docker.yml +++ b/.github/workflows/publish_docker.yml @@ -17,13 +17,17 @@ on: jobs: publish_docker_image: - name: Publish Docker Image - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Publish image to Dockerhub + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + - name: Build and publish images to DockerHub env: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} DOCKER_PASS: ${{ secrets.DOCKER_PASS }} DOCKER_REPO: "avaplatform/subnet-evm" - run: .github/workflows/publish_docker_image.sh ${{ inputs.vm_id }} + VM_ID: ${{ inputs.vm_id }} + PUBLISH: 1 + PLATFORMS: "linux/amd64,linux/arm64" + run: scripts/build_docker_image.sh diff --git a/.github/workflows/publish_docker_image.sh b/.github/workflows/publish_docker_image.sh deleted file mode 100755 index 71bce26c12..0000000000 --- a/.github/workflows/publish_docker_image.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -set -o nounset -set -o pipefail - -# If this is not a trusted build (Docker Credentials are not set) -if [[ -z "$DOCKER_USERNAME" ]]; then - exit 0; -fi - -# Avalanche root directory -SUBNET_EVM_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd ../.. && pwd ) - -# Load the versions -source "$SUBNET_EVM_PATH"/scripts/versions.sh - -# Set the vm id if provided -if [[ $# -eq 1 ]]; then - VM_ID=$1 -fi - -# Buld the docker image -source "$SUBNET_EVM_PATH"/scripts/build_docker_image.sh - -if [[ $CURRENT_BRANCH == "master" ]]; then - echo "Tagging current image as $DOCKERHUB_REPO:latest" - docker tag "$DOCKERHUB_REPO:$BUILD_IMAGE_ID" "$DOCKERHUB_REPO:latest" -fi - -echo "Pushing $DOCKERHUB_REPO:$BUILD_IMAGE_ID" - -echo "$DOCKER_PASS" | docker login --username "$DOCKER_USERNAME" --password-stdin - -docker push -a "$DOCKERHUB_REPO" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 84113cffe1..5af8b527c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: tag: - description: "Tag to include in artifact name" + description: "Tag to checkout & release" required: true push: tags: @@ -20,11 +20,11 @@ jobs: with: fetch-depth: 0 path: subnet-evm + ref: ${{ github.event.inputs.tag }} - name: Set up Go uses: actions/setup-go@v5 with: go-version: "~1.22.8" - check-latest: true - name: Set up arm64 cross compiler run: | sudo apt-get -y update diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3540ea2616..6e573052d4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,12 +17,11 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 - - run: ./scripts/lint_allowed_geth_imports.sh + - run: ./scripts/lint_allowed_eth_imports.sh shell: bash - uses: actions/setup-go@v5 with: go-version: ${{ env.min_go_version }} - check-latest: true - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: @@ -36,6 +35,10 @@ jobs: - name: Run actionlint shell: bash run: scripts/actionlint.sh + - name: go mod tidy + run: | + go mod tidy + git diff --exit-code unit_test: name: Golang Unit Tests (${{ matrix.os }}) @@ -49,13 +52,19 @@ jobs: - uses: actions/setup-go@v5 with: go-version: ${{ env.min_go_version }} - check-latest: true - name: Set timeout on Windows # Windows UT run slower and need a longer timeout shell: bash if: matrix.os == 'windows-latest' run: echo "TIMEOUT=1200s" >> "$GITHUB_ENV" - run: go mod download shell: bash + - name: Mocks are up to date + shell: bash + run: | + grep -lr -E '^// Code generated by MockGen\. DO NOT EDIT\.$' . | xargs -r rm + go generate -run "go.uber.org/mock/mockgen" ./... + git add --intent-to-add --all + git diff --exit-code - run: ./scripts/build.sh shell: bash - run: ./scripts/build_test.sh @@ -77,7 +86,6 @@ jobs: uses: actions/setup-go@v5 with: go-version: ${{ env.min_go_version }} - check-latest: true - name: Use Node.js uses: actions/setup-node@v4 with: @@ -119,7 +127,6 @@ jobs: uses: actions/setup-go@v5 with: go-version: ${{ env.min_go_version }} - check-latest: true - name: Use Node.js uses: actions/setup-node@v4 with: @@ -140,7 +147,7 @@ jobs: shell: bash run: ./scripts/build.sh - name: Run Warp E2E Tests - uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@v1.11.11-monitoring-url + uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@v1.11.13 with: run: AVALANCHEGO_BUILD_PATH=/tmp/e2e-test/avalanchego ./scripts/run_ginkgo_warp.sh prometheus_id: ${{ secrets.PROMETHEUS_ID || '' }} @@ -164,7 +171,6 @@ jobs: uses: actions/setup-go@v5 with: go-version: ${{ env.min_go_version }} - check-latest: true - name: Install AvalancheGo Release shell: bash run: BASEDIR=/tmp/e2e-test AVALANCHEGO_BUILD_PATH=/tmp/e2e-test/avalanchego ./scripts/install_avalanchego_release.sh @@ -172,7 +178,7 @@ jobs: shell: bash run: ./scripts/build.sh - name: Run E2E Load Tests - uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@v1.11.11-monitoring-url + uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@v1.11.13 with: run: AVALANCHEGO_BUILD_PATH=/tmp/e2e-test/avalanchego ./scripts/run_ginkgo_load.sh prometheus_id: ${{ secrets.PROMETHEUS_ID || '' }} @@ -184,19 +190,6 @@ jobs: if: always() with: name: load-tmpnet-data - mock_gen: - name: MockGen Check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.min_go_version }} - check-latest: true - - shell: bash - run: scripts/mock.gen.sh - - shell: bash - run: .github/workflows/check-clean-branch.sh test_build_image: name: Image build runs-on: ubuntu-latest @@ -213,7 +206,6 @@ jobs: - uses: actions/setup-go@v5 with: go-version: ${{ env.min_go_version }} - check-latest: true - name: Install AvalancheGo Release shell: bash run: BASEDIR=/tmp/e2e-test AVALANCHEGO_BUILD_PATH=/tmp/e2e-test/avalanchego ./scripts/install_avalanchego_release.sh diff --git a/.goreleaser.yml b/.goreleaser.yml index bec5952578..62808b512d 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -18,10 +18,12 @@ builds: overrides: - goos: linux goarch: arm64 + goarm64: v8.0 env: - CC=aarch64-linux-gnu-gcc - goos: darwin goarch: arm64 + goarm64: v8.0 env: - CC=oa64-clang - goos: darwin diff --git a/README.md b/README.md index 186ff7dc14..30bdfb31ab 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ The Subnet EVM runs in a separate process from the main AvalancheGo process and [v0.6.9] AvalancheGo@v1.11.11-v1.11.12 (Protocol Version: 37) [v0.6.10] AvalancheGo@v1.11.11-v1.11.12 (Protocol Version: 37) [v0.6.11] AvalancheGo@v1.11.11-v1.11.12 (Protocol Version: 37) +[v0.6.12] AvalancheGo@v1.11.13/v1.12.0 (Protocol Version: 38) +[v0.7.0] AvalancheGo@v1.12.0-v1.12.1 (Protocol Version: 38) +[v0.7.1] AvalancheGo@v1.12.0-v1.12.1 (Protocol Version: 38) ``` ## API diff --git a/RELEASES.md b/RELEASES.md index 9781320c7d..29febf1347 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,6 +2,18 @@ ## Pending Release +* Refactored trie_prefetcher.go to be structurally similar to upstream. + +## [v0.7.0](https://github.com/ava-labs/subnet-evm/releases/tag/v0.7.0) + +### Updates + +- Changed default write option from `Sync` to `NoSync` in PebbleDB + +### Fixes + +- Fixed database close on shutdown + ## [v0.6.11](https://github.com/ava-labs/subnet-evm/releases/tag/v0.6.11) This release focuses on Standalone DB and database configs. diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 1a6e224090..cb924a0189 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -34,8 +34,8 @@ import ( "io" "math/big" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" ) // The ABI holds information about a contract's context and available diff --git a/accounts/abi/abi_extra_test.go b/accounts/abi/abi_extra_test.go index 52bce1b0a4..32d3c2d0b5 100644 --- a/accounts/abi/abi_extra_test.go +++ b/accounts/abi/abi_extra_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/require" ) diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 68052e639a..1e30d27f19 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -36,9 +36,9 @@ import ( "strings" "testing" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/crypto" "github.com/stretchr/testify/assert" ) diff --git a/accounts/abi/bind/auth.go b/accounts/abi/bind/auth.go index d663c022f1..919b74685a 100644 --- a/accounts/abi/bind/auth.go +++ b/accounts/abi/bind/auth.go @@ -33,13 +33,13 @@ import ( "io" "math/big" + "github.com/ava-labs/libevm/accounts" + "github.com/ava-labs/libevm/accounts/external" + "github.com/ava-labs/libevm/accounts/keystore" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/external" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" ) // ErrNoChainID is returned whenever the user failed to specify a chain id. diff --git a/accounts/abi/bind/backend.go b/accounts/abi/bind/backend.go index b95a05532d..73e9877534 100644 --- a/accounts/abi/bind/backend.go +++ b/accounts/abi/bind/backend.go @@ -31,9 +31,9 @@ import ( "errors" "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/interfaces" - "github.com/ethereum/go-ethereum/common" ) var ( diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 141f30f9c8..7254a3539e 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -29,11 +29,11 @@ package backends import ( "context" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient/simulated" "github.com/ava-labs/subnet-evm/interfaces" - "github.com/ethereum/go-ethereum/common" ) // Verify that SimulatedBackend implements required interfaces diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 50c4a74ac1..4c4f21f0b8 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -34,13 +34,13 @@ import ( "strings" "sync" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/event" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/interfaces" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/event" ) const basefeeWiggleMultiplier = 2 diff --git a/accounts/abi/bind/base_test.go b/accounts/abi/bind/base_test.go index 8ed30c23a4..35d1d5804a 100644 --- a/accounts/abi/bind/base_test.go +++ b/accounts/abi/bind/base_test.go @@ -34,14 +34,14 @@ import ( "strings" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/interfaces" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/assert" ) diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index 7ad368e5ad..d7fe4c03ea 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -39,8 +39,8 @@ import ( "text/template" "unicode" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/accounts/abi" - "github.com/ethereum/go-ethereum/log" ) // BindHook is a callback function that can be used to customize the binding. diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 3c9fd8825b..98b4c91c48 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -35,7 +35,7 @@ import ( "strings" "testing" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) var bindTests = []struct { @@ -56,7 +56,7 @@ var bindTests = []struct { `contract NilContract {}`, []string{`606060405260068060106000396000f3606060405200`}, []string{`[]`}, - `"github.com/ethereum/go-ethereum/common"`, + `"github.com/ava-labs/libevm/common"`, ` if b, err := NewEmpty(common.Address{}, nil); b == nil || err != nil { t.Fatalf("combined binding (%v) nil or error (%v) not nil", b, nil) @@ -79,7 +79,7 @@ var bindTests = []struct { `https://ethereum.org/token`, []string{`60606040526040516107fd3803806107fd83398101604052805160805160a05160c051929391820192909101600160a060020a0333166000908152600360209081526040822086905581548551838052601f6002600019610100600186161502019093169290920482018390047f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56390810193919290918801908390106100e857805160ff19168380011785555b506101189291505b8082111561017157600081556001016100b4565b50506002805460ff19168317905550505050610658806101a56000396000f35b828001600101855582156100ac579182015b828111156100ac5782518260005055916020019190600101906100fa565b50508060016000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061017557805160ff19168380011785555b506100c89291506100b4565b5090565b82800160010185558215610165579182015b8281111561016557825182600050559160200191906001019061018756606060405236156100775760e060020a600035046306fdde03811461007f57806323b872dd146100dc578063313ce5671461010e57806370a082311461011a57806395d89b4114610132578063a9059cbb1461018e578063cae9ca51146101bd578063dc3080f21461031c578063dd62ed3e14610341575b610365610002565b61036760008054602060026001831615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156104eb5780601f106104c0576101008083540402835291602001916104eb565b6103d5600435602435604435600160a060020a038316600090815260036020526040812054829010156104f357610002565b6103e760025460ff1681565b6103d560043560036020526000908152604090205481565b610367600180546020600282841615610100026000190190921691909104601f810182900490910260809081016040526060828152929190828280156104eb5780601f106104c0576101008083540402835291602001916104eb565b610365600435602435600160a060020a033316600090815260036020526040902054819010156103f157610002565b60806020604435600481810135601f8101849004909302840160405260608381526103d5948235946024803595606494939101919081908382808284375094965050505050505060006000836004600050600033600160a060020a03168152602001908152602001600020600050600087600160a060020a031681526020019081526020016000206000508190555084905080600160a060020a0316638f4ffcb1338630876040518560e060020a0281526004018085600160a060020a0316815260200184815260200183600160a060020a03168152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156102f25780820380516001836020036101000a031916815260200191505b50955050505050506000604051808303816000876161da5a03f11561000257505050509392505050565b6005602090815260043560009081526040808220909252602435815220546103d59081565b60046020818152903560009081526040808220909252602435815220546103d59081565b005b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156103c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a03821660009081526040902054808201101561041357610002565b806003600050600033600160a060020a03168152602001908152602001600020600082828250540392505081905550806003600050600084600160a060020a0316815260200190815260200160002060008282825054019250508190555081600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b820191906000526020600020905b8154815290600101906020018083116104ce57829003601f168201915b505050505081565b600160a060020a03831681526040812054808301101561051257610002565b600160a060020a0380851680835260046020908152604080852033949094168086529382528085205492855260058252808520938552929052908220548301111561055c57610002565b816003600050600086600160a060020a03168152602001908152602001600020600082828250540392505081905550816003600050600085600160a060020a03168152602001908152602001600020600082828250540192505081905550816005600050600086600160a060020a03168152602001908152602001600020600050600033600160a060020a0316815260200190815260200160002060008282825054019250508190555082600160a060020a031633600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3939250505056`}, []string{`[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"spentAllowance","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"inputs":[{"name":"initialSupply","type":"uint256"},{"name":"tokenName","type":"string"},{"name":"decimalUnits","type":"uint8"},{"name":"tokenSymbol","type":"string"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]`}, - `"github.com/ethereum/go-ethereum/common"`, + `"github.com/ava-labs/libevm/common"`, ` if b, err := NewToken(common.Address{}, nil); b == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", b, nil) @@ -95,7 +95,7 @@ var bindTests = []struct { `https://ethereum.org/crowdsale`, []string{`606060408190526007805460ff1916905560a0806105a883396101006040529051608051915160c05160e05160008054600160a060020a03199081169095178155670de0b6b3a7640000958602600155603c9093024201600355930260045560058054909216909217905561052f90819061007990396000f36060604052361561006c5760e060020a600035046301cb3b20811461008257806329dcb0cf1461014457806338af3eed1461014d5780636e66f6e91461015f5780637a3a0e84146101715780637b3e5e7b1461017a578063a035b1fe14610183578063dc0d3dff1461018c575b61020060075460009060ff161561032357610002565b61020060035460009042106103205760025460015490106103cb576002548154600160a060020a0316908290606082818181858883f150915460025460408051600160a060020a039390931683526020830191909152818101869052517fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf6945090819003909201919050a15b60405160008054600160a060020a039081169230909116319082818181858883f150506007805460ff1916600117905550505050565b6103a160035481565b6103ab600054600160a060020a031681565b6103ab600554600160a060020a031681565b6103a160015481565b6103a160025481565b6103a160045481565b6103be60043560068054829081101561000257506000526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f8101547ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d409190910154600160a060020a03919091169082565b005b505050815481101561000257906000526020600020906002020160005060008201518160000160006101000a815481600160a060020a030219169083021790555060208201518160010160005055905050806002600082828250540192505081905550600560009054906101000a9004600160a060020a0316600160a060020a031663a9059cbb3360046000505484046040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506000604051808303816000876161da5a03f11561000257505060408051600160a060020a03331681526020810184905260018183015290517fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf692509081900360600190a15b50565b5060a0604052336060908152346080819052600680546001810180835592939282908280158290116102025760020281600202836000526020600020918201910161020291905b8082111561039d57805473ffffffffffffffffffffffffffffffffffffffff19168155600060019190910190815561036a565b5090565b6060908152602090f35b600160a060020a03166060908152602090f35b6060918252608052604090f35b5b60065481101561010e576006805482908110156100025760009182526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0190600680549254600160a060020a0316928490811015610002576002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40015460405190915082818181858883f19350505050507fe842aea7a5f1b01049d752008c53c52890b1a6daf660cf39e8eec506112bbdf660066000508281548110156100025760008290526002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01548154600160a060020a039190911691908490811015610002576002027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40015460408051600160a060020a0394909416845260208401919091526000838201525191829003606001919050a16001016103cc56`}, []string{`[{"constant":false,"inputs":[],"name":"checkGoalReached","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"deadline","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"beneficiary","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"tokenReward","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[],"name":"fundingGoal","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"amountRaised","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"price","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"funders","outputs":[{"name":"addr","type":"address"},{"name":"amount","type":"uint256"}],"type":"function"},{"inputs":[{"name":"ifSuccessfulSendTo","type":"address"},{"name":"fundingGoalInEthers","type":"uint256"},{"name":"durationInMinutes","type":"uint256"},{"name":"etherCostOfEachToken","type":"uint256"},{"name":"addressOfTokenUsedAsReward","type":"address"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"backer","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"isContribution","type":"bool"}],"name":"FundTransfer","type":"event"}]`}, - `"github.com/ethereum/go-ethereum/common"`, + `"github.com/ava-labs/libevm/common"`, ` if b, err := NewCrowdsale(common.Address{}, nil); b == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", b, nil) @@ -111,7 +111,7 @@ var bindTests = []struct { `https://ethereum.org/dao`, []string{`606060405260405160808061145f833960e06040529051905160a05160c05160008054600160a060020a03191633179055600184815560028490556003839055600780549182018082558280158290116100b8576003028160030283600052602060002091820191016100b891906101c8565b50506060919091015160029190910155600160a060020a0381166000146100a65760008054600160a060020a031916821790555b505050506111f18061026e6000396000f35b505060408051608081018252600080825260208281018290528351908101845281815292820192909252426060820152600780549194509250811015610002579081527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889050815181546020848101517401000000000000000000000000000000000000000002600160a060020a03199290921690921760a060020a60ff021916178255604083015180516001848101805460008281528690209195600293821615610100026000190190911692909204601f9081018390048201949192919091019083901061023e57805160ff19168380011785555b50610072929150610226565b5050600060028201556001015b8082111561023a578054600160a860020a031916815560018181018054600080835592600290821615610100026000190190911604601f81901061020c57506101bb565b601f0160209004906000526020600020908101906101bb91905b8082111561023a5760008155600101610226565b5090565b828001600101855582156101af579182015b828111156101af57825182600050559160200191906001019061025056606060405236156100b95760e060020a6000350463013cf08b81146100bb578063237e9492146101285780633910682114610281578063400e3949146102995780635daf08ca146102a257806369bd34361461032f5780638160f0b5146103385780638da5cb5b146103415780639644fcbd14610353578063aa02a90f146103be578063b1050da5146103c7578063bcca1fd3146104b5578063d3c0715b146104dc578063eceb29451461058d578063f2fde38b1461067b575b005b61069c6004356004805482908110156100025790600052602060002090600a02016000506005810154815460018301546003840154600485015460068601546007870154600160a060020a03959095169750929560020194919360ff828116946101009093041692919089565b60408051602060248035600481810135601f81018590048502860185019096528585526107759581359591946044949293909201918190840183828082843750949650505050505050600060006004600050848154811015610002575090527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19e600a8402908101547f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b909101904210806101e65750600481015460ff165b8061026757508060000160009054906101000a9004600160a060020a03168160010160005054846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020816007016000505414155b8061027757506001546005820154105b1561109257610002565b61077560043560066020526000908152604090205481565b61077560055481565b61078760043560078054829081101561000257506000526003026000805160206111d18339815191528101547fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a820154600160a060020a0382169260a060020a90920460ff16917fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c689019084565b61077560025481565b61077560015481565b610830600054600160a060020a031681565b604080516020604435600481810135601f81018490048402850184019095528484526100b9948135946024803595939460649492939101918190840183828082843750949650505050505050600080548190600160a060020a03908116339091161461084d57610002565b61077560035481565b604080516020604435600481810135601f8101849004840285018401909552848452610775948135946024803595939460649492939101918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024909101945090925082915084018382808284375094965050505050505033600160a060020a031660009081526006602052604081205481908114806104ab5750604081205460078054909190811015610002579082526003026000805160206111d1833981519152015460a060020a900460ff16155b15610ce557610002565b6100b960043560243560443560005433600160a060020a03908116911614610b1857610002565b604080516020604435600481810135601f810184900484028501840190955284845261077594813594602480359593946064949293910191819084018382808284375094965050505050505033600160a060020a031660009081526006602052604081205481908114806105835750604081205460078054909190811015610002579082526003026000805160206111d18339815191520181505460a060020a900460ff16155b15610f1d57610002565b604080516020606435600481810135601f81018490048402850184019095528484526107759481359460248035956044359560849492019190819084018382808284375094965050505050505060006000600460005086815481101561000257908252600a027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01815090508484846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160070160005054149150610cdc565b6100b960043560005433600160a060020a03908116911614610f0857610002565b604051808a600160a060020a031681526020018981526020018060200188815260200187815260200186815260200185815260200184815260200183815260200182810382528981815460018160011615610100020316600290048152602001915080546001816001161561010002031660029004801561075e5780601f106107335761010080835404028352916020019161075e565b820191906000526020600020905b81548152906001019060200180831161074157829003601f168201915b50509a505050505050505050505060405180910390f35b60408051918252519081900360200190f35b60408051600160a060020a038616815260208101859052606081018390526080918101828152845460026001821615610100026000190190911604928201839052909160a08301908590801561081e5780601f106107f35761010080835404028352916020019161081e565b820191906000526020600020905b81548152906001019060200180831161080157829003601f168201915b50509550505050505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b600160a060020a03851660009081526006602052604081205414156108a957604060002060078054918290556001820180825582801582901161095c5760030281600302836000526020600020918201910161095c9190610a4f565b600160a060020a03851660009081526006602052604090205460078054919350908390811015610002575060005250600381026000805160206111d183398151915201805474ff0000000000000000000000000000000000000000191660a060020a85021781555b60408051600160a060020a03871681526020810186905281517f27b022af4a8347100c7a041ce5ccf8e14d644ff05de696315196faae8cd50c9b929181900390910190a15050505050565b505050915081506080604051908101604052808681526020018581526020018481526020014281526020015060076000508381548110156100025790600052602060002090600302016000508151815460208481015160a060020a02600160a060020a03199290921690921774ff00000000000000000000000000000000000000001916178255604083015180516001848101805460008281528690209195600293821615610100026000190190911692909204601f90810183900482019491929190910190839010610ad357805160ff19168380011785555b50610b03929150610abb565b5050600060028201556001015b80821115610acf57805474ffffffffffffffffffffffffffffffffffffffffff1916815560018181018054600080835592600290821615610100026000190190911604601f819010610aa15750610a42565b601f016020900490600052602060002090810190610a4291905b80821115610acf5760008155600101610abb565b5090565b82800160010185558215610a36579182015b82811115610a36578251826000505591602001919060010190610ae5565b50506060919091015160029190910155610911565b600183905560028290556003819055604080518481526020810184905280820183905290517fa439d3fa452be5e0e1e24a8145e715f4fd8b9c08c96a42fd82a855a85e5d57de9181900360600190a1505050565b50508585846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160070160005081905550600260005054603c024201816003016000508190555060008160040160006101000a81548160ff0219169083021790555060008160040160016101000a81548160ff02191690830217905550600081600501600050819055507f646fec02522b41e7125cfc859a64fd4f4cefd5dc3b6237ca0abe251ded1fa881828787876040518085815260200184600160a060020a03168152602001838152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015610cc45780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a1600182016005555b50949350505050565b6004805460018101808355909190828015829011610d1c57600a0281600a028360005260206000209182019101610d1c9190610db8565b505060048054929450918491508110156100025790600052602060002090600a02016000508054600160a060020a031916871781556001818101879055855160028381018054600082815260209081902096975091959481161561010002600019011691909104601f90810182900484019391890190839010610ed857805160ff19168380011785555b50610b6c929150610abb565b50506001015b80821115610acf578054600160a060020a03191681556000600182810182905560028381018054848255909281161561010002600019011604601f819010610e9c57505b5060006003830181905560048301805461ffff191690556005830181905560068301819055600783018190556008830180548282559082526020909120610db2916002028101905b80821115610acf57805474ffffffffffffffffffffffffffffffffffffffffff1916815560018181018054600080835592600290821615610100026000190190911604601f819010610eba57505b5050600101610e44565b601f016020900490600052602060002090810190610dfc9190610abb565b601f016020900490600052602060002090810190610e929190610abb565b82800160010185558215610da6579182015b82811115610da6578251826000505591602001919060010190610eea565b60008054600160a060020a0319168217905550565b600480548690811015610002576000918252600a027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01905033600160a060020a0316600090815260098201602052604090205490915060ff1660011415610f8457610002565b33600160a060020a031660009081526009820160205260409020805460ff1916600190811790915560058201805490910190558315610fcd576006810180546001019055610fda565b6006810180546000190190555b7fc34f869b7ff431b034b7b9aea9822dac189a685e0b015c7d1be3add3f89128e8858533866040518085815260200184815260200183600160a060020a03168152602001806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600f02600301f150905090810190601f16801561107a5780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a1509392505050565b6006810154600354901315611158578060000160009054906101000a9004600160a060020a0316600160a060020a03168160010160005054670de0b6b3a76400000284604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f1680156111225780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f15050505060048101805460ff191660011761ff00191661010017905561116d565b60048101805460ff191660011761ff00191690555b60068101546005820154600483015460408051888152602081019490945283810192909252610100900460ff166060830152517fd220b7272a8b6d0d7d6bcdace67b936a8f175e6d5c1b3ee438b72256b32ab3af9181900360800190a1509291505056a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688`}, []string{`[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"proposals","outputs":[{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"},{"name":"description","type":"string"},{"name":"votingDeadline","type":"uint256"},{"name":"executed","type":"bool"},{"name":"proposalPassed","type":"bool"},{"name":"numberOfVotes","type":"uint256"},{"name":"currentResult","type":"int256"},{"name":"proposalHash","type":"bytes32"}],"type":"function"},{"constant":false,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"transactionBytecode","type":"bytes"}],"name":"executeProposal","outputs":[{"name":"result","type":"int256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"memberId","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"numProposals","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"members","outputs":[{"name":"member","type":"address"},{"name":"canVote","type":"bool"},{"name":"name","type":"string"},{"name":"memberSince","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"debatingPeriodInMinutes","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"minimumQuorum","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"targetMember","type":"address"},{"name":"canVote","type":"bool"},{"name":"memberName","type":"string"}],"name":"changeMembership","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"majorityMargin","outputs":[{"name":"","type":"int256"}],"type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"},{"name":"etherAmount","type":"uint256"},{"name":"JobDescription","type":"string"},{"name":"transactionBytecode","type":"bytes"}],"name":"newProposal","outputs":[{"name":"proposalID","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"minimumQuorumForProposals","type":"uint256"},{"name":"minutesForDebate","type":"uint256"},{"name":"marginOfVotesForMajority","type":"int256"}],"name":"changeVotingRules","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"supportsProposal","type":"bool"},{"name":"justificationText","type":"string"}],"name":"vote","outputs":[{"name":"voteID","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"proposalNumber","type":"uint256"},{"name":"beneficiary","type":"address"},{"name":"etherAmount","type":"uint256"},{"name":"transactionBytecode","type":"bytes"}],"name":"checkProposalCode","outputs":[{"name":"codeChecksOut","type":"bool"}],"type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"type":"function"},{"inputs":[{"name":"minimumQuorumForProposals","type":"uint256"},{"name":"minutesForDebate","type":"uint256"},{"name":"marginOfVotesForMajority","type":"int256"},{"name":"congressLeader","type":"address"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"recipient","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"description","type":"string"}],"name":"ProposalAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"position","type":"bool"},{"indexed":false,"name":"voter","type":"address"},{"indexed":false,"name":"justification","type":"string"}],"name":"Voted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"proposalID","type":"uint256"},{"indexed":false,"name":"result","type":"int256"},{"indexed":false,"name":"quorum","type":"uint256"},{"indexed":false,"name":"active","type":"bool"}],"name":"ProposalTallied","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"member","type":"address"},{"indexed":false,"name":"isMember","type":"bool"}],"name":"MembershipChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"minimumQuorum","type":"uint256"},{"indexed":false,"name":"debatingPeriodInMinutes","type":"uint256"},{"indexed":false,"name":"majorityMargin","type":"int256"}],"name":"ChangeOfRules","type":"event"}]`}, - `"github.com/ethereum/go-ethereum/common"`, + `"github.com/ava-labs/libevm/common"`, ` if b, err := NewDAO(common.Address{}, nil); b == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", b, nil) @@ -138,7 +138,7 @@ var bindTests = []struct { ` "fmt" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" `, `if b, err := NewInputChecker(common.Address{}, nil); b == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", b, nil) @@ -176,7 +176,7 @@ var bindTests = []struct { ` "fmt" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" `, `if b, err := NewOutputChecker(common.Address{}, nil); b == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", b, nil) @@ -217,7 +217,7 @@ var bindTests = []struct { "math/big" "reflect" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" `, `if e, err := NewEventChecker(common.Address{}, nil); e == nil || err != nil { t.Fatalf("binding (%v) nil or error (%v) not nil", e, nil) @@ -300,7 +300,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -356,7 +356,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -402,7 +402,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -458,9 +458,9 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -508,7 +508,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -575,7 +575,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -619,7 +619,7 @@ var bindTests = []struct { ` "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" `, ` @@ -658,7 +658,7 @@ var bindTests = []struct { ` "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" `, ` @@ -707,7 +707,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -755,9 +755,9 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -832,7 +832,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -924,9 +924,9 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -1116,7 +1116,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -1251,7 +1251,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` @@ -1393,7 +1393,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -1459,7 +1459,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Initialize test accounts @@ -1567,7 +1567,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/core/types" `, ` @@ -1630,7 +1630,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/core/types" `, ` @@ -1693,7 +1693,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` // Generate a new random account and a funded simulator @@ -1754,7 +1754,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` key, _ := crypto.GenerateKey() @@ -1842,7 +1842,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` var ( @@ -1912,7 +1912,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, ` var ( @@ -1964,7 +1964,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, tester: ` var ( @@ -2012,7 +2012,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, tester: ` var ( @@ -2053,7 +2053,7 @@ var bindTests = []struct { "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/backends" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" `, tester: ` var ( @@ -2088,7 +2088,7 @@ var bindTests = []struct { bytecode: []string{"0x6080604052348015600f57600080fd5b5060958061001e6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80639d993132146041578063d02767c7146049578063ffa02795146051575b600080fd5b60476059565b005b604f605b565b005b6057605d565b005b565b565b56fea26469706673582212200382ca602dff96a7e2ba54657985e2b4ac423a56abe4a1f0667bc635c4d4371f64736f6c63430008110033"}, abi: []string{`[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_param","type":"address"}],"name":"_1TestEvent","type":"event"},{"inputs":[],"name":"_1test","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"__1test","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"__2test","outputs":[],"stateMutability":"pure","type":"function"}]`}, imports: ` - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" `, tester: ` if b, err := NewNumericMethodName(common.Address{}, nil); b == nil || err != nil { @@ -2179,11 +2179,6 @@ func golangBindings(t *testing.T, overload bool) { if out, err := replacer.CombinedOutput(); err != nil { t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out) } - replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/ethereum/go-ethereum@v0.0.0", "-replace", "github.com/ethereum/go-ethereum=github.com/ava-labs/go-ethereum@v0.0.0-20241007222654-0752a11d4aee") - replacer.Dir = pkg - if out, err := replacer.CombinedOutput(); err != nil { - t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out) - } tidier := exec.Command(gocmd, "mod", "tidy", "-compat=1.22") tidier.Dir = pkg if out, err := tidier.CombinedOutput(); err != nil { diff --git a/accounts/abi/bind/precompilebind/precompile_bind_test.go b/accounts/abi/bind/precompilebind/precompile_bind_test.go index 02d7e60aa1..a631f0e086 100644 --- a/accounts/abi/bind/precompilebind/precompile_bind_test.go +++ b/accounts/abi/bind/precompilebind/precompile_bind_test.go @@ -35,8 +35,8 @@ import ( "strings" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) @@ -207,7 +207,7 @@ var bindTests = []struct { ` "math/big" "github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" `, ` testArgs := []common.Address{common.HexToAddress("1"), common.HexToAddress("2"), common.HexToAddress("3")} @@ -451,7 +451,7 @@ var bindTests = []struct { `[{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"readAllowList","outputs":[{"internalType":"uint256","name":"role","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sayHello","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"response","type":"string"}],"name":"setGreeting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setNone","outputs":[],"stateMutability":"nonpayable","type":"function"}]`, `"github.com/stretchr/testify/require" "math/big" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/extstate" "github.com/ava-labs/subnet-evm/precompile/allowlist" `, @@ -516,7 +516,7 @@ var bindTests = []struct { `, `[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addressTest","type":"address"},{"indexed":true,"internalType":"uint8","name":"intTest","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"bytesTest","type":"bytes"}],"name":"test","type":"event"},{"inputs":[],"name":"eventTest","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"type":"event","name":"empty","inputs":[]},{"type":"event","name":"indexed","inputs":[{"name":"addr","type":"address","indexed":true},{"name":"num","type":"int8","indexed":true}]},{"type":"event","name":"mixed","inputs":[{"name":"addr","type":"address","indexed":true},{"name":"num","type":"int8"}]},{"type":"event","name":"dynamic","inputs":[{"name":"idxStr","type":"string","indexed":true},{"name":"idxDat","type":"bytes","indexed":true},{"name":"str","type":"string"},{"name":"dat","type":"bytes"}]},{"type":"event","name":"unnamed","inputs":[{"name":"","type":"uint8","indexed":true},{"name":"","type":"uint8","indexed":true}]}]`, `"github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" `, ` @@ -695,11 +695,6 @@ func TestPrecompileBind(t *testing.T) { if out, err := replacer.CombinedOutput(); err != nil { t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out) } - replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/ethereum/go-ethereum@v0.0.0", "-replace", "github.com/ethereum/go-ethereum=github.com/ava-labs/go-ethereum@v0.0.0-20241007222654-0752a11d4aee") - replacer.Dir = pkg - if out, err := replacer.CombinedOutput(); err != nil { - t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out) - } tidier := exec.Command(gocmd, "mod", "tidy", "-compat=1.22") tidier.Dir = pkg if out, err := tidier.CombinedOutput(); err != nil { diff --git a/accounts/abi/bind/precompilebind/precompile_config_template.go b/accounts/abi/bind/precompilebind/precompile_config_template.go index 69c4fcbcc9..cc04ca7d05 100644 --- a/accounts/abi/bind/precompilebind/precompile_config_template.go +++ b/accounts/abi/bind/precompilebind/precompile_config_template.go @@ -15,7 +15,7 @@ import ( {{- if .Contract.AllowList}} "github.com/ava-labs/subnet-evm/precompile/allowlist" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" {{- end}} ) diff --git a/accounts/abi/bind/precompilebind/precompile_config_test_template.go b/accounts/abi/bind/precompilebind/precompile_config_test_template.go index 3c03732fd4..26e28dba60 100644 --- a/accounts/abi/bind/precompilebind/precompile_config_test_template.go +++ b/accounts/abi/bind/precompilebind/precompile_config_test_template.go @@ -19,7 +19,7 @@ import ( {{- if .Contract.AllowList}} "github.com/ava-labs/subnet-evm/precompile/allowlist" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" {{- end}} "go.uber.org/mock/gomock" ) diff --git a/accounts/abi/bind/precompilebind/precompile_contract_template.go b/accounts/abi/bind/precompilebind/precompile_contract_template.go index 8b637b0ec4..5421bd9a9e 100644 --- a/accounts/abi/bind/precompilebind/precompile_contract_template.go +++ b/accounts/abi/bind/precompilebind/precompile_contract_template.go @@ -41,7 +41,7 @@ import ( _ "embed" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) {{$contract := .Contract}} const ( diff --git a/accounts/abi/bind/precompilebind/precompile_contract_test_template.go b/accounts/abi/bind/precompilebind/precompile_contract_test_template.go index f518ed6de9..9af40cb1c9 100644 --- a/accounts/abi/bind/precompilebind/precompile_contract_test_template.go +++ b/accounts/abi/bind/precompilebind/precompile_contract_test_template.go @@ -20,7 +20,7 @@ import ( {{- end}} "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/require" ) diff --git a/accounts/abi/bind/precompilebind/precompile_event_template.go b/accounts/abi/bind/precompilebind/precompile_event_template.go index 3a5582b35e..246a8d06bf 100644 --- a/accounts/abi/bind/precompilebind/precompile_event_template.go +++ b/accounts/abi/bind/precompilebind/precompile_event_template.go @@ -13,7 +13,7 @@ import ( "math/big" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) // CUSTOM CODE STARTS HERE diff --git a/accounts/abi/bind/precompilebind/precompile_module_template.go b/accounts/abi/bind/precompilebind/precompile_module_template.go index e9dd8e7275..e5f0c2f61a 100644 --- a/accounts/abi/bind/precompilebind/precompile_module_template.go +++ b/accounts/abi/bind/precompilebind/precompile_module_template.go @@ -17,7 +17,7 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/modules" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) var _ contract.Configurator = &configurator{} diff --git a/accounts/abi/bind/template.go b/accounts/abi/bind/template.go index a39311d774..7b78dafa26 100644 --- a/accounts/abi/bind/template.go +++ b/accounts/abi/bind/template.go @@ -105,8 +105,8 @@ import ( "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/interfaces" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/event" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/event" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/accounts/abi/bind/util.go b/accounts/abi/bind/util.go index 2d4e3a6eb5..960bbd1d64 100644 --- a/accounts/abi/bind/util.go +++ b/accounts/abi/bind/util.go @@ -31,10 +31,10 @@ import ( "errors" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/interfaces" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" ) // WaitMined waits for tx to be mined on the blockchain. diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/util_test.go index 1dfff2f1f5..5c7eb1fd76 100644 --- a/accounts/abi/bind/util_test.go +++ b/accounts/abi/bind/util_test.go @@ -33,12 +33,12 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient/simulated" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" ) var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -125,7 +125,10 @@ func TestWaitDeployedCornerCases(t *testing.T) { // Create a transaction to an account. code := "6060604052600a8060106000396000f360606040526008565b00" tx := types.NewTransaction(0, common.HexToAddress("0x01"), big.NewInt(0), 3000000, gasPrice, common.FromHex(code)) - tx, _ = types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(1337)), testKey) + tx, err := types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(1337)), testKey) + if err != nil { + t.Fatalf("Failed to sign transaction: %s", err) + } ctx, cancel := context.WithCancel(context.Background()) defer cancel() if err := backend.Client().SendTransaction(ctx, tx); err != nil { diff --git a/accounts/abi/error.go b/accounts/abi/error.go index a968fd20c0..46b056c052 100644 --- a/accounts/abi/error.go +++ b/accounts/abi/error.go @@ -31,8 +31,8 @@ import ( "fmt" "strings" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" ) type Error struct { diff --git a/accounts/abi/event.go b/accounts/abi/event.go index f4f0f5d92d..39b55bb62c 100644 --- a/accounts/abi/event.go +++ b/accounts/abi/event.go @@ -30,8 +30,8 @@ import ( "fmt" "strings" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" ) // Event is an event potentially triggered by the EVM's LOG mechanism. The Event diff --git a/accounts/abi/event_test.go b/accounts/abi/event_test.go index a967decd52..1da8c9dae1 100644 --- a/accounts/abi/event_test.go +++ b/accounts/abi/event_test.go @@ -35,8 +35,8 @@ import ( "strings" "testing" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/accounts/abi/method.go b/accounts/abi/method.go index 1da260da2c..e437d8d2a9 100644 --- a/accounts/abi/method.go +++ b/accounts/abi/method.go @@ -30,7 +30,7 @@ import ( "fmt" "strings" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/crypto" ) // FunctionType represents different types of functions a contract might have. diff --git a/accounts/abi/pack.go b/accounts/abi/pack.go index 9f9f2b23d5..830df0b390 100644 --- a/accounts/abi/pack.go +++ b/accounts/abi/pack.go @@ -32,8 +32,8 @@ import ( "math/big" "reflect" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" ) // packBytesSlice packs the given bytes as [L, V] as the canonical representation diff --git a/accounts/abi/pack_test.go b/accounts/abi/pack_test.go index 47d4931698..99bf47200e 100644 --- a/accounts/abi/pack_test.go +++ b/accounts/abi/pack_test.go @@ -37,7 +37,7 @@ import ( "strings" "testing" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) // TestPack tests the general pack/unpack tests in packing_test.go diff --git a/accounts/abi/packing_test.go b/accounts/abi/packing_test.go index 8e876dcaef..0c2ee00745 100644 --- a/accounts/abi/packing_test.go +++ b/accounts/abi/packing_test.go @@ -29,7 +29,7 @@ package abi import ( "math/big" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) type packUnpackTest struct { diff --git a/accounts/abi/topics.go b/accounts/abi/topics.go index 03082f221e..0e3cb383ee 100644 --- a/accounts/abi/topics.go +++ b/accounts/abi/topics.go @@ -33,9 +33,9 @@ import ( "math/big" "reflect" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/crypto" ) // packTopic packs rule into the corresponding hash value for a log's topic diff --git a/accounts/abi/topics_test.go b/accounts/abi/topics_test.go index 70522b6ce6..691c2c09dc 100644 --- a/accounts/abi/topics_test.go +++ b/accounts/abi/topics_test.go @@ -32,8 +32,8 @@ import ( "reflect" "testing" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" ) func TestMakeTopics(t *testing.T) { diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 75a6c15fd7..93678f5578 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -36,7 +36,7 @@ import ( "unicode" "unicode/utf8" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) // Type enumerator diff --git a/accounts/abi/type_test.go b/accounts/abi/type_test.go index ad0daffe06..c55559167f 100644 --- a/accounts/abi/type_test.go +++ b/accounts/abi/type_test.go @@ -31,8 +31,8 @@ import ( "reflect" "testing" + "github.com/ava-labs/libevm/common" "github.com/davecgh/go-spew/spew" - "github.com/ethereum/go-ethereum/common" ) // typeWithoutStringer is a alias for the Type type which simply doesn't implement diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index b975cb8802..c161c81767 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -34,7 +34,7 @@ import ( "math/big" "reflect" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) var ( diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 0b4224efa5..2454bde1fb 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -37,7 +37,7 @@ import ( "strings" "testing" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/require" ) diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 83ffd67fe2..63974b35cb 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -34,12 +34,12 @@ import ( "regexp" "strings" + "github.com/ava-labs/libevm/common/compiler" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/cmd/utils" "github.com/ava-labs/subnet-evm/internal/flags" - "github.com/ethereum/go-ethereum/common/compiler" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" "github.com/urfave/cli/v2" ) diff --git a/cmd/evm/disasm.go b/cmd/evm/disasm.go index f227e90a2c..5212913546 100644 --- a/cmd/evm/disasm.go +++ b/cmd/evm/disasm.go @@ -32,7 +32,7 @@ import ( "os" "strings" - "github.com/ethereum/go-ethereum/core/asm" + "github.com/ava-labs/libevm/core/asm" "github.com/urfave/cli/v2" ) diff --git a/cmd/evm/internal/compiler/compiler.go b/cmd/evm/internal/compiler/compiler.go index ba72065e43..70dcdde6dc 100644 --- a/cmd/evm/internal/compiler/compiler.go +++ b/cmd/evm/internal/compiler/compiler.go @@ -30,7 +30,7 @@ import ( "errors" "fmt" - "github.com/ethereum/go-ethereum/core/asm" + "github.com/ava-labs/libevm/core/asm" ) func Compile(fn string, src []byte, debug bool) (string, error) { diff --git a/cmd/evm/internal/t8ntool/block.go b/cmd/evm/internal/t8ntool/block.go index c245f0e45b..0543014753 100644 --- a/cmd/evm/internal/t8ntool/block.go +++ b/cmd/evm/internal/t8ntool/block.go @@ -34,12 +34,12 @@ import ( "math/big" "os" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" "github.com/urfave/cli/v2" ) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 4d79684c16..488065fad0 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -30,21 +30,21 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) diff --git a/cmd/evm/internal/t8ntool/flags.go b/cmd/evm/internal/t8ntool/flags.go index 47d72b9ce7..b384d5177e 100644 --- a/cmd/evm/internal/t8ntool/flags.go +++ b/cmd/evm/internal/t8ntool/flags.go @@ -30,8 +30,8 @@ import ( "fmt" "strings" + "github.com/ava-labs/libevm/core/vm" "github.com/ava-labs/subnet-evm/tests" - "github.com/ethereum/go-ethereum/core/vm" "github.com/urfave/cli/v2" ) diff --git a/cmd/evm/internal/t8ntool/gen_header.go b/cmd/evm/internal/t8ntool/gen_header.go index 6ace0fb35d..867ee56241 100644 --- a/cmd/evm/internal/t8ntool/gen_header.go +++ b/cmd/evm/internal/t8ntool/gen_header.go @@ -8,9 +8,9 @@ import ( "math/big" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" ) var _ = (*headerMarshaling)(nil) diff --git a/cmd/evm/internal/t8ntool/gen_stenv.go b/cmd/evm/internal/t8ntool/gen_stenv.go index fcd3431480..8d9fe9e443 100644 --- a/cmd/evm/internal/t8ntool/gen_stenv.go +++ b/cmd/evm/internal/t8ntool/gen_stenv.go @@ -7,8 +7,8 @@ import ( "errors" "math/big" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" ) var _ = (*stEnvMarshaling)(nil) diff --git a/cmd/evm/internal/t8ntool/tracewriter.go b/cmd/evm/internal/t8ntool/tracewriter.go index 92c3e56cbf..bffbf20523 100644 --- a/cmd/evm/internal/t8ntool/tracewriter.go +++ b/cmd/evm/internal/t8ntool/tracewriter.go @@ -21,10 +21,10 @@ import ( "io" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/eth/tracers" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/log" ) // traceWriter is an vm.EVMLogger which also holds an inner logger/tracer. diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index a760670b78..e409a8e9aa 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -34,13 +34,13 @@ import ( "os" "strings" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/tests" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/rlp" "github.com/urfave/cli/v2" ) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 31c0e85b13..35489eb149 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -34,17 +34,17 @@ import ( "os" "path" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/eth/tracers/logger" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/eth/tracers" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/tests" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/logger" - "github.com/ethereum/go-ethereum/log" "github.com/urfave/cli/v2" ) diff --git a/cmd/evm/internal/t8ntool/tx_iterator.go b/cmd/evm/internal/t8ntool/tx_iterator.go index 6a7d909a56..81021c662a 100644 --- a/cmd/evm/internal/t8ntool/tx_iterator.go +++ b/cmd/evm/internal/t8ntool/tx_iterator.go @@ -25,12 +25,12 @@ import ( "os" "strings" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" ) // txWithKey is a helper-struct, to allow us to use the types.Transaction along with diff --git a/cmd/evm/main.go b/cmd/evm/main.go index df423ecfac..3919207818 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -38,8 +38,8 @@ import ( "github.com/urfave/cli/v2" // Force-load the tracer engines to trigger registration - _ "github.com/ethereum/go-ethereum/eth/tracers/js" - _ "github.com/ethereum/go-ethereum/eth/tracers/native" + _ "github.com/ava-labs/libevm/eth/tracers/js" + _ "github.com/ava-labs/libevm/eth/tracers/native" ) var ( diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 16d8d4c151..6e7317bb85 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -37,6 +37,10 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/eth/tracers/logger" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/cmd/evm/internal/compiler" "github.com/ava-labs/subnet-evm/cmd/utils" "github.com/ava-labs/subnet-evm/core" @@ -45,11 +49,7 @@ import ( "github.com/ava-labs/subnet-evm/core/vm/runtime" "github.com/ava-labs/subnet-evm/internal/flags" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/triedb/hashdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/urfave/cli/v2" ) @@ -159,8 +159,8 @@ func runCmd(ctx *cli.Context) error { db := rawdb.NewMemoryDatabase() triedb := triedb.NewDatabase(db, &triedb.Config{ - Preimages: preimages, - HashDB: hashdb.Defaults, + Preimages: preimages, + DBOverride: hashdb.Defaults.BackendConstructor, }) defer triedb.Close() genesis := genesisConfig.MustCommit(db, triedb) diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 7e4da83f11..ab77c5e767 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -32,12 +32,12 @@ import ( "fmt" "os" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/eth/tracers/logger" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/tests" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/urfave/cli/v2" ) diff --git a/cmd/precompilegen/main.go b/cmd/precompilegen/main.go index 35328f4fcd..b7e0a83708 100644 --- a/cmd/precompilegen/main.go +++ b/cmd/precompilegen/main.go @@ -35,11 +35,11 @@ import ( _ "embed" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/accounts/abi/bind/precompilebind" "github.com/ava-labs/subnet-evm/cmd/utils" "github.com/ava-labs/subnet-evm/internal/flags" - "github.com/ethereum/go-ethereum/log" "github.com/urfave/cli/v2" ) diff --git a/cmd/simulator/key/key.go b/cmd/simulator/key/key.go index a1a247b84f..a2dd0de829 100644 --- a/cmd/simulator/key/key.go +++ b/cmd/simulator/key/key.go @@ -10,8 +10,8 @@ import ( "os" "path/filepath" - "github.com/ethereum/go-ethereum/common" - ethcrypto "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + ethcrypto "github.com/ava-labs/libevm/crypto" ) type Key struct { diff --git a/cmd/simulator/load/funder.go b/cmd/simulator/load/funder.go index cda5722a28..209580031b 100644 --- a/cmd/simulator/load/funder.go +++ b/cmd/simulator/load/funder.go @@ -9,14 +9,14 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/cmd/simulator/key" "github.com/ava-labs/subnet-evm/cmd/simulator/metrics" "github.com/ava-labs/subnet-evm/cmd/simulator/txs" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" ) // DistributeFunds ensures that each address in keys has at least [minFundsPerAddr] by sending funds diff --git a/cmd/simulator/load/loader.go b/cmd/simulator/load/loader.go index 0dffe80bb7..31e1902a41 100644 --- a/cmd/simulator/load/loader.go +++ b/cmd/simulator/load/loader.go @@ -14,6 +14,9 @@ import ( "syscall" "time" + "github.com/ava-labs/libevm/common" + ethcrypto "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/cmd/simulator/config" "github.com/ava-labs/subnet-evm/cmd/simulator/key" "github.com/ava-labs/subnet-evm/cmd/simulator/metrics" @@ -21,9 +24,6 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - ethcrypto "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" "golang.org/x/sync/errgroup" ) diff --git a/cmd/simulator/load/worker.go b/cmd/simulator/load/worker.go index 6794127015..367281c810 100644 --- a/cmd/simulator/load/worker.go +++ b/cmd/simulator/load/worker.go @@ -8,11 +8,11 @@ import ( "fmt" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/interfaces" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" ) type ethereumTxWorker struct { diff --git a/cmd/simulator/main/main.go b/cmd/simulator/main/main.go index 5b6603a420..3eca2f4af8 100644 --- a/cmd/simulator/main/main.go +++ b/cmd/simulator/main/main.go @@ -9,10 +9,10 @@ import ( "fmt" "os" + gethlog "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/cmd/simulator/config" "github.com/ava-labs/subnet-evm/cmd/simulator/load" "github.com/ava-labs/subnet-evm/log" - gethlog "github.com/ethereum/go-ethereum/log" "github.com/spf13/pflag" ) diff --git a/cmd/simulator/metrics/metrics.go b/cmd/simulator/metrics/metrics.go index f9d44bbbcb..1c80e73755 100644 --- a/cmd/simulator/metrics/metrics.go +++ b/cmd/simulator/metrics/metrics.go @@ -11,7 +11,7 @@ import ( "net/http" "os" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) diff --git a/cmd/simulator/txs/agent.go b/cmd/simulator/txs/agent.go index db7259bcad..89395c1630 100644 --- a/cmd/simulator/txs/agent.go +++ b/cmd/simulator/txs/agent.go @@ -9,9 +9,9 @@ import ( "fmt" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/cmd/simulator/metrics" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" ) type THash interface { diff --git a/cmd/simulator/txs/tx_generator.go b/cmd/simulator/txs/tx_generator.go index b75672c0f9..cf71363d0e 100644 --- a/cmd/simulator/txs/tx_generator.go +++ b/cmd/simulator/txs/tx_generator.go @@ -8,9 +8,9 @@ import ( "crypto/ecdsa" "fmt" + ethcrypto "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" - ethcrypto "github.com/ethereum/go-ethereum/crypto" ) var _ TxSequence[*types.Transaction] = (*txSequence)(nil) diff --git a/commontype/fee_config.go b/commontype/fee_config.go index 3089df5d9c..a62a4199eb 100644 --- a/commontype/fee_config.go +++ b/commontype/fee_config.go @@ -7,8 +7,8 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" ) // FeeConfig specifies the parameters for the dynamic fee algorithm, which determines the gas limit, base fee, and block gas cost of blocks diff --git a/compatibility.json b/compatibility.json index 0a169e4e2f..435fda56ee 100644 --- a/compatibility.json +++ b/compatibility.json @@ -1,5 +1,8 @@ { "rpcChainVMProtocolVersion": { + "v0.7.1": 38, + "v0.7.0": 38, + "v0.6.12": 38, "v0.6.11": 37, "v0.6.10": 37, "v0.6.9": 37, diff --git a/consensus/consensus.go b/consensus/consensus.go index b96297c4ad..d95ebfae18 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -30,11 +30,11 @@ package consensus import ( "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" ) // ChainHeaderReader defines a small collection of methods needed to access the local diff --git a/consensus/dummy/README.md b/consensus/dummy/README.md index 4375dff5ab..f2269e3019 100644 --- a/consensus/dummy/README.md +++ b/consensus/dummy/README.md @@ -18,7 +18,7 @@ The dynamic fee algorithm aims to adjust the base fee to handle network congesti - EIP-1559 is intended for Ethereum where a block is produced roughly every 10s - The dynamic fee algorithm needs to handle the case that the network quiesces and there are no blocks for a long period of time -- Since Subnet-EVM produces blocks at a different cadence, it adapts EIP-1559 to sum the amount of gas consumed within a 10 second interval instead of using only the amount of gas consumed in the parent block +- Since Subnet-EVM produces blocks at a different cadence, it adapts EIP-1559 to sum the amount of gas consumed within a 10-second interval instead of using only the amount of gas consumed in the parent block ## Consensus Engine Callbacks diff --git a/consensus/dummy/consensus.go b/consensus/dummy/consensus.go index f238c19620..e4e6b09a33 100644 --- a/consensus/dummy/consensus.go +++ b/consensus/dummy/consensus.go @@ -11,14 +11,14 @@ import ( "time" "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/trie" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" ) var ( diff --git a/consensus/dummy/consensus_test.go b/consensus/dummy/consensus_test.go index 12fc21a499..3c49be3ad1 100644 --- a/consensus/dummy/consensus_test.go +++ b/consensus/dummy/consensus_test.go @@ -8,9 +8,9 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" ) var testBlockGasCostStep = big.NewInt(50_000) diff --git a/consensus/dummy/dynamic_fees.go b/consensus/dummy/dynamic_fees.go index eec44aeee9..b6c9db6480 100644 --- a/consensus/dummy/dynamic_fees.go +++ b/consensus/dummy/dynamic_fees.go @@ -9,11 +9,11 @@ import ( "math/big" "github.com/ava-labs/avalanchego/utils/wrappers" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" ) // CalcBaseFee takes the previous header and the timestamp of its child block diff --git a/consensus/dummy/dynamic_fees_test.go b/consensus/dummy/dynamic_fees_test.go index 4ef2af9c22..dd9c8bb069 100644 --- a/consensus/dummy/dynamic_fees_test.go +++ b/consensus/dummy/dynamic_fees_test.go @@ -8,12 +8,12 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/log" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/constants/constants.go b/constants/constants.go index 2514f58119..d1523eaa5b 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -3,7 +3,7 @@ package constants -import "github.com/ethereum/go-ethereum/common" +import "github.com/ava-labs/libevm/common" var ( BlackholeAddr = common.Address{ diff --git a/core/bench_test.go b/core/bench_test.go index 82d09f8ec2..7a5dc50676 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -31,15 +31,15 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" ) func BenchmarkInsertChain_empty_memdb(b *testing.B) { diff --git a/core/block_validator.go b/core/block_validator.go index 1d97574810..78f552ce32 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -30,11 +30,11 @@ import ( "errors" "fmt" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/trie" ) // BlockValidator is responsible for validating block headers, uncles and diff --git a/core/blockchain.go b/core/blockchain.go index 5ba7cc277f..64ac22c0ec 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -39,6 +39,14 @@ import ( "sync/atomic" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/lru" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" @@ -49,16 +57,8 @@ import ( "github.com/ava-labs/subnet-evm/internal/version" "github.com/ava-labs/subnet-evm/metrics" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/triedb/hashdb" "github.com/ava-labs/subnet-evm/triedb/pathdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/lru" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" ) var ( @@ -197,18 +197,18 @@ type CacheConfig struct { func (c *CacheConfig) triedbConfig() *triedb.Config { config := &triedb.Config{Preimages: c.Preimages} if c.StateScheme == rawdb.HashScheme || c.StateScheme == "" { - config.HashDB = &hashdb.Config{ + config.DBOverride = hashdb.Config{ CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, StatsPrefix: trieCleanCacheStatsNamespace, - ReferenceRootAtomicallyOnUpdate: true, - } + ReferenceRootAtomicallyOnUpdate: true, // Automatically reference root nodes when an update is made + }.BackendConstructor } if c.StateScheme == rawdb.PathScheme { - config.PathDB = &pathdb.Config{ + config.DBOverride = pathdb.Config{ StateHistory: c.StateHistory, CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, DirtyCacheSize: c.TrieDirtyLimit * 1024 * 1024, - } + }.BackendConstructor } return config } @@ -1187,8 +1187,8 @@ func (bc *BlockChain) newTip(block *types.Block) bool { // canonical chain. // writeBlockAndSetHead expects to be the last verification step during InsertBlock // since it creates a reference that will only be cleaned up by Accept/Reject. -func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB) error { - if err := bc.writeBlockWithState(block, receipts, state); err != nil { +func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, parentRoot common.Hash, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB) error { + if err := bc.writeBlockWithState(block, parentRoot, receipts, state); err != nil { return err } @@ -1205,7 +1205,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types // writeBlockWithState writes the block and all associated state to the database, // but it expects the chain mutex to be held. -func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) error { +func (bc *BlockChain) writeBlockWithState(block *types.Block, parentRoot common.Hash, receipts []*types.Receipt, state *state.StateDB) error { // Irrelevant of the canonical status, write the block itself to the database. // // Note all the components of block(hash->number map, header, body, receipts) @@ -1219,14 +1219,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } // Commit all cached state changes into underlying memory database. - // If snapshots are enabled, call CommitWithSnaps to explicitly create a snapshot - // diff layer for the block. var err error - if bc.snaps == nil { - _, err = state.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number())) - } else { - _, err = state.CommitWithSnap(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number()), bc.snaps, block.Hash(), block.ParentHash()) - } + _, err = bc.commitWithSnap(block, parentRoot, state) if err != nil { return err } @@ -1349,16 +1343,6 @@ func (bc *BlockChain) insertBlock(block *types.Block, writes bool) error { blockContentValidationTimer.Inc(time.Since(substart).Milliseconds()) // No validation errors for the block - var activeState *state.StateDB - defer func() { - // The chain importer is starting and stopping trie prefetchers. If a bad - // block or other error is hit however, an early return may not properly - // terminate the background threads. This defer ensures that we clean up - // and dangling prefetcher, without deferring each and holding on live refs. - if activeState != nil { - activeState.StopPrefetcher() - } - }() // Retrieve the parent block to determine which root to build state on substart = time.Now() @@ -1377,8 +1361,8 @@ func (bc *BlockChain) insertBlock(block *types.Block, writes bool) error { blockStateInitTimer.Inc(time.Since(substart).Milliseconds()) // Enable prefetching to pull in trie node paths while processing transactions - statedb.StartPrefetcher("chain", bc.cacheConfig.TriePrefetcherParallelism) - activeState = statedb + statedb.StartPrefetcher("chain", state.WithConcurrentWorkers(bc.cacheConfig.TriePrefetcherParallelism)) + defer statedb.StopPrefetcher() // Process block using the parent state as reference point pstart := time.Now() @@ -1429,7 +1413,7 @@ func (bc *BlockChain) insertBlock(block *types.Block, writes bool) error { // will be cleaned up in Accept/Reject so we need to ensure an error cannot occur // later in verification, since that would cause the referenced root to never be dereferenced. wstart := time.Now() - if err := bc.writeBlockAndSetHead(block, receipts, logs, statedb); err != nil { + if err := bc.writeBlockAndSetHead(block, parent.Root, receipts, logs, statedb); err != nil { return err } // Update the metrics touched during block commit @@ -1729,17 +1713,15 @@ func (bc *BlockChain) reprocessBlock(parent *types.Block, current *types.Block) if snap == nil { return common.Hash{}, fmt.Errorf("failed to get snapshot for parent root: %s", parentRoot) } - statedb, err = state.NewWithSnapshot(parentRoot, bc.stateCache, snap) + statedb, err = state.New(parentRoot, bc.stateCache, bc.snaps) } if err != nil { return common.Hash{}, fmt.Errorf("could not fetch state for (%s: %d): %v", parent.Hash().Hex(), parent.NumberU64(), err) } // Enable prefetching to pull in trie node paths while processing transactions - statedb.StartPrefetcher("chain", bc.cacheConfig.TriePrefetcherParallelism) - defer func() { - statedb.StopPrefetcher() - }() + statedb.StartPrefetcher("chain", state.WithConcurrentWorkers(bc.cacheConfig.TriePrefetcherParallelism)) + defer statedb.StopPrefetcher() // Process previously stored block receipts, _, usedGas, err := bc.processor.Process(current, parent.Header(), statedb, vm.Config{}) @@ -1754,12 +1736,28 @@ func (bc *BlockChain) reprocessBlock(parent *types.Block, current *types.Block) log.Debug("Processed block", "block", current.Hash(), "number", current.NumberU64()) // Commit all cached state changes into underlying memory database. - // If snapshots are enabled, call CommitWithSnaps to explicitly create a snapshot - // diff layer for the block. - if bc.snaps == nil { - return statedb.Commit(current.NumberU64(), bc.chainConfig.IsEIP158(current.Number())) + return bc.commitWithSnap(current, parentRoot, statedb) +} + +func (bc *BlockChain) commitWithSnap( + current *types.Block, parentRoot common.Hash, statedb *state.StateDB, +) (common.Hash, error) { + // blockHashes must be passed through Commit since snapshots are based on the + // block hash. + blockHashes := snapshot.WithBlockHashes(current.Hash(), current.ParentHash()) + root, err := statedb.Commit(current.NumberU64(), bc.chainConfig.IsEIP158(current.Number()), blockHashes) + if err != nil { + return common.Hash{}, err + } + // Upstream does not perform a snapshot update if the root is the same as the + // parent root, however here the snapshots are based on the block hash, so + // this update is necessary. Note blockHashes are passed here as well. + if bc.snaps != nil && root == parentRoot { + if err := bc.snaps.Update(root, parentRoot, nil, nil, nil, blockHashes); err != nil { + return common.Hash{}, err + } } - return statedb.CommitWithSnap(current.NumberU64(), bc.chainConfig.IsEIP158(current.Number()), bc.snaps, current.Hash(), current.ParentHash()) + return root, nil } // initSnapshot instantiates a Snapshot instance and adds it to [bc] diff --git a/core/blockchain_log_test.go b/core/blockchain_log_test.go index 7885ad2378..f5cf2aafc9 100644 --- a/core/blockchain_log_test.go +++ b/core/blockchain_log_test.go @@ -8,14 +8,14 @@ import ( "strings" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 11b81e39eb..3a6b7f5ce6 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -29,6 +29,10 @@ package core import ( "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/constants" @@ -39,10 +43,6 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/contracts/feemanager" "github.com/ava-labs/subnet-evm/precompile/contracts/rewardmanager" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/event" ) // CurrentHeader retrieves the current head header of the canonical chain. The diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index b05c34a0fc..fb00cec5af 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -34,14 +34,14 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index 5063f981ad..dec6dffcde 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -38,14 +38,14 @@ import ( "strings" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" ) // snapshotTestBasic wraps the common testing fields in the snapshot tests. diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 528a545695..0ddab0a3b9 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -10,17 +10,17 @@ import ( "testing" "github.com/ava-labs/avalanchego/upgrade" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/eth/tracers/logger" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/state/pruner" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/logger" - "github.com/ethereum/go-ethereum/ethdb" "github.com/holiman/uint256" ) diff --git a/core/bloom_indexer.go b/core/bloom_indexer.go index a1f5b3f5e9..b2100d6355 100644 --- a/core/bloom_indexer.go +++ b/core/bloom_indexer.go @@ -20,12 +20,12 @@ import ( "context" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/bitutil" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/core/bloombits" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/bitutil" - "github.com/ethereum/go-ethereum/ethdb" ) const ( diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go index 532bc7af93..94bbb59c6b 100644 --- a/core/bloombits/matcher.go +++ b/core/bloombits/matcher.go @@ -36,8 +36,8 @@ import ( "sync/atomic" "time" - "github.com/ethereum/go-ethereum/common/bitutil" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common/bitutil" + "github.com/ava-labs/libevm/crypto" ) // bloomIndexes represents the bit indexes inside the bloom filter that belong diff --git a/core/bloombits/matcher_test.go b/core/bloombits/matcher_test.go index c095ec31e4..04318f3489 100644 --- a/core/bloombits/matcher_test.go +++ b/core/bloombits/matcher_test.go @@ -33,7 +33,7 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) const testSectionSize = 4096 diff --git a/core/chain_indexer.go b/core/chain_indexer.go index a7a2f945f2..ce0d7e20cd 100644 --- a/core/chain_indexer.go +++ b/core/chain_indexer.go @@ -35,12 +35,12 @@ import ( "sync/atomic" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" ) // ChainIndexerBackend defines the methods needed to process chain segments in diff --git a/core/chain_indexer_test.go b/core/chain_indexer_test.go index 17491b8f08..b47c4af282 100644 --- a/core/chain_indexer_test.go +++ b/core/chain_indexer_test.go @@ -35,9 +35,9 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" ) // Runs multiple tests with randomized parameters. diff --git a/core/chain_makers.go b/core/chain_makers.go index f76c3a4b01..68e3c0a562 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -30,6 +30,10 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/dummy" @@ -39,10 +43,6 @@ import ( "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" "github.com/holiman/uint256" ) diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 12a3b3eab4..ad819b7bee 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -30,14 +30,14 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" ) func ExampleGenerateChain() { diff --git a/core/events.go b/core/events.go index 6544585c2a..dc85101f72 100644 --- a/core/events.go +++ b/core/events.go @@ -27,8 +27,8 @@ package core import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" ) // NewTxsEvent is posted when a batch of transactions enter the transaction pool. diff --git a/core/evm.go b/core/evm.go index 108faf5f4a..19796055bf 100644 --- a/core/evm.go +++ b/core/evm.go @@ -30,16 +30,16 @@ import ( "bytes" "math/big" + "github.com/ava-labs/libevm/common" + ethtypes "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" "github.com/ava-labs/subnet-evm/core/extstate" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/predicate" - "github.com/ethereum/go-ethereum/common" - gethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/log" "github.com/holiman/uint256" ) @@ -152,7 +152,7 @@ func newEVMBlockContext(header *types.Header, chain ChainContext, author *common BaseFee: baseFee, BlobBaseFee: blobBaseFee, GasLimit: header.GasLimit, - Header: &gethtypes.Header{ + Header: ðtypes.Header{ Number: new(big.Int).Set(header.Number), Time: header.Time, Extra: extra, diff --git a/core/extstate/statedb.go b/core/extstate/statedb.go index dc85c921e0..def7860c2d 100644 --- a/core/extstate/statedb.go +++ b/core/extstate/statedb.go @@ -4,17 +4,18 @@ package extstate import ( + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/predicate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" ) type VmStateDB interface { vm.StateDB + Logs() []*types.Log + GetTxHash() common.Hash - GetLogData() (topics [][]common.Hash, data [][]byte) } type StateDB struct { @@ -31,6 +32,16 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d s.VmStateDB.Prepare(rules, sender, coinbase, dst, precompiles, list) } +// GetLogData returns the underlying topics and data from each log included in the StateDB +// Test helper function. +func (s *StateDB) GetLogData() (topics [][]common.Hash, data [][]byte) { + for _, log := range s.Logs() { + topics = append(topics, log.Topics) + data = append(data, common.CopyBytes(log.Data)) + } + return topics, data +} + // GetPredicateStorageSlots returns the storage slots associated with the address, index pair. // A list of access tuples can be included within transaction types post EIP-2930. The address // is declared directly on the access tuple and the index is the i'th occurrence of an access diff --git a/core/extstate/test_statedb.go b/core/extstate/test_statedb.go index f97d76e4e1..62cd5d8bda 100644 --- a/core/extstate/test_statedb.go +++ b/core/extstate/test_statedb.go @@ -5,10 +5,10 @@ package extstate import ( "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) diff --git a/core/gen_genesis.go b/core/gen_genesis.go index 03f7c6fe42..e4f9c23fd4 100644 --- a/core/gen_genesis.go +++ b/core/gen_genesis.go @@ -8,10 +8,10 @@ import ( "math/big" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/params" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/params" ) var _ = (*genesisSpecMarshaling)(nil) diff --git a/core/genesis.go b/core/genesis.go index df461a0c4e..a918057248 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -33,19 +33,19 @@ import ( "math/big" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/triedb/pathdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" "github.com/holiman/uint256" ) @@ -230,8 +230,8 @@ func (g *Genesis) trieConfig() *triedb.Config { return nil } return &triedb.Config{ - PathDB: pathdb.Defaults, - IsVerkle: true, + DBOverride: pathdb.Defaults.BackendConstructor, + IsVerkle: true, } } diff --git a/core/genesis_test.go b/core/genesis_test.go index 30bdfeaea4..2f71821dd2 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -33,6 +33,11 @@ import ( "reflect" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" @@ -40,14 +45,9 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/contracts/deployerallowlist" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/triedb/pathdb" "github.com/ava-labs/subnet-evm/utils" "github.com/davecgh/go-spew/spew" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -351,7 +351,7 @@ func newDbConfig(scheme string) *triedb.Config { if scheme == rawdb.HashScheme { return triedb.HashDefaults } - return &triedb.Config{PathDB: pathdb.Defaults} + return &triedb.Config{DBOverride: pathdb.Defaults.BackendConstructor} } func TestVerkleGenesisCommit(t *testing.T) { @@ -391,7 +391,7 @@ func TestVerkleGenesisCommit(t *testing.T) { } db := rawdb.NewMemoryDatabase() - triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults}) + triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, DBOverride: pathdb.Defaults.BackendConstructor}) block := genesis.MustCommit(db, triedb) if !bytes.Equal(block.Root().Bytes(), expected) { t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got) diff --git a/core/headerchain.go b/core/headerchain.go index ae84e03e40..981d37f547 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -33,13 +33,13 @@ import ( mrand "math/rand" "sync/atomic" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/lru" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/lru" - "github.com/ethereum/go-ethereum/ethdb" ) const ( diff --git a/core/headerchain_test.go b/core/headerchain_test.go index 5c8fc0bf8e..c11eadaed8 100644 --- a/core/headerchain_test.go +++ b/core/headerchain_test.go @@ -32,13 +32,13 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" ) func verifyUnbrokenCanonchain(bc *BlockChain) error { diff --git a/core/mkalloc.go b/core/mkalloc.go index bfb68eed28..4699743095 100644 --- a/core/mkalloc.go +++ b/core/mkalloc.go @@ -42,9 +42,9 @@ import ( "os" "strconv" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" "golang.org/x/exp/slices" ) diff --git a/core/predicate_check.go b/core/predicate_check.go index 6f379fb7eb..1656531475 100644 --- a/core/predicate_check.go +++ b/core/predicate_check.go @@ -8,12 +8,12 @@ import ( "fmt" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/predicate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" ) var ErrMissingPredicateContext = errors.New("missing predicate context") diff --git a/core/predicate_check_test.go b/core/predicate_check_test.go index fa245e152d..5dfcc43ded 100644 --- a/core/predicate_check_test.go +++ b/core/predicate_check_test.go @@ -9,10 +9,10 @@ import ( "github.com/ava-labs/avalanchego/snow/engine/snowman/block" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" ) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index eca8abfbc7..ff4a98ae92 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -32,13 +32,13 @@ import ( "errors" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) // ReadCanonicalHash retrieves the hash assigned to a canonical block number. diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index b9e1eddb4d..fe78e88643 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -25,10 +25,10 @@ import ( "reflect" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" "golang.org/x/crypto/sha3" ) diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 5d705c4b4d..3a883f6667 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -30,12 +30,12 @@ import ( "bytes" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) // ReadTxLookupEntry retrieves the positional metadata associated with a transaction diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index f887b7ea3d..666c8e32b5 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -21,11 +21,11 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/internal/blocktest" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/rlp" ) var newTestHasher = blocktest.NewHasher diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go index cd48562bcc..23861cc1a6 100644 --- a/core/rawdb/accessors_metadata.go +++ b/core/rawdb/accessors_metadata.go @@ -30,11 +30,11 @@ import ( "encoding/json" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) // ReadDatabaseVersion retrieves the version number of the database. diff --git a/core/rawdb/accessors_snapshot.go b/core/rawdb/accessors_snapshot.go index 06a136ba89..f091b63831 100644 --- a/core/rawdb/accessors_snapshot.go +++ b/core/rawdb/accessors_snapshot.go @@ -27,9 +27,9 @@ package rawdb import ( - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" ) // ReadSnapshotRoot retrieves the root of the block whose state is contained in diff --git a/core/rawdb/accessors_state.go b/core/rawdb/accessors_state.go index 31f89b0d13..e7f509bbb7 100644 --- a/core/rawdb/accessors_state.go +++ b/core/rawdb/accessors_state.go @@ -29,9 +29,9 @@ package rawdb import ( "encoding/binary" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" ) // ReadPreimage retrieves a single preimage of the provided hash. diff --git a/core/rawdb/accessors_state_sync.go b/core/rawdb/accessors_state_sync.go index 36ba9ef1bd..0781a8c142 100644 --- a/core/rawdb/accessors_state_sync.go +++ b/core/rawdb/accessors_state_sync.go @@ -7,9 +7,9 @@ import ( "encoding/binary" "github.com/ava-labs/avalanchego/utils/wrappers" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" ) // ReadSyncRoot reads the root corresponding to the main trie of an in-progress diff --git a/core/rawdb/accessors_state_sync_test.go b/core/rawdb/accessors_state_sync_test.go index 5c51eb7bf3..506e843c8b 100644 --- a/core/rawdb/accessors_state_sync_test.go +++ b/core/rawdb/accessors_state_sync_test.go @@ -6,7 +6,7 @@ package rawdb import ( "testing" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/require" ) diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index e148a4280b..742a462c7c 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -30,10 +30,10 @@ import ( "fmt" "sync" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" "golang.org/x/crypto/sha3" ) diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index 88133218b5..ede3c71e38 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -31,12 +31,12 @@ import ( "sync/atomic" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/prque" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/prque" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) type blockTxHashes struct { diff --git a/core/rawdb/chain_iterator_test.go b/core/rawdb/chain_iterator_test.go index caca8d94af..daea1834b0 100644 --- a/core/rawdb/chain_iterator_test.go +++ b/core/rawdb/chain_iterator_test.go @@ -33,8 +33,8 @@ import ( "sync" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" ) func TestChainIterator(t *testing.T) { diff --git a/core/rawdb/database.go b/core/rawdb/database.go index edf26c6427..2195ab31ac 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -33,12 +33,12 @@ import ( "path/filepath" "time" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/ethdb/leveldb" - "github.com/ethereum/go-ethereum/ethdb/memorydb" - "github.com/ethereum/go-ethereum/ethdb/pebble" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/ethdb/leveldb" + "github.com/ava-labs/libevm/ethdb/memorydb" + "github.com/ava-labs/libevm/ethdb/pebble" + "github.com/ava-labs/libevm/log" "github.com/olekukonko/tablewriter" ) diff --git a/core/rawdb/key_length_iterator.go b/core/rawdb/key_length_iterator.go index fe95d719f0..8d1a7d2f54 100644 --- a/core/rawdb/key_length_iterator.go +++ b/core/rawdb/key_length_iterator.go @@ -26,7 +26,7 @@ package rawdb -import "github.com/ethereum/go-ethereum/ethdb" +import "github.com/ava-labs/libevm/ethdb" // KeyLengthIterator is a wrapper for a database iterator that ensures only key-value pairs // with a specific key length will be returned. diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index 78d1cb4a72..8a402c1866 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -32,9 +32,9 @@ import ( "encoding/binary" "github.com/ava-labs/avalanchego/utils/wrappers" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/metrics" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" ) // The fields below define the low level database schema prefixing. diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 5dc709080c..cb9156173a 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -27,7 +27,7 @@ package rawdb import ( - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ava-labs/libevm/ethdb" ) // table is a wrapper around a database that prefixes each key access with a pre- diff --git a/core/rawdb/table_test.go b/core/rawdb/table_test.go index 9cb913c2a1..a6f4b454f6 100644 --- a/core/rawdb/table_test.go +++ b/core/rawdb/table_test.go @@ -30,7 +30,7 @@ import ( "bytes" "testing" - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ava-labs/libevm/ethdb" ) func TestTableDatabase(t *testing.T) { testTableDatabase(t, "prefix") } diff --git a/core/rlp_test.go b/core/rlp_test.go index 56fb3ce3d5..a608ac2550 100644 --- a/core/rlp_test.go +++ b/core/rlp_test.go @@ -31,12 +31,12 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" "golang.org/x/crypto/sha3" ) diff --git a/core/state/access_list.go b/core/state/access_list.go deleted file mode 100644 index d5044ccc5b..0000000000 --- a/core/state/access_list.go +++ /dev/null @@ -1,146 +0,0 @@ -// (c) 2019-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2020 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 state - -import ( - "github.com/ethereum/go-ethereum/common" -) - -type accessList struct { - addresses map[common.Address]int - slots []map[common.Hash]struct{} -} - -// ContainsAddress returns true if the address is in the access list. -func (al *accessList) ContainsAddress(address common.Address) bool { - _, ok := al.addresses[address] - return ok -} - -// Contains checks if a slot within an account is present in the access list, returning -// separate flags for the presence of the account and the slot respectively. -func (al *accessList) Contains(address common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) { - idx, ok := al.addresses[address] - if !ok { - // no such address (and hence zero slots) - return false, false - } - if idx == -1 { - // address yes, but no slots - return true, false - } - _, slotPresent = al.slots[idx][slot] - return true, slotPresent -} - -// newAccessList creates a new accessList. -func newAccessList() *accessList { - return &accessList{ - addresses: make(map[common.Address]int), - } -} - -// Copy creates an independent copy of an accessList. -func (a *accessList) Copy() *accessList { - cp := newAccessList() - for k, v := range a.addresses { - cp.addresses[k] = v - } - cp.slots = make([]map[common.Hash]struct{}, len(a.slots)) - for i, slotMap := range a.slots { - newSlotmap := make(map[common.Hash]struct{}, len(slotMap)) - for k := range slotMap { - newSlotmap[k] = struct{}{} - } - cp.slots[i] = newSlotmap - } - return cp -} - -// AddAddress adds an address to the access list, and returns 'true' if the operation -// caused a change (addr was not previously in the list). -func (al *accessList) AddAddress(address common.Address) bool { - if _, present := al.addresses[address]; present { - return false - } - al.addresses[address] = -1 - return true -} - -// AddSlot adds the specified (addr, slot) combo to the access list. -// Return values are: -// - address added -// - slot added -// For any 'true' value returned, a corresponding journal entry must be made. -func (al *accessList) AddSlot(address common.Address, slot common.Hash) (addrChange bool, slotChange bool) { - idx, addrPresent := al.addresses[address] - if !addrPresent || idx == -1 { - // Address not present, or addr present but no slots there - al.addresses[address] = len(al.slots) - slotmap := map[common.Hash]struct{}{slot: {}} - al.slots = append(al.slots, slotmap) - return !addrPresent, true - } - // There is already an (address,slot) mapping - slotmap := al.slots[idx] - if _, ok := slotmap[slot]; !ok { - slotmap[slot] = struct{}{} - // Journal add slot change - return false, true - } - // No changes required - return false, false -} - -// DeleteSlot removes an (address, slot)-tuple from the access list. -// This operation needs to be performed in the same order as the addition happened. -// This method is meant to be used by the journal, which maintains ordering of -// operations. -func (al *accessList) DeleteSlot(address common.Address, slot common.Hash) { - idx, addrOk := al.addresses[address] - // There are two ways this can fail - if !addrOk { - panic("reverting slot change, address not present in list") - } - slotmap := al.slots[idx] - delete(slotmap, slot) - // If that was the last (first) slot, remove it - // Since additions and rollbacks are always performed in order, - // we can delete the item without worrying about screwing up later indices - if len(slotmap) == 0 { - al.slots = al.slots[:idx] - al.addresses[address] = -1 - } -} - -// DeleteAddress removes an address from the access list. This operation -// needs to be performed in the same order as the addition happened. -// This method is meant to be used by the journal, which maintains ordering of -// operations. -func (al *accessList) DeleteAddress(address common.Address) { - delete(al.addresses, address) -} diff --git a/core/state/database.go b/core/state/database.go index 2e310707ac..02ffa8ce3e 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -30,17 +30,16 @@ import ( "errors" "fmt" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/lru" + ethstate "github.com/ava-labs/libevm/core/state" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/trie/utils" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/utils" - "github.com/ava-labs/subnet-evm/triedb" "github.com/crate-crypto/go-ipa/banderwagon" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/lru" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" ) const ( @@ -82,74 +81,7 @@ type Database interface { } // Trie is a Ethereum Merkle Patricia trie. -type Trie interface { - // GetKey returns the sha3 preimage of a hashed key that was previously used - // to store a value. - // - // TODO(fjl): remove this when StateTrie is removed - GetKey([]byte) []byte - - // GetAccount abstracts an account read from the trie. It retrieves the - // account blob from the trie with provided account address and decodes it - // with associated decoding algorithm. If the specified account is not in - // the trie, nil will be returned. If the trie is corrupted(e.g. some nodes - // are missing or the account blob is incorrect for decoding), an error will - // be returned. - GetAccount(address common.Address) (*types.StateAccount, error) - - // GetStorage returns the value for key stored in the trie. The value bytes - // must not be modified by the caller. If a node was not found in the database, - // a trie.MissingNodeError is returned. - GetStorage(addr common.Address, key []byte) ([]byte, error) - - // UpdateAccount abstracts an account write to the trie. It encodes the - // provided account object with associated algorithm and then updates it - // in the trie with provided address. - UpdateAccount(address common.Address, account *types.StateAccount) error - - // UpdateStorage associates key with value in the trie. If value has length zero, - // any existing value is deleted from the trie. The value bytes must not be modified - // by the caller while they are stored in the trie. If a node was not found in the - // database, a trie.MissingNodeError is returned. - UpdateStorage(addr common.Address, key, value []byte) error - - // DeleteAccount abstracts an account deletion from the trie. - DeleteAccount(address common.Address) error - - // DeleteStorage removes any existing value for key from the trie. If a node - // was not found in the database, a trie.MissingNodeError is returned. - DeleteStorage(addr common.Address, key []byte) error - - // UpdateContractCode abstracts code write to the trie. It is expected - // to be moved to the stateWriter interface when the latter is ready. - UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error - - // Hash returns the root hash of the trie. It does not write to the database and - // can be used even if the trie doesn't have one. - Hash() common.Hash - - // Commit collects all dirty nodes in the trie and replace them with the - // corresponding node hash. All collected nodes(including dirty leaves if - // collectLeaf is true) will be encapsulated into a nodeset for return. - // The returned nodeset can be nil if the trie is clean(nothing to commit). - // Once the trie is committed, it's not usable anymore. A new trie must - // be created with new root and updated trie database for following usage - Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) - - // NodeIterator returns an iterator that returns nodes of the trie. Iteration - // starts at the key after the given start key. And error will be returned - // if fails to create node iterator. - NodeIterator(startKey []byte) (trie.NodeIterator, error) - - // Prove constructs a Merkle proof for key. The result contains all encoded nodes - // on the path to the value at key. The value itself is also included in the last - // node and can be retrieved by verifying the proof. - // - // If the trie does not contain a value for key, the returned proof contains all - // nodes of the longest existing prefix of the key (at least the root), ending - // with the node that proves the absence of the key. - Prove(key []byte, proofDb ethdb.KeyValueWriter) error -} +type Trie = ethstate.Trie // NewDatabase creates a backing store for state. The returned database is safe for // concurrent use, but does not retain any recent trie nodes in memory. To keep some diff --git a/core/state/dump.go b/core/state/dump.go index ee02e4b40c..deac606017 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -27,219 +27,12 @@ package state import ( - "encoding/json" - "fmt" - "time" - - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" + ethstate "github.com/ava-labs/libevm/core/state" ) -// DumpConfig is a set of options to control what portions of the state will be -// iterated and collected. -type DumpConfig struct { - SkipCode bool - SkipStorage bool - OnlyWithAddresses bool - Start []byte - Max uint64 -} - -// DumpCollector interface which the state trie calls during iteration -type DumpCollector interface { - // OnRoot is called with the state root - OnRoot(common.Hash) - // OnAccount is called once for each account in the trie - OnAccount(*common.Address, DumpAccount) -} - -// DumpAccount represents an account in the state. -type DumpAccount struct { - Balance string `json:"balance"` - Nonce uint64 `json:"nonce"` - Root hexutil.Bytes `json:"root"` - CodeHash hexutil.Bytes `json:"codeHash"` - Code hexutil.Bytes `json:"code,omitempty"` - Storage map[common.Hash]string `json:"storage,omitempty"` - Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode - AddressHash hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key - -} - -// Dump represents the full dump in a collected format, as one large map. -type Dump struct { - Root string `json:"root"` - Accounts map[string]DumpAccount `json:"accounts"` - // Next can be set to represent that this dump is only partial, and Next - // is where an iterator should be positioned in order to continue the dump. - Next []byte `json:"next,omitempty"` // nil if no more accounts -} - -// OnRoot implements DumpCollector interface -func (d *Dump) OnRoot(root common.Hash) { - d.Root = fmt.Sprintf("%x", root) -} - -// OnAccount implements DumpCollector interface -func (d *Dump) OnAccount(addr *common.Address, account DumpAccount) { - if addr == nil { - d.Accounts[fmt.Sprintf("pre(%s)", account.AddressHash)] = account - } - if addr != nil { - d.Accounts[(*addr).String()] = account - } -} - -// iterativeDump is a DumpCollector-implementation which dumps output line-by-line iteratively. -type iterativeDump struct { - *json.Encoder -} - -// OnAccount implements DumpCollector interface -func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) { - dumpAccount := &DumpAccount{ - Balance: account.Balance, - Nonce: account.Nonce, - Root: account.Root, - CodeHash: account.CodeHash, - Code: account.Code, - Storage: account.Storage, - AddressHash: account.AddressHash, - Address: addr, - } - d.Encode(dumpAccount) -} - -// OnRoot implements DumpCollector interface -func (d iterativeDump) OnRoot(root common.Hash) { - d.Encode(struct { - Root common.Hash `json:"root"` - }{root}) -} - -// DumpToCollector iterates the state according to the given options and inserts -// the items into a collector for aggregation or serialization. -func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []byte) { - // Sanitize the input to allow nil configs - if conf == nil { - conf = new(DumpConfig) - } - var ( - missingPreimages int - accounts uint64 - start = time.Now() - logged = time.Now() - ) - log.Info("Trie dumping started", "root", s.trie.Hash()) - c.OnRoot(s.trie.Hash()) - - trieIt, err := s.trie.NodeIterator(conf.Start) - if err != nil { - log.Error("Trie dumping error", "err", err) - return nil - } - it := trie.NewIterator(trieIt) - for it.Next() { - var data types.StateAccount - if err := rlp.DecodeBytes(it.Value, &data); err != nil { - panic(err) - } - var ( - account = DumpAccount{ - Balance: data.Balance.String(), - Nonce: data.Nonce, - Root: data.Root[:], - CodeHash: data.CodeHash, - AddressHash: it.Key, - } - address *common.Address - addr common.Address - addrBytes = s.trie.GetKey(it.Key) - ) - if addrBytes == nil { - missingPreimages++ - if conf.OnlyWithAddresses { - continue - } - } else { - addr = common.BytesToAddress(addrBytes) - address = &addr - account.Address = address - } - obj := newObject(s, addr, &data) - if !conf.SkipCode { - account.Code = obj.Code() - } - if !conf.SkipStorage { - account.Storage = make(map[common.Hash]string) - tr, err := obj.getTrie() - if err != nil { - log.Error("Failed to load storage trie", "err", err) - continue - } - trieIt, err := tr.NodeIterator(nil) - if err != nil { - log.Error("Failed to create trie iterator", "err", err) - continue - } - storageIt := trie.NewIterator(trieIt) - for storageIt.Next() { - _, content, _, err := rlp.Split(storageIt.Value) - if err != nil { - log.Error("Failed to decode the value returned by iterator", "error", err) - continue - } - account.Storage[common.BytesToHash(s.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(content) - } - } - c.OnAccount(address, account) - accounts++ - if time.Since(logged) > 8*time.Second { - log.Info("Trie dumping in progress", "at", it.Key, "accounts", accounts, - "elapsed", common.PrettyDuration(time.Since(start))) - logged = time.Now() - } - if conf.Max > 0 && accounts >= conf.Max { - if it.Next() { - nextKey = it.Key - } - break - } - } - if missingPreimages > 0 { - log.Warn("Dump incomplete due to missing preimages", "missing", missingPreimages) - } - log.Info("Trie dumping complete", "accounts", accounts, - "elapsed", common.PrettyDuration(time.Since(start))) - - return nextKey -} - -// RawDump returns the state. If the processing is aborted e.g. due to options -// reaching Max, the `Next` key is set on the returned Dump. -func (s *StateDB) RawDump(opts *DumpConfig) Dump { - dump := &Dump{ - Accounts: make(map[string]DumpAccount), - } - dump.Next = s.DumpToCollector(dump, opts) - return *dump -} - -// Dump returns a JSON string representing the entire state as a single json-object -func (s *StateDB) Dump(opts *DumpConfig) []byte { - dump := s.RawDump(opts) - json, err := json.MarshalIndent(dump, "", " ") - if err != nil { - log.Error("Error dumping state", "err", err) - } - return json -} - -// IterativeDump dumps out accounts as json-objects, delimited by linebreaks on stdout -func (s *StateDB) IterativeDump(opts *DumpConfig, output *json.Encoder) { - s.DumpToCollector(iterativeDump{output}, opts) -} +type ( + DumpConfig = ethstate.DumpConfig + DumpCollector = ethstate.DumpCollector + DumpAccount = ethstate.DumpAccount + Dump = ethstate.Dump +) diff --git a/core/state/journal.go b/core/state/journal.go deleted file mode 100644 index 5e19f2df79..0000000000 --- a/core/state/journal.go +++ /dev/null @@ -1,310 +0,0 @@ -// (c) 2019-2020, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 state - -import ( - "github.com/ethereum/go-ethereum/common" - "github.com/holiman/uint256" -) - -// journalEntry is a modification entry in the state change journal that can be -// reverted on demand. -type journalEntry interface { - // revert undoes the changes introduced by this journal entry. - revert(*StateDB) - - // dirtied returns the Ethereum address modified by this journal entry. - dirtied() *common.Address -} - -// journal contains the list of state modifications applied since the last state -// commit. These are tracked to be able to be reverted in the case of an execution -// exception or request for reversal. -type journal struct { - entries []journalEntry // Current changes tracked by the journal - dirties map[common.Address]int // Dirty accounts and the number of changes -} - -// newJournal creates a new initialized journal. -func newJournal() *journal { - return &journal{ - dirties: make(map[common.Address]int), - } -} - -// append inserts a new modification entry to the end of the change journal. -func (j *journal) append(entry journalEntry) { - j.entries = append(j.entries, entry) - if addr := entry.dirtied(); addr != nil { - j.dirties[*addr]++ - } -} - -// revert undoes a batch of journalled modifications along with any reverted -// dirty handling too. -func (j *journal) revert(statedb *StateDB, snapshot int) { - for i := len(j.entries) - 1; i >= snapshot; i-- { - // Undo the changes made by the operation - j.entries[i].revert(statedb) - - // Drop any dirty tracking induced by the change - if addr := j.entries[i].dirtied(); addr != nil { - if j.dirties[*addr]--; j.dirties[*addr] == 0 { - delete(j.dirties, *addr) - } - } - } - j.entries = j.entries[:snapshot] -} - -// dirty explicitly sets an address to dirty, even if the change entries would -// otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD -// precompile consensus exception. -func (j *journal) dirty(addr common.Address) { - j.dirties[addr]++ -} - -// length returns the current number of entries in the journal. -func (j *journal) length() int { - return len(j.entries) -} - -type ( - // Changes to the account trie. - createObjectChange struct { - account *common.Address - } - resetObjectChange struct { - account *common.Address - prev *stateObject - prevdestruct bool - prevAccount []byte - prevStorage map[common.Hash][]byte - - prevAccountOriginExist bool - prevAccountOrigin []byte - prevStorageOrigin map[common.Hash][]byte - } - selfDestructChange struct { - account *common.Address - prev bool // whether account had already self-destructed - prevbalance *uint256.Int - } - - // Changes to individual accounts. - balanceChange struct { - account *common.Address - prev *uint256.Int - } - nonceChange struct { - account *common.Address - prev uint64 - } - storageChange struct { - account *common.Address - key, prevalue common.Hash - } - codeChange struct { - account *common.Address - prevcode, prevhash []byte - } - - // Changes to other state values. - refundChange struct { - prev uint64 - } - addLogChange struct { - txhash common.Hash - } - addPreimageChange struct { - hash common.Hash - } - touchChange struct { - account *common.Address - } - // Changes to the access list - accessListAddAccountChange struct { - address *common.Address - } - accessListAddSlotChange struct { - address *common.Address - slot *common.Hash - } - - transientStorageChange struct { - account *common.Address - key, prevalue common.Hash - } -) - -func (ch createObjectChange) revert(s *StateDB) { - delete(s.stateObjects, *ch.account) - delete(s.stateObjectsDirty, *ch.account) -} - -func (ch createObjectChange) dirtied() *common.Address { - return ch.account -} - -func (ch resetObjectChange) revert(s *StateDB) { - s.setStateObject(ch.prev) - if !ch.prevdestruct { - delete(s.stateObjectsDestruct, ch.prev.address) - } - if ch.prevAccount != nil { - s.accounts[ch.prev.addrHash] = ch.prevAccount - } - if ch.prevStorage != nil { - s.storages[ch.prev.addrHash] = ch.prevStorage - } - if ch.prevAccountOriginExist { - s.accountsOrigin[ch.prev.address] = ch.prevAccountOrigin - } - if ch.prevStorageOrigin != nil { - s.storagesOrigin[ch.prev.address] = ch.prevStorageOrigin - } -} - -func (ch resetObjectChange) dirtied() *common.Address { - return ch.account -} - -func (ch selfDestructChange) revert(s *StateDB) { - obj := s.getStateObject(*ch.account) - if obj != nil { - obj.selfDestructed = ch.prev - obj.setBalance(ch.prevbalance) - } -} - -func (ch selfDestructChange) dirtied() *common.Address { - return ch.account -} - -var ripemd = common.HexToAddress("0000000000000000000000000000000000000003") - -func (ch touchChange) revert(s *StateDB) { -} - -func (ch touchChange) dirtied() *common.Address { - return ch.account -} - -func (ch balanceChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setBalance(ch.prev) -} - -func (ch balanceChange) dirtied() *common.Address { - return ch.account -} - -func (ch nonceChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setNonce(ch.prev) -} - -func (ch nonceChange) dirtied() *common.Address { - return ch.account -} - -func (ch codeChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) -} - -func (ch codeChange) dirtied() *common.Address { - return ch.account -} - -func (ch storageChange) revert(s *StateDB) { - s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) -} - -func (ch storageChange) dirtied() *common.Address { - return ch.account -} - -func (ch transientStorageChange) revert(s *StateDB) { - s.setTransientState(*ch.account, ch.key, ch.prevalue) -} - -func (ch transientStorageChange) dirtied() *common.Address { - return nil -} - -func (ch refundChange) revert(s *StateDB) { - s.refund = ch.prev -} - -func (ch refundChange) dirtied() *common.Address { - return nil -} - -func (ch addLogChange) revert(s *StateDB) { - logs := s.logs[ch.txhash] - if len(logs) == 1 { - delete(s.logs, ch.txhash) - } else { - s.logs[ch.txhash] = logs[:len(logs)-1] - } - s.logSize-- -} - -func (ch addLogChange) dirtied() *common.Address { - return nil -} - -func (ch addPreimageChange) revert(s *StateDB) { - delete(s.preimages, ch.hash) -} - -func (ch addPreimageChange) dirtied() *common.Address { - return nil -} - -func (ch accessListAddAccountChange) revert(s *StateDB) { - /* - One important invariant here, is that whenever a (addr, slot) is added, if the - addr is not already present, the add causes two journal entries: - - one for the address, - - one for the (address,slot) - Therefore, when unrolling the change, we can always blindly delete the - (addr) at this point, since no storage adds can remain when come upon - a single (addr) change. - */ - s.accessList.DeleteAddress(*ch.address) -} - -func (ch accessListAddAccountChange) dirtied() *common.Address { - return nil -} - -func (ch accessListAddSlotChange) revert(s *StateDB) { - s.accessList.DeleteSlot(*ch.address, *ch.slot) -} - -func (ch accessListAddSlotChange) dirtied() *common.Address { - return nil -} diff --git a/core/state/metrics.go b/core/state/metrics.go deleted file mode 100644 index 5af6243c98..0000000000 --- a/core/state/metrics.go +++ /dev/null @@ -1,47 +0,0 @@ -// (c) 2019-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2021 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 state - -import "github.com/ava-labs/subnet-evm/metrics" - -var ( - accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil) - storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil) - accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil) - storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil) - accountTrieUpdatedMeter = metrics.NewRegisteredMeter("state/update/accountnodes", nil) - storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil) - accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil) - storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil) - - slotDeletionMaxCount = metrics.NewRegisteredGauge("state/delete/storage/max/slot", nil) - slotDeletionMaxSize = metrics.NewRegisteredGauge("state/delete/storage/max/size", nil) - slotDeletionTimer = metrics.NewRegisteredResettingTimer("state/delete/storage/timer", nil) - slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil) - slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil) - slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil) -) diff --git a/core/state/pruner/bloom.go b/core/state/pruner/bloom.go index 060a952f37..fe741461f4 100644 --- a/core/state/pruner/bloom.go +++ b/core/state/pruner/bloom.go @@ -31,9 +31,9 @@ import ( "errors" "os" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" bloomfilter "github.com/holiman/bloomfilter/v2" ) diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 96e27d28cd..0ad5ee464b 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -37,22 +37,22 @@ import ( "strings" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) const ( // stateBloomFilePrefix is the filename prefix of state bloom filter. stateBloomFilePrefix = "statebloom" - // stateBloomFilePrefix is the filename suffix of state bloom filter. + // stateBloomFileSuffix is the filename suffix of state bloom filter. stateBloomFileSuffix = "bf.gz" // stateBloomFileTempSuffix is the filename suffix of state bloom filter diff --git a/core/state/snapshot/context.go b/core/state/snapshot/context.go index 35b22c6ea3..45acfbba29 100644 --- a/core/state/snapshot/context.go +++ b/core/state/snapshot/context.go @@ -34,8 +34,8 @@ import ( "golang.org/x/exp/slog" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" ) // generatorStats is a collection of statistics gathered by the snapshot generator diff --git a/core/state/snapshot/conversion.go b/core/state/snapshot/conversion.go index 91bbae1b23..d48dadb853 100644 --- a/core/state/snapshot/conversion.go +++ b/core/state/snapshot/conversion.go @@ -35,13 +35,13 @@ import ( "sync" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) // trieKV represents a trie key-value pair @@ -92,7 +92,7 @@ func GenerateTrie(snaptree *Tree, root common.Hash, src ethdb.Database, dst ethd rawdb.WriteCode(dst, codeHash, code) } // Then migrate all storage trie nodes into the tmp db. - storageIt, err := snaptree.StorageIterator(root, accountHash, common.Hash{}, false) + storageIt, err := snaptree.StorageIterator(root, accountHash, common.Hash{}) if err != nil { return common.Hash{}, err } diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index 62175cea25..257315180e 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -35,9 +35,9 @@ import ( "sync/atomic" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" bloomfilter "github.com/holiman/bloomfilter/v2" "golang.org/x/exp/slices" ) diff --git a/core/state/snapshot/difflayer_test.go b/core/state/snapshot/difflayer_test.go index 08bbf4104d..d312864b1f 100644 --- a/core/state/snapshot/difflayer_test.go +++ b/core/state/snapshot/difflayer_test.go @@ -32,10 +32,10 @@ import ( "math/rand" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb/memorydb" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb/memorydb" ) func copyDestructs(destructs map[common.Hash]struct{}) map[common.Hash]struct{} { diff --git a/core/state/snapshot/disklayer.go b/core/state/snapshot/disklayer.go index 478b6716b1..817eb7d939 100644 --- a/core/state/snapshot/disklayer.go +++ b/core/state/snapshot/disklayer.go @@ -31,13 +31,13 @@ import ( "sync" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/rlp" ) // diskLayer is a low level persistent snapshot built on top of a key-value store. diff --git a/core/state/snapshot/disklayer_test.go b/core/state/snapshot/disklayer_test.go index c5ebf65f86..023ac923e8 100644 --- a/core/state/snapshot/disklayer_test.go +++ b/core/state/snapshot/disklayer_test.go @@ -30,10 +30,10 @@ import ( "bytes" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb/memorydb" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb/memorydb" - "github.com/ethereum/go-ethereum/rlp" ) // reverse reverses the contents of a byte slice. It's used to update random accs @@ -121,7 +121,7 @@ func TestDiskMerge(t *testing.T) { base.Storage(conNukeCache, conNukeCacheSlot) // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffBlockHash, diffRoot, baseBlockHash, map[common.Hash]struct{}{ + if err := snaps.UpdateWithBlockHashes(diffBlockHash, diffRoot, baseBlockHash, map[common.Hash]struct{}{ accDelNoCache: {}, accDelCache: {}, conNukeNoCache: {}, @@ -341,7 +341,7 @@ func TestDiskPartialMerge(t *testing.T) { assertStorage(conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:]) // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffBlockHash, diffRoot, baseBlockHash, map[common.Hash]struct{}{ + if err := snaps.UpdateWithBlockHashes(diffBlockHash, diffRoot, baseBlockHash, map[common.Hash]struct{}{ accDelNoCache: {}, accDelCache: {}, conNukeNoCache: {}, @@ -460,7 +460,7 @@ func TestDiskGeneratorPersistence(t *testing.T) { dl := snaps.disklayer() dl.genMarker = genMarker // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffBlockHash, diffRoot, baseBlockHash, nil, map[common.Hash][]byte{ + if err := snaps.UpdateWithBlockHashes(diffBlockHash, diffRoot, baseBlockHash, nil, map[common.Hash][]byte{ accTwo: accTwo[:], }, nil); err != nil { t.Fatalf("failed to update snapshot tree: %v", err) @@ -478,7 +478,7 @@ func TestDiskGeneratorPersistence(t *testing.T) { } // Test scenario 2, the disk layer is fully generated // Modify or delete some accounts, flatten everything onto disk - if err := snaps.Update(diffTwoBlockHash, diffTwoRoot, diffBlockHash, nil, map[common.Hash][]byte{ + if err := snaps.UpdateWithBlockHashes(diffTwoBlockHash, diffTwoRoot, diffBlockHash, nil, map[common.Hash][]byte{ accThree: accThree.Bytes(), }, map[common.Hash]map[common.Hash][]byte{ accThree: {accThreeSlot: accThreeSlot.Bytes()}, diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 35539ec3a7..d8daf5d678 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -31,15 +31,15 @@ import ( "fmt" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) const ( diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index d50b31211f..6452850bba 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -32,17 +32,17 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/trie/trienode" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/triedb/hashdb" "github.com/ava-labs/subnet-evm/triedb/pathdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) @@ -176,9 +176,9 @@ func newHelper(scheme string) *testHelper { diskdb := rawdb.NewMemoryDatabase() config := &triedb.Config{} if scheme == rawdb.PathScheme { - config.PathDB = &pathdb.Config{} // disable caching + config.DBOverride = pathdb.Config{}.BackendConstructor // disable caching } else { - config.HashDB = &hashdb.Config{} // disable caching + config.DBOverride = hashdb.Config{}.BackendConstructor // disable caching } triedb := triedb.NewDatabase(diskdb, config) accTrie, _ := trie.NewStateTrie(trie.StateTrieID(types.EmptyRootHash), triedb) diff --git a/core/state/snapshot/iterator.go b/core/state/snapshot/iterator.go index f75fee23c9..fc62749843 100644 --- a/core/state/snapshot/iterator.go +++ b/core/state/snapshot/iterator.go @@ -31,9 +31,10 @@ import ( "fmt" "sort" + "github.com/ava-labs/libevm/common" + ethsnapshot "github.com/ava-labs/libevm/core/state/snapshot" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" ) // Iterator is an iterator to step over all the accounts or the specific @@ -69,13 +70,7 @@ type AccountIterator interface { // StorageIterator is an iterator to step over the specific storage in a snapshot, // which may or may not be composed of multiple layers. -type StorageIterator interface { - Iterator - - // Slot returns the storage slot the iterator is currently at. An error will - // be returned if the iterator becomes invalid - Slot() []byte -} +type StorageIterator = ethsnapshot.StorageIterator // diffAccountIterator is an account iterator that steps over the accounts (both // live and deleted) contained within a single diff layer. Higher order iterators diff --git a/core/state/snapshot/iterator_binary.go b/core/state/snapshot/iterator_binary.go index cff012402c..68f95901f7 100644 --- a/core/state/snapshot/iterator_binary.go +++ b/core/state/snapshot/iterator_binary.go @@ -29,7 +29,7 @@ package snapshot import ( "bytes" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) // binaryIterator is a simplistic iterator to step over the accounts or storage diff --git a/core/state/snapshot/iterator_fast.go b/core/state/snapshot/iterator_fast.go index 4e324ee28b..d8dda5f71c 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -31,7 +31,7 @@ import ( "fmt" "sort" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "golang.org/x/exp/slices" ) diff --git a/core/state/snapshot/iterator_test.go b/core/state/snapshot/iterator_test.go index 6e5b6d8836..79d287b394 100644 --- a/core/state/snapshot/iterator_test.go +++ b/core/state/snapshot/iterator_test.go @@ -34,8 +34,8 @@ import ( "math/rand" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" ) // TestAccountIteratorBasics tests some simple single-layer(diff and disk) iteration @@ -222,13 +222,13 @@ func TestAccountIteratorTraversal(t *testing.T) { // Create a snapshot tree with a single empty disk layer with the specified root and block hash snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, randomAccountSet("0xbb", "0xdd", "0xf0"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, randomAccountSet("0xcc", "0xf0", "0xff"), nil) // Verify the single and multi-layer iterators @@ -263,13 +263,13 @@ func TestStorageIteratorTraversal(t *testing.T) { // Create an empty base layer and a snapshot tree out of it snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), + snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), + snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04", "0x05", "0x06"}}, nil)) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), + snaps.UpdateWithBlockHashes(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil)) // Verify the single and multi-layer iterators @@ -279,7 +279,7 @@ func TestStorageIteratorTraversal(t *testing.T) { verifyIterator(t, 3, diffIter, verifyNothing) verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage) - it, _ := snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.Hash{}, false) + it, _ := snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 6, it, verifyStorage) it.Release() @@ -296,7 +296,7 @@ func TestStorageIteratorTraversal(t *testing.T) { } verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage) - it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.Hash{}, false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 6, it, verifyStorage) it.Release() } @@ -342,14 +342,14 @@ func TestAccountIteratorTraversalValues(t *testing.T) { } } // Assemble a stack of snapshots from the account layers - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, a, nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, b, nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, c, nil) - snaps.Update(common.HexToHash("0x05"), common.HexToHash("0xff05"), common.HexToHash("0x04"), nil, d, nil) - snaps.Update(common.HexToHash("0x06"), common.HexToHash("0xff06"), common.HexToHash("0x05"), nil, e, nil) - snaps.Update(common.HexToHash("0x07"), common.HexToHash("0xff07"), common.HexToHash("0x06"), nil, f, nil) - snaps.Update(common.HexToHash("0x08"), common.HexToHash("0xff08"), common.HexToHash("0x07"), nil, g, nil) - snaps.Update(common.HexToHash("0x09"), common.HexToHash("0xff09"), common.HexToHash("0x08"), nil, h, nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, a, nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, b, nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, c, nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0x05"), common.HexToHash("0xff05"), common.HexToHash("0x04"), nil, d, nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0x06"), common.HexToHash("0xff06"), common.HexToHash("0x05"), nil, e, nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0x07"), common.HexToHash("0xff07"), common.HexToHash("0x06"), nil, f, nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0x08"), common.HexToHash("0xff08"), common.HexToHash("0x07"), nil, g, nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0x09"), common.HexToHash("0xff09"), common.HexToHash("0x08"), nil, h, nil) it, _ := snaps.AccountIterator(common.HexToHash("0xff09"), common.Hash{}, false) head := snaps.Snapshot(common.HexToHash("0xff09")) @@ -437,16 +437,16 @@ func TestStorageIteratorTraversalValues(t *testing.T) { } } // Assemble a stack of snapshots from the account layers - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), wrapStorage(a)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), wrapStorage(b)) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), wrapStorage(c)) - snaps.Update(common.HexToHash("0x05"), common.HexToHash("0xff05"), common.HexToHash("0x04"), nil, randomAccountSet("0xaa"), wrapStorage(d)) - snaps.Update(common.HexToHash("0x06"), common.HexToHash("0xff06"), common.HexToHash("0x05"), nil, randomAccountSet("0xaa"), wrapStorage(e)) - snaps.Update(common.HexToHash("0x07"), common.HexToHash("0xff07"), common.HexToHash("0x06"), nil, randomAccountSet("0xaa"), wrapStorage(e)) - snaps.Update(common.HexToHash("0x08"), common.HexToHash("0xff08"), common.HexToHash("0x07"), nil, randomAccountSet("0xaa"), wrapStorage(g)) - snaps.Update(common.HexToHash("0x09"), common.HexToHash("0xff09"), common.HexToHash("0x08"), nil, randomAccountSet("0xaa"), wrapStorage(h)) - - it, _ := snaps.StorageIterator(common.HexToHash("0xff09"), common.HexToHash("0xaa"), common.Hash{}, false) + snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), wrapStorage(a)) + snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), wrapStorage(b)) + snaps.UpdateWithBlockHashes(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), wrapStorage(c)) + snaps.UpdateWithBlockHashes(common.HexToHash("0x05"), common.HexToHash("0xff05"), common.HexToHash("0x04"), nil, randomAccountSet("0xaa"), wrapStorage(d)) + snaps.UpdateWithBlockHashes(common.HexToHash("0x06"), common.HexToHash("0xff06"), common.HexToHash("0x05"), nil, randomAccountSet("0xaa"), wrapStorage(e)) + snaps.UpdateWithBlockHashes(common.HexToHash("0x07"), common.HexToHash("0xff07"), common.HexToHash("0x06"), nil, randomAccountSet("0xaa"), wrapStorage(e)) + snaps.UpdateWithBlockHashes(common.HexToHash("0x08"), common.HexToHash("0xff08"), common.HexToHash("0x07"), nil, randomAccountSet("0xaa"), wrapStorage(g)) + snaps.UpdateWithBlockHashes(common.HexToHash("0x09"), common.HexToHash("0xff09"), common.HexToHash("0x08"), nil, randomAccountSet("0xaa"), wrapStorage(h)) + + it, _ := snaps.StorageIterator(common.HexToHash("0xff09"), common.HexToHash("0xaa"), common.Hash{}) head := snaps.Snapshot(common.HexToHash("0xff09")) for it.Next() { hash := it.Hash() @@ -474,7 +474,7 @@ func TestStorageIteratorTraversalValues(t *testing.T) { } } - it, _ = snaps.StorageIterator(common.HexToHash("0xff09"), common.HexToHash("0xaa"), common.Hash{}, false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff09"), common.HexToHash("0xaa"), common.Hash{}) for it.Next() { hash := it.Hash() want, err := head.Storage(common.HexToHash("0xaa"), hash) @@ -503,7 +503,7 @@ func TestAccountIteratorLargeTraversal(t *testing.T) { // Build up a large stack of snapshots snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) for i := 1; i < 128; i++ { - snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0xff%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) + snaps.UpdateWithBlockHashes(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0xff%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) } // Iterate the entire stack and ensure everything is hit only once head := snaps.Snapshot(common.HexToHash("0xff80")) @@ -543,13 +543,13 @@ func TestAccountIteratorFlattening(t *testing.T) { // Create an empty base layer and a snapshot tree out of it snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) // Create a stack of diffs on top - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, randomAccountSet("0xbb", "0xdd", "0xf0"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, randomAccountSet("0xcc", "0xf0", "0xff"), nil) // Create an iterator and flatten the data from underneath it @@ -568,13 +568,13 @@ func TestAccountIteratorFlattening(t *testing.T) { func TestAccountIteratorSeek(t *testing.T) { // Create a snapshot stack with some initial data snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, randomAccountSet("0xbb", "0xdd", "0xf0"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, randomAccountSet("0xcc", "0xf0", "0xff"), nil) // Account set is now @@ -623,13 +623,13 @@ func TestStorageIteratorSeek(t *testing.T) { // Create a snapshot stack with some initial data snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x05", "0x06"}}, nil)) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x05", "0x08"}}, nil)) // Account set is now @@ -637,35 +637,35 @@ func TestStorageIteratorSeek(t *testing.T) { // 03: 01, 02, 03, 05 (, 05), 06 // 04: 01(, 01), 02, 03, 05(, 05, 05), 06, 08 // Construct various iterators and ensure their traversal is correct - it, _ := snaps.StorageIterator(common.HexToHash("0xff02"), common.HexToHash("0xaa"), common.HexToHash("0x01"), false) + it, _ := snaps.StorageIterator(common.HexToHash("0xff02"), common.HexToHash("0xaa"), common.HexToHash("0x01")) defer it.Release() verifyIterator(t, 3, it, verifyStorage) // expected: 01, 03, 05 - it, _ = snaps.StorageIterator(common.HexToHash("0xff02"), common.HexToHash("0xaa"), common.HexToHash("0x02"), false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff02"), common.HexToHash("0xaa"), common.HexToHash("0x02")) defer it.Release() verifyIterator(t, 2, it, verifyStorage) // expected: 03, 05 - it, _ = snaps.StorageIterator(common.HexToHash("0xff02"), common.HexToHash("0xaa"), common.HexToHash("0x5"), false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff02"), common.HexToHash("0xaa"), common.HexToHash("0x5")) defer it.Release() verifyIterator(t, 1, it, verifyStorage) // expected: 05 - it, _ = snaps.StorageIterator(common.HexToHash("0xff02"), common.HexToHash("0xaa"), common.HexToHash("0x6"), false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff02"), common.HexToHash("0xaa"), common.HexToHash("0x6")) defer it.Release() verifyIterator(t, 0, it, verifyStorage) // expected: nothing - it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.HexToHash("0x01"), false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.HexToHash("0x01")) defer it.Release() verifyIterator(t, 6, it, verifyStorage) // expected: 01, 02, 03, 05, 06, 08 - it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.HexToHash("0x05"), false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.HexToHash("0x05")) defer it.Release() verifyIterator(t, 3, it, verifyStorage) // expected: 05, 06, 08 - it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.HexToHash("0x08"), false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.HexToHash("0x08")) defer it.Release() verifyIterator(t, 1, it, verifyStorage) // expected: 08 - it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.HexToHash("0x09"), false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.HexToHash("0x09")) defer it.Release() verifyIterator(t, 0, it, verifyStorage) // expected: nothing } @@ -677,17 +677,17 @@ func TestAccountIteratorDeletions(t *testing.T) { // Create an empty base layer and a snapshot tree out of it snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), + snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, randomAccountSet("0x11", "0x22", "0x33"), nil) deleted := common.HexToHash("0x22") destructed := map[common.Hash]struct{}{ deleted: {}, } - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), + snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), destructed, randomAccountSet("0x11", "0x33"), nil) - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), + snaps.UpdateWithBlockHashes(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, randomAccountSet("0x33", "0x44", "0x55"), nil) // The output should be 11,33,44,55 @@ -714,19 +714,19 @@ func TestStorageIteratorDeletions(t *testing.T) { // Create an empty base layer and a snapshot tree out of it snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) // Stack three diff layers on top with various overlaps - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil)) - snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}})) // The output should be 02,04,05,06 - it, _ := snaps.StorageIterator(common.HexToHash("0xff03"), common.HexToHash("0xaa"), common.Hash{}, false) + it, _ := snaps.StorageIterator(common.HexToHash("0xff03"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 4, it, verifyStorage) it.Release() // The output should be 04,05,06 - it, _ = snaps.StorageIterator(common.HexToHash("0xff03"), common.HexToHash("0xaa"), common.HexToHash("0x03"), false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff03"), common.HexToHash("0xaa"), common.HexToHash("0x03")) verifyIterator(t, 3, it, verifyStorage) it.Release() @@ -734,24 +734,24 @@ func TestStorageIteratorDeletions(t *testing.T) { destructed := map[common.Hash]struct{}{ common.HexToHash("0xaa"): {}, } - snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), destructed, nil, nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), destructed, nil, nil) - it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.Hash{}, false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff04"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 0, it, verifyStorage) it.Release() // Re-insert the slots of the same account - snaps.Update(common.HexToHash("0x05"), common.HexToHash("0xff05"), common.HexToHash("0x04"), nil, + snaps.UpdateWithBlockHashes(common.HexToHash("0x05"), common.HexToHash("0xff05"), common.HexToHash("0x04"), nil, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil)) // The output should be 07,08,09 - it, _ = snaps.StorageIterator(common.HexToHash("0xff05"), common.HexToHash("0xaa"), common.Hash{}, false) + it, _ = snaps.StorageIterator(common.HexToHash("0xff05"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 3, it, verifyStorage) it.Release() // Destruct the whole storage but re-create the account in the same layer - snaps.Update(common.HexToHash("0x06"), common.HexToHash("0xff06"), common.HexToHash("0x05"), destructed, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, nil)) - it, _ = snaps.StorageIterator(common.HexToHash("0xff06"), common.HexToHash("0xaa"), common.Hash{}, false) + snaps.UpdateWithBlockHashes(common.HexToHash("0x06"), common.HexToHash("0xff06"), common.HexToHash("0x05"), destructed, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, nil)) + it, _ = snaps.StorageIterator(common.HexToHash("0xff06"), common.HexToHash("0xaa"), common.Hash{}) verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12 it.Release() @@ -783,7 +783,7 @@ func BenchmarkAccountIteratorTraversal(b *testing.B) { // Build up a large stack of snapshots snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) for i := 1; i <= 100; i++ { - snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0xff%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) + snaps.UpdateWithBlockHashes(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0xff%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil) } // We call this once before the benchmark, so the creation of // sorted accountlists are not included in the results. @@ -869,9 +869,9 @@ func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) { } // Build up a large stack of snapshots snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) - snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, makeAccounts(2000), nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, makeAccounts(2000), nil) for i := 2; i <= 100; i++ { - snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0xff%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(20), nil) + snaps.UpdateWithBlockHashes(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0xff%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(20), nil) } // We call this once before the benchmark, so the creation of // sorted accountlists are not included in the results. diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index 6f8d82311f..786b7af135 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -32,12 +32,12 @@ import ( "fmt" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) // journalGenerator is a disk layer entry containing the generator progress marker. diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 3490d743bf..0aaa3a27f4 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -34,13 +34,14 @@ import ( "sync" "time" + "github.com/ava-labs/libevm/common" + ethsnapshot "github.com/ava-labs/libevm/core/state/snapshot" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/libevm/stateconf" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/metrics" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" ) const ( @@ -118,28 +119,7 @@ var ( ) // Snapshot represents the functionality supported by a snapshot storage layer. -type Snapshot interface { - // Root returns the root hash for which this snapshot was made. - Root() common.Hash - - // Account directly retrieves the account associated with a particular hash in - // the snapshot slim data format. - Account(hash common.Hash) (*types.SlimAccount, error) - - // AccountRLP directly retrieves the account RLP associated with a particular - // hash in the snapshot slim data format. - AccountRLP(hash common.Hash) ([]byte, error) - - // Storage directly retrieves the storage data associated with a particular hash, - // within a particular account. - Storage(accountHash, storageHash common.Hash) ([]byte, error) - - // AccountIterator creates an account iterator over the account trie given by the provided root hash. - AccountIterator(seek common.Hash) AccountIterator - - // StorageIterator creates a storage iterator over the storage trie given by the provided root hash. - StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) -} +type Snapshot = ethsnapshot.Snapshot // snapshot is the internal version of the snapshot data layer that supports some // additional methods compared to the public API. @@ -164,6 +144,12 @@ type snapshot interface { // Stale return whether this layer has become stale (was flattened across) or // if it's still live. Stale() bool + + // AccountIterator creates an account iterator over an arbitrary layer. + AccountIterator(seek common.Hash) AccountIterator + + // StorageIterator creates a storage iterator over an arbitrary layer. + StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) } // Config includes the configurations for snapshots. @@ -321,9 +307,44 @@ func (t *Tree) Snapshots(blockHash common.Hash, limits int, nodisk bool) []Snaps return ret } +type blockHashes struct { + blockHash common.Hash + parentBlockHash common.Hash +} + +func WithBlockHashes(blockHash, parentBlockHash common.Hash) stateconf.SnapshotUpdateOption { + return stateconf.WithUpdatePayload(blockHashes{blockHash, parentBlockHash}) +} + // Update adds a new snapshot into the tree, if that can be linked to an existing // old parent. It is disallowed to insert a disk layer (the origin of all). -func (t *Tree) Update(blockHash, blockRoot, parentBlockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { +func (t *Tree) Update( + blockRoot common.Hash, + parentRoot common.Hash, + destructs map[common.Hash]struct{}, + accounts map[common.Hash][]byte, + storage map[common.Hash]map[common.Hash][]byte, + opts ...stateconf.SnapshotUpdateOption, +) error { + if len(opts) == 0 { + return fmt.Errorf("missing block hashes") + } + + payload := stateconf.ExtractUpdatePayload(opts[0]) + p, ok := payload.(blockHashes) + if !ok { + return fmt.Errorf("invalid block hashes payload type: %T", payload) + } + + return t.UpdateWithBlockHashes(p.blockHash, blockRoot, p.parentBlockHash, destructs, accounts, storage) +} + +func (t *Tree) UpdateWithBlockHashes( + blockHash, blockRoot, parentBlockHash common.Hash, + destructs map[common.Hash]struct{}, + accounts map[common.Hash][]byte, + storage map[common.Hash]map[common.Hash][]byte, +) error { t.lock.Lock() defer t.lock.Unlock() @@ -381,6 +402,10 @@ func (t *Tree) verifyIntegrity(base *diskLayer, waitBuild bool) error { return nil } +func (t *Tree) Cap(root common.Hash, layers int) error { + return nil // No-op as this code uses Flatten on block accept instead +} + // Flatten flattens the snapshot for [blockHash] into its parent. if its // parent is not a disk layer, Flatten will return an error. // Note: a blockHash is used instead of a state root so that the exact state @@ -823,7 +848,11 @@ func (t *Tree) AccountIterator(root common.Hash, seek common.Hash, force bool) ( // account. The iterator will be move to the specific start position. When [force] // is true, a new account iterator is created without acquiring the [snapTree] // lock and without confirming that the snapshot on the disk layer is fully generated. -func (t *Tree) StorageIterator(root common.Hash, account common.Hash, seek common.Hash, force bool) (StorageIterator, error) { +func (t *Tree) StorageIterator(root common.Hash, account common.Hash, seek common.Hash) (StorageIterator, error) { + return t.StorageIteratorWithForce(root, account, seek, false) +} + +func (t *Tree) StorageIteratorWithForce(root common.Hash, account common.Hash, seek common.Hash, force bool) (StorageIterator, error) { if !force { ok, err := t.generating() if err != nil { @@ -854,7 +883,7 @@ func (t *Tree) verify(root common.Hash, force bool) error { defer acctIt.Release() got, err := generateTrieRoot(nil, "", acctIt, common.Hash{}, stackTrieGenerate, func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) { - storageIt, err := t.StorageIterator(root, accountHash, common.Hash{}, force) + storageIt, err := t.StorageIteratorWithForce(root, accountHash, common.Hash{}, force) if err != nil { return common.Hash{}, err } diff --git a/core/state/snapshot/snapshot_ext.go b/core/state/snapshot/snapshot_ext.go index ee06542c19..fa9af3ddc3 100644 --- a/core/state/snapshot/snapshot_ext.go +++ b/core/state/snapshot/snapshot_ext.go @@ -3,9 +3,9 @@ package snapshot import ( "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" ) func (t *Tree) DiskAccountIterator(seek common.Hash) AccountIterator { @@ -23,9 +23,19 @@ func (t *Tree) DiskStorageIterator(account common.Hash, seek common.Hash) Storag return it } +type SnapshotIterable interface { + Snapshot + + // AccountIterator creates an account iterator over an arbitrary layer. + AccountIterator(seek common.Hash) AccountIterator + + // StorageIterator creates a storage iterator over an arbitrary layer. + StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) +} + // NewDiskLayer creates a diskLayer for direct access to the contents of the on-disk // snapshot. Does not perform any validation. -func NewDiskLayer(diskdb ethdb.KeyValueStore) Snapshot { +func NewDiskLayer(diskdb ethdb.KeyValueStore) SnapshotIterable { return &diskLayer{ diskdb: diskdb, created: time.Now(), diff --git a/core/state/snapshot/snapshot_test.go b/core/state/snapshot/snapshot_test.go index 4d4b476d55..bd98f50140 100644 --- a/core/state/snapshot/snapshot_test.go +++ b/core/state/snapshot/snapshot_test.go @@ -33,10 +33,10 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" ) @@ -106,7 +106,7 @@ func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := snaps.NumStateLayers(); n != 2 { @@ -147,10 +147,10 @@ func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := snaps.NumBlockLayers(); n != 3 { @@ -196,13 +196,13 @@ func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) { accounts := map[common.Hash][]byte{ common.HexToHash("0xa1"): randomAccount(), } - if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(common.HexToHash("0x02"), common.HexToHash("0xff02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(common.HexToHash("0x03"), common.HexToHash("0xff03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.Update(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, accounts, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(common.HexToHash("0x04"), common.HexToHash("0xff04"), common.HexToHash("0x03"), nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } if n := snaps.NumStateLayers(); n != 4 { @@ -244,12 +244,12 @@ func TestPostFlattenBasicDataAccess(t *testing.T) { // Create a starting base layer and a snapshot tree out of it snaps := NewTestTree(rawdb.NewMemoryDatabase(), common.HexToHash("0x01"), common.HexToHash("0xff01")) // The lowest difflayer - snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0xffa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil) - snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xffa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil) - snaps.Update(common.HexToHash("0xb2"), common.HexToHash("0xffb2"), common.HexToHash("0xa1"), nil, setAccount("0xb2"), nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0xa1"), common.HexToHash("0xffa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0xa2"), common.HexToHash("0xffa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0xb2"), common.HexToHash("0xffb2"), common.HexToHash("0xa1"), nil, setAccount("0xb2"), nil) - snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xffa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil) - snaps.Update(common.HexToHash("0xb3"), common.HexToHash("0xffb3"), common.HexToHash("0xb2"), nil, setAccount("0xb3"), nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0xa3"), common.HexToHash("0xffa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil) + snaps.UpdateWithBlockHashes(common.HexToHash("0xb3"), common.HexToHash("0xffb3"), common.HexToHash("0xb2"), nil, setAccount("0xb3"), nil) // checkExist verifies if an account exists in a snapshot checkExist := func(layer Snapshot, key string) error { @@ -434,10 +434,10 @@ func TestTreeFlattenDoesNotDropPendingLayers(t *testing.T) { diffBlockAHash := common.Hash{0xee, 0xee, byte(i)} diffBlockBHash := common.Hash{0xdd, 0xdd, byte(i)} diffBlockRoot := common.Hash{0xff, 0xff, byte(i)} - if err := snaps.Update(diffBlockAHash, diffBlockRoot, parentAHash, nil, accounts, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(diffBlockAHash, diffBlockRoot, parentAHash, nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } - if err := snaps.Update(diffBlockBHash, diffBlockRoot, parentBHash, nil, accounts, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(diffBlockBHash, diffBlockRoot, parentBHash, nil, accounts, nil); err != nil { t.Fatalf("failed to create a diff layer: %v", err) } @@ -509,7 +509,7 @@ func TestStaleOriginLayer(t *testing.T) { } // Create diff layer A containing account 0xa1 - if err := snaps.Update(diffBlockHashA, diffRootA, baseBlockHash, nil, accountsA, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(diffBlockHashA, diffRootA, baseBlockHash, nil, accountsA, nil); err != nil { t.Errorf("failed to create diff layer A: %v", err) } // Flatten account 0xa1 to disk @@ -519,12 +519,12 @@ func TestStaleOriginLayer(t *testing.T) { } // Create diff layer B containing account 0xa2 // The bloom filter should contain only 0xa2. - if err := snaps.Update(diffBlockHashB, diffRootB, diffBlockHashA, nil, accountsB, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(diffBlockHashB, diffRootB, diffBlockHashA, nil, accountsB, nil); err != nil { t.Errorf("failed to create diff layer B: %v", err) } // Create diff layer C containing account 0xa3 // The bloom filter should contain 0xa2 and 0xa3 - if err := snaps.Update(diffBlockHashC, diffRootC, diffBlockHashB, nil, accountsC, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(diffBlockHashC, diffRootC, diffBlockHashB, nil, accountsC, nil); err != nil { t.Errorf("failed to create diff layer C: %v", err) } @@ -591,16 +591,16 @@ func TestRebloomOnFlatten(t *testing.T) { } // Build the tree - if err := snaps.Update(diffBlockHashA, diffRootA, baseBlockHash, nil, accountsA, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(diffBlockHashA, diffRootA, baseBlockHash, nil, accountsA, nil); err != nil { t.Errorf("failed to create diff layer A: %v", err) } - if err := snaps.Update(diffBlockHashB, diffRootB, diffBlockHashA, nil, accountsB, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(diffBlockHashB, diffRootB, diffBlockHashA, nil, accountsB, nil); err != nil { t.Errorf("failed to create diff layer B: %v", err) } - if err := snaps.Update(diffBlockHashC, diffRootC, diffBlockHashB, nil, accountsC, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(diffBlockHashC, diffRootC, diffBlockHashB, nil, accountsC, nil); err != nil { t.Errorf("failed to create diff layer C: %v", err) } - if err := snaps.Update(diffBlockHashD, diffRootD, diffBlockHashB, nil, accountsD, nil); err != nil { + if err := snaps.UpdateWithBlockHashes(diffBlockHashD, diffRootD, diffBlockHashB, nil, accountsD, nil); err != nil { t.Errorf("failed to create diff layer D: %v", err) } @@ -687,9 +687,9 @@ func TestReadStateDuringFlattening(t *testing.T) { snaps := NewTestTree(rawdb.NewMemoryDatabase(), baseBlockHash, baseRoot) // 4 layers in total, 3 diff layers and 1 disk layers - snaps.Update(diffBlockHashA, diffRootA, baseBlockHash, nil, setAccount("0xa1"), nil) - snaps.Update(diffBlockHashB, diffRootB, diffBlockHashA, nil, setAccount("0xa2"), nil) - snaps.Update(diffBlockHashC, diffRootC, diffBlockHashB, nil, setAccount("0xa3"), nil) + snaps.UpdateWithBlockHashes(diffBlockHashA, diffRootA, baseBlockHash, nil, setAccount("0xa1"), nil) + snaps.UpdateWithBlockHashes(diffBlockHashB, diffRootB, diffBlockHashA, nil, setAccount("0xa2"), nil) + snaps.UpdateWithBlockHashes(diffBlockHashC, diffRootC, diffBlockHashB, nil, setAccount("0xa3"), nil) // Obtain the topmost snapshot handler for state accessing snap := snaps.Snapshot(diffRootC) diff --git a/core/state/snapshot/utils.go b/core/state/snapshot/utils.go index 6131ae4c20..af62b72686 100644 --- a/core/state/snapshot/utils.go +++ b/core/state/snapshot/utils.go @@ -31,10 +31,10 @@ import ( "fmt" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" ) // CheckDanglingStorage iterates the snap storage data, and verifies that all diff --git a/core/state/snapshot/wipe.go b/core/state/snapshot/wipe.go index 9de121a244..451930ce69 100644 --- a/core/state/snapshot/wipe.go +++ b/core/state/snapshot/wipe.go @@ -30,10 +30,10 @@ import ( "bytes" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" ) // WipeSnapshot starts a goroutine to iterate over the entire key-value database diff --git a/core/state/snapshot/wipe_test.go b/core/state/snapshot/wipe_test.go index c1080a1465..18d13311f7 100644 --- a/core/state/snapshot/wipe_test.go +++ b/core/state/snapshot/wipe_test.go @@ -30,9 +30,9 @@ import ( "math/rand" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb/memorydb" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb/memorydb" ) // Tests that given a database with random data content, all parts of a snapshot diff --git a/core/state/state_object.go b/core/state/state_object.go deleted file mode 100644 index fbff5a1c48..0000000000 --- a/core/state/state_object.go +++ /dev/null @@ -1,556 +0,0 @@ -// (c) 2019-2020, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 state - -import ( - "bytes" - "fmt" - "io" - "time" - - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/metrics" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" - "github.com/holiman/uint256" -) - -type Code []byte - -func (c Code) String() string { - return string(c) //strings.Join(Disassemble(c), " ") -} - -type Storage map[common.Hash]common.Hash - -func (s Storage) String() (str string) { - for key, value := range s { - str += fmt.Sprintf("%X : %X\n", key, value) - } - return -} - -func (s Storage) Copy() Storage { - cpy := make(Storage, len(s)) - for key, value := range s { - cpy[key] = value - } - return cpy -} - -// stateObject represents an Ethereum account which is being modified. -// -// The usage pattern is as follows: -// - First you need to obtain a state object. -// - Account values as well as storages can be accessed and modified through the object. -// - Finally, call commit to return the changes of storage trie and update account data. -type stateObject struct { - db *StateDB - address common.Address // address of ethereum account - addrHash common.Hash // hash of ethereum address of the account - origin *types.StateAccount // Account original data without any change applied, nil means it was not existent - data types.StateAccount // Account data with all mutations applied in the scope of block - - // Write caches. - trie Trie // storage trie, which becomes non-nil on first access - code Code // contract bytecode, which gets set when code is loaded - - originStorage Storage // Storage cache of original entries to dedup rewrites - pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block - dirtyStorage Storage // Storage entries that have been modified in the current transaction execution, reset for every transaction - - // Cache flags. - dirtyCode bool // true if the code was updated - - // Flag whether the account was marked as self-destructed. The self-destructed account - // is still accessible in the scope of same transaction. - selfDestructed bool - - // Flag whether the account was marked as deleted. A self-destructed account - // or an account that is considered as empty will be marked as deleted at - // the end of transaction and no longer accessible anymore. - deleted bool - - // Flag whether the object was created in the current transaction - created bool -} - -// empty returns whether the account is considered empty. -func (s *stateObject) empty() bool { - return s.data.Nonce == 0 && s.data.Balance.IsZero() && bytes.Equal(s.data.CodeHash, types.EmptyCodeHash.Bytes()) -} - -// newObject creates a state object. -func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject { - var ( - origin = acct - created = acct == nil // true if the account was not existent - ) - if acct == nil { - acct = types.NewEmptyStateAccount() - } - return &stateObject{ - db: db, - address: address, - addrHash: crypto.Keccak256Hash(address[:]), - origin: origin, - data: *acct, - originStorage: make(Storage), - pendingStorage: make(Storage), - dirtyStorage: make(Storage), - created: created, - } -} - -// EncodeRLP implements rlp.Encoder. -func (s *stateObject) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, &s.data) -} - -func (s *stateObject) markSelfdestructed() { - s.selfDestructed = true -} - -func (s *stateObject) touch() { - s.db.journal.append(touchChange{ - account: &s.address, - }) - if s.address == ripemd { - // Explicitly put it in the dirty-cache, which is otherwise generated from - // flattened journals. - s.db.journal.dirty(s.address) - } -} - -// getTrie returns the associated storage trie. The trie will be opened -// if it's not loaded previously. An error will be returned if trie can't -// be loaded. -func (s *stateObject) getTrie() (Trie, error) { - if s.trie == nil { - // Try fetching from prefetcher first - if s.data.Root != types.EmptyRootHash && s.db.prefetcher != nil { - // When the miner is creating the pending state, there is no prefetcher - s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root) - } - if s.trie == nil { - tr, err := s.db.db.OpenStorageTrie(s.db.originalRoot, s.address, s.data.Root, s.db.trie) - if err != nil { - return nil, err - } - s.trie = tr - } - } - return s.trie, nil -} - -// GetState retrieves a value from the account storage trie. -func (s *stateObject) GetState(key common.Hash) common.Hash { - // If we have a dirty value for this state entry, return it - value, dirty := s.dirtyStorage[key] - if dirty { - return value - } - // Otherwise return the entry's original value - return s.GetCommittedState(key) -} - -// GetCommittedState retrieves a value from the committed account storage trie. -func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { - // If we have a pending write or clean cached, return that - if value, pending := s.pendingStorage[key]; pending { - return value - } - if value, cached := s.originStorage[key]; cached { - return value - } - // If the object was destructed in *this* block (and potentially resurrected), - // the storage has been cleared out, and we should *not* consult the previous - // database about any storage values. The only possible alternatives are: - // 1) resurrect happened, and new slot values were set -- those should - // have been handles via pendingStorage above. - // 2) we don't have new values, and can deliver empty response back - if _, destructed := s.db.stateObjectsDestruct[s.address]; destructed { - return common.Hash{} - } - // If no live objects are available, attempt to use snapshots - var ( - enc []byte - err error - value common.Hash - ) - if s.db.snap != nil { - start := time.Now() - enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes())) - if metrics.EnabledExpensive { - s.db.SnapshotStorageReads += time.Since(start) - } - if len(enc) > 0 { - _, content, _, err := rlp.Split(enc) - if err != nil { - s.db.setError(err) - } - value.SetBytes(content) - } - } - // If the snapshot is unavailable or reading from it fails, load from the database. - if s.db.snap == nil || err != nil { - start := time.Now() - tr, err := s.getTrie() - if err != nil { - s.db.setError(err) - return common.Hash{} - } - val, err := tr.GetStorage(s.address, key.Bytes()) - if metrics.EnabledExpensive { - s.db.StorageReads += time.Since(start) - } - if err != nil { - s.db.setError(err) - return common.Hash{} - } - value.SetBytes(val) - } - s.originStorage[key] = value - return value -} - -// SetState updates a value in account storage. -func (s *stateObject) SetState(key, value common.Hash) { - // If the new value is the same as old, don't set - prev := s.GetState(key) - if prev == value { - return - } - // New value is different, update and journal the change - s.db.journal.append(storageChange{ - account: &s.address, - key: key, - prevalue: prev, - }) - s.setState(key, value) -} - -func (s *stateObject) setState(key, value common.Hash) { - s.dirtyStorage[key] = value -} - -// finalise moves all dirty storage slots into the pending area to be hashed or -// committed later. It is invoked at the end of every transaction. -func (s *stateObject) finalise(prefetch bool) { - slotsToPrefetch := make([][]byte, 0, len(s.dirtyStorage)) - for key, value := range s.dirtyStorage { - s.pendingStorage[key] = value - if value != s.originStorage[key] { - slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure - } - } - if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { - s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch) - } - if len(s.dirtyStorage) > 0 { - s.dirtyStorage = make(Storage) - } -} - -// updateTrie is responsible for persisting cached storage changes into the -// object's storage trie. In case the storage trie is not yet loaded, this -// function will load the trie automatically. If any issues arise during the -// loading or updating of the trie, an error will be returned. Furthermore, -// this function will return the mutated storage trie, or nil if there is no -// storage change at all. -func (s *stateObject) updateTrie() (Trie, error) { - // Make sure all dirty slots are finalized into the pending storage area - s.finalise(false) - - // Short circuit if nothing changed, don't bother with hashing anything - if len(s.pendingStorage) == 0 { - return s.trie, nil - } - // Track the amount of time wasted on updating the storage trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now()) - } - // The snapshot storage map for the object - var ( - storage map[common.Hash][]byte - origin map[common.Hash][]byte - ) - tr, err := s.getTrie() - if err != nil { - s.db.setError(err) - return nil, err - } - // Insert all the pending storage updates into the trie - usedStorage := make([][]byte, 0, len(s.pendingStorage)) - for key, value := range s.pendingStorage { - // Skip noop changes, persist actual changes - if value == s.originStorage[key] { - continue - } - prev := s.originStorage[key] - s.originStorage[key] = value - - var encoded []byte // rlp-encoded value to be used by the snapshot - if (value == common.Hash{}) { - if err := tr.DeleteStorage(s.address, key[:]); err != nil { - s.db.setError(err) - return nil, err - } - s.db.StorageDeleted += 1 - } else { - // Encoding []byte cannot fail, ok to ignore the error. - trimmed := common.TrimLeftZeroes(value[:]) - encoded, _ = rlp.EncodeToBytes(trimmed) - if err := tr.UpdateStorage(s.address, key[:], trimmed); err != nil { - s.db.setError(err) - return nil, err - } - s.db.StorageUpdated += 1 - } - // Cache the mutated storage slots until commit - if storage == nil { - if storage = s.db.storages[s.addrHash]; storage == nil { - storage = make(map[common.Hash][]byte) - s.db.storages[s.addrHash] = storage - } - } - khash := crypto.HashData(s.db.hasher, key[:]) - storage[khash] = encoded // encoded will be nil if it's deleted - - // Cache the original value of mutated storage slots - if origin == nil { - if origin = s.db.storagesOrigin[s.address]; origin == nil { - origin = make(map[common.Hash][]byte) - s.db.storagesOrigin[s.address] = origin - } - } - // Track the original value of slot only if it's mutated first time - if _, ok := origin[khash]; !ok { - if prev == (common.Hash{}) { - origin[khash] = nil // nil if it was not present previously - } else { - // Encoding []byte cannot fail, ok to ignore the error. - b, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(prev[:])) - origin[khash] = b - } - } - // Cache the items for preloading - usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure - } - if s.db.prefetcher != nil { - s.db.prefetcher.used(s.addrHash, s.data.Root, usedStorage) - } - s.pendingStorage = make(Storage) // reset pending map - return tr, nil -} - -// updateRoot flushes all cached storage mutations to trie, recalculating the -// new storage trie root. -func (s *stateObject) updateRoot() { - // Flush cached storage mutations into trie, short circuit if any error - // is occurred or there is not change in the trie. - tr, err := s.updateTrie() - if err != nil || tr == nil { - return - } - // Track the amount of time wasted on hashing the storage trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now()) - } - s.data.Root = tr.Hash() -} - -// commit obtains a set of dirty storage trie nodes and updates the account data. -// The returned set can be nil if nothing to commit. This function assumes all -// storage mutations have already been flushed into trie by updateRoot. -func (s *stateObject) commit() (*trienode.NodeSet, error) { - // Short circuit if trie is not even loaded, don't bother with committing anything - if s.trie == nil { - s.origin = s.data.Copy() - return nil, nil - } - // Track the amount of time wasted on committing the storage trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) - } - // The trie is currently in an open state and could potentially contain - // cached mutations. Call commit to acquire a set of nodes that have been - // modified, the set can be nil if nothing to commit. - root, nodes, err := s.trie.Commit(false) - if err != nil { - return nil, err - } - s.data.Root = root - - // Update original account data after commit - s.origin = s.data.Copy() - return nodes, nil -} - -// AddBalance adds amount to s's balance. -// It is used to add funds to the destination account of a transfer. -func (s *stateObject) AddBalance(amount *uint256.Int) { - // EIP161: We must check emptiness for the objects such that the account - // clearing (0,0,0 objects) can take effect. - if amount.IsZero() { - if s.empty() { - s.touch() - } - return - } - s.SetBalance(new(uint256.Int).Add(s.Balance(), amount)) -} - -// SubBalance removes amount from s's balance. -// It is used to remove funds from the origin account of a transfer. -func (s *stateObject) SubBalance(amount *uint256.Int) { - if amount.IsZero() { - return - } - s.SetBalance(new(uint256.Int).Sub(s.Balance(), amount)) -} - -func (s *stateObject) SetBalance(amount *uint256.Int) { - s.db.journal.append(balanceChange{ - account: &s.address, - prev: new(uint256.Int).Set(s.data.Balance), - }) - s.setBalance(amount) -} - -func (s *stateObject) setBalance(amount *uint256.Int) { - s.data.Balance = amount -} - -func (s *stateObject) deepCopy(db *StateDB) *stateObject { - obj := &stateObject{ - db: db, - address: s.address, - addrHash: s.addrHash, - origin: s.origin, - data: s.data, - } - if s.trie != nil { - obj.trie = db.db.CopyTrie(s.trie) - } - obj.code = s.code - obj.dirtyStorage = s.dirtyStorage.Copy() - obj.originStorage = s.originStorage.Copy() - obj.pendingStorage = s.pendingStorage.Copy() - obj.selfDestructed = s.selfDestructed - obj.dirtyCode = s.dirtyCode - obj.deleted = s.deleted - return obj -} - -// -// Attribute accessors -// - -// Address returns the address of the contract/account -func (s *stateObject) Address() common.Address { - return s.address -} - -// Code returns the contract code associated with this object, if any. -func (s *stateObject) Code() []byte { - if s.code != nil { - return s.code - } - if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { - return nil - } - code, err := s.db.db.ContractCode(s.address, common.BytesToHash(s.CodeHash())) - if err != nil { - s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) - } - s.code = code - return code -} - -// CodeSize returns the size of the contract code associated with this object, -// or zero if none. This method is an almost mirror of Code, but uses a cache -// inside the database to avoid loading codes seen recently. -func (s *stateObject) CodeSize() int { - if s.code != nil { - return len(s.code) - } - if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { - return 0 - } - size, err := s.db.db.ContractCodeSize(s.address, common.BytesToHash(s.CodeHash())) - if err != nil { - s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err)) - } - return size -} - -func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { - prevcode := s.Code() - s.db.journal.append(codeChange{ - account: &s.address, - prevhash: s.CodeHash(), - prevcode: prevcode, - }) - s.setCode(codeHash, code) -} - -func (s *stateObject) setCode(codeHash common.Hash, code []byte) { - s.code = code - s.data.CodeHash = codeHash[:] - s.dirtyCode = true -} - -func (s *stateObject) SetNonce(nonce uint64) { - s.db.journal.append(nonceChange{ - account: &s.address, - prev: s.data.Nonce, - }) - s.setNonce(nonce) -} - -func (s *stateObject) setNonce(nonce uint64) { - s.data.Nonce = nonce -} - -func (s *stateObject) CodeHash() []byte { - return s.data.CodeHash -} - -func (s *stateObject) Balance() *uint256.Int { - return s.data.Balance -} - -func (s *stateObject) Nonce() uint64 { - return s.data.Nonce -} - -func (s *stateObject) Root() common.Hash { - return s.data.Root -} diff --git a/core/state/state_test.go b/core/state/state_test.go index 24313429db..4f2f6b792f 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -27,17 +27,12 @@ package state import ( - "bytes" - "encoding/json" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/holiman/uint256" ) type stateEnv struct { @@ -51,100 +46,6 @@ func newStateEnv() *stateEnv { return &stateEnv{db: db, state: sdb} } -func TestDump(t *testing.T) { - db := rawdb.NewMemoryDatabase() - tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true}) - sdb, _ := New(types.EmptyRootHash, tdb, nil) - s := &stateEnv{db: db, state: sdb} - - // generate a few entries - obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01})) - obj1.AddBalance(uint256.NewInt(22)) - obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) - obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) - obj3 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02})) - obj3.SetBalance(uint256.NewInt(44)) - - // write some of them to the trie - s.state.updateStateObject(obj1) - s.state.updateStateObject(obj2) - root, _ := s.state.Commit(0, false) - - // check that DumpToCollector contains the state objects that are in trie - s.state, _ = New(root, tdb, nil) - got := string(s.state.Dump(nil)) - want := `{ - "root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2", - "accounts": { - "0x0000000000000000000000000000000000000001": { - "balance": "22", - "nonce": 0, - "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "address": "0x0000000000000000000000000000000000000001", - "key": "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d" - }, - "0x0000000000000000000000000000000000000002": { - "balance": "44", - "nonce": 0, - "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "address": "0x0000000000000000000000000000000000000002", - "key": "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62" - }, - "0x0000000000000000000000000000000000000102": { - "balance": "0", - "nonce": 0, - "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "codeHash": "0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3", - "code": "0x03030303030303", - "address": "0x0000000000000000000000000000000000000102", - "key": "0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1" - } - } -}` - if got != want { - t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want) - } -} - -func TestIterativeDump(t *testing.T) { - db := rawdb.NewMemoryDatabase() - tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true}) - sdb, _ := New(types.EmptyRootHash, tdb, nil) - s := &stateEnv{db: db, state: sdb} - - // generate a few entries - obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01})) - obj1.AddBalance(uint256.NewInt(22)) - obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02})) - obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3}) - obj3 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02})) - obj3.SetBalance(uint256.NewInt(44)) - obj4 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x00})) - obj4.AddBalance(uint256.NewInt(1337)) - - // write some of them to the trie - s.state.updateStateObject(obj1) - s.state.updateStateObject(obj2) - root, _ := s.state.Commit(0, false) - s.state, _ = New(root, tdb, nil) - - b := &bytes.Buffer{} - s.state.IterativeDump(nil, json.NewEncoder(b)) - // check that DumpToCollector contains the state objects that are in trie - got := b.String() - want := `{"root":"0xd5710ea8166b7b04bc2bfb129d7db12931cee82f75ca8e2d075b4884322bf3de"} -{"balance":"22","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000001","key":"0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"} -{"balance":"1337","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000000","key":"0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a"} -{"balance":"0","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3","code":"0x03030303030303","address":"0x0000000000000000000000000000000000000102","key":"0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"} -{"balance":"44","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000002","key":"0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"} -` - if got != want { - t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want) - } -} - func TestNull(t *testing.T) { s := newStateEnv() address := common.HexToAddress("0x823140710bf13990e4500136726d8b55") @@ -202,107 +103,3 @@ func TestSnapshotEmpty(t *testing.T) { s := newStateEnv() s.state.RevertToSnapshot(s.state.Snapshot()) } - -func TestSnapshot2(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) - - stateobjaddr0 := common.BytesToAddress([]byte("so0")) - stateobjaddr1 := common.BytesToAddress([]byte("so1")) - var storageaddr common.Hash - - data0 := common.BytesToHash([]byte{17}) - data1 := common.BytesToHash([]byte{18}) - - state.SetState(stateobjaddr0, storageaddr, data0) - state.SetState(stateobjaddr1, storageaddr, data1) - - // db, trie are already non-empty values - so0 := state.getStateObject(stateobjaddr0) - so0.SetBalance(uint256.NewInt(42)) - so0.SetNonce(43) - so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'}) - so0.selfDestructed = false - so0.deleted = false - state.setStateObject(so0) - - root, _ := state.Commit(0, false) - state, _ = New(root, state.db, nil) - - // and one with deleted == true - so1 := state.getStateObject(stateobjaddr1) - so1.SetBalance(uint256.NewInt(52)) - so1.SetNonce(53) - so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'}) - so1.selfDestructed = true - so1.deleted = true - state.setStateObject(so1) - - so1 = state.getStateObject(stateobjaddr1) - if so1 != nil { - t.Fatalf("deleted object not nil when getting") - } - - snapshot := state.Snapshot() - state.RevertToSnapshot(snapshot) - - so0Restored := state.getStateObject(stateobjaddr0) - // Update lazily-loaded values before comparing. - so0Restored.GetState(storageaddr) - so0Restored.Code() - // non-deleted is equal (restored) - compareStateObjects(so0Restored, so0, t) - - // deleted should be nil, both before and after restore of state copy - so1Restored := state.getStateObject(stateobjaddr1) - if so1Restored != nil { - t.Fatalf("deleted object not nil after restoring snapshot: %+v", so1Restored) - } -} - -func compareStateObjects(so0, so1 *stateObject, t *testing.T) { - if so0.Address() != so1.Address() { - t.Fatalf("Address mismatch: have %v, want %v", so0.address, so1.address) - } - if so0.Balance().Cmp(so1.Balance()) != 0 { - t.Fatalf("Balance mismatch: have %v, want %v", so0.Balance(), so1.Balance()) - } - if so0.Nonce() != so1.Nonce() { - t.Fatalf("Nonce mismatch: have %v, want %v", so0.Nonce(), so1.Nonce()) - } - if so0.data.Root != so1.data.Root { - t.Errorf("Root mismatch: have %x, want %x", so0.data.Root[:], so1.data.Root[:]) - } - if !bytes.Equal(so0.CodeHash(), so1.CodeHash()) { - t.Fatalf("CodeHash mismatch: have %v, want %v", so0.CodeHash(), so1.CodeHash()) - } - if !bytes.Equal(so0.code, so1.code) { - t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code) - } - - if len(so1.dirtyStorage) != len(so0.dirtyStorage) { - t.Errorf("Dirty storage size mismatch: have %d, want %d", len(so1.dirtyStorage), len(so0.dirtyStorage)) - } - for k, v := range so1.dirtyStorage { - if so0.dirtyStorage[k] != v { - t.Errorf("Dirty storage key %x mismatch: have %v, want %v", k, so0.dirtyStorage[k], v) - } - } - for k, v := range so0.dirtyStorage { - if so1.dirtyStorage[k] != v { - t.Errorf("Dirty storage key %x mismatch: have %v, want none.", k, v) - } - } - if len(so1.originStorage) != len(so0.originStorage) { - t.Errorf("Origin storage size mismatch: have %d, want %d", len(so1.originStorage), len(so0.originStorage)) - } - for k, v := range so1.originStorage { - if so0.originStorage[k] != v { - t.Errorf("Origin storage key %x mismatch: have %v, want %v", k, so0.originStorage[k], v) - } - } - for k, v := range so0.originStorage { - if so1.originStorage[k] != v { - t.Errorf("Origin storage key %x mismatch: have %v, want none.", k, v) - } - } -} diff --git a/core/state/statedb.go b/core/state/statedb.go index 34bfac5a6c..f6073af670 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -28,35 +28,11 @@ package state import ( - "fmt" - "sort" - "time" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/state/snapshot" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/metrics" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" - "github.com/holiman/uint256" -) - -const ( - // storageDeleteLimit denotes the highest permissible memory allocation - // employed for contract storage deletion. - storageDeleteLimit = 512 * 1024 * 1024 + "github.com/ava-labs/libevm/common" + ethstate "github.com/ava-labs/libevm/core/state" + "github.com/ava-labs/subnet-evm/utils" ) -type revision struct { - id int - journalIndex int -} - // StateDB structs within the ethereum protocol are used to store anything // within the merkle trie. StateDBs take care of caching and storing // nested states. It's the general query interface to retrieve: @@ -69,905 +45,54 @@ type revision struct { // must be created with new root and updated database for accessing post- // commit states. type StateDB struct { - db Database - prefetcher *triePrefetcher - trie Trie - hasher crypto.KeccakState - snap snapshot.Snapshot // Nil if snapshot is not available - - // originalRoot is the pre-state root, before any changes were made. - // It will be updated when the Commit is called. - originalRoot common.Hash - - // These maps hold the state changes (including the corresponding - // original value) that occurred in this **block**. - accounts map[common.Hash][]byte // The mutated accounts in 'slim RLP' encoding - storages map[common.Hash]map[common.Hash][]byte // The mutated slots in prefix-zero trimmed rlp format - accountsOrigin map[common.Address][]byte // The original value of mutated accounts in 'slim RLP' encoding - storagesOrigin map[common.Address]map[common.Hash][]byte // The original value of mutated slots in prefix-zero trimmed rlp format - - // This map holds 'live' objects, which will get modified while processing - // a state transition. - stateObjects map[common.Address]*stateObject - stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie - stateObjectsDirty map[common.Address]struct{} // State objects modified in the current execution - stateObjectsDestruct map[common.Address]*types.StateAccount // State objects destructed in the block along with its previous value - - // DB error. - // State objects are used by the consensus core and VM which are - // unable to deal with database-level errors. Any error that occurs - // during a database read is memoized here and will eventually be - // returned by StateDB.Commit. Notably, this error is also shared - // by all cached state objects in case the database failure occurs - // when accessing state of accounts. - dbErr error + *ethstate.StateDB - // The refund counter, also used by state transitioning. - refund uint64 - - // The tx context and all occurred logs in the scope of transaction. + // The tx context thash common.Hash txIndex int - logs map[common.Hash][]*types.Log - logSize uint - - // Preimages occurred seen by VM in the scope of block. - preimages map[common.Hash][]byte - - // Per-transaction access list - accessList *accessList - - // Transient storage - transientStorage transientStorage - - // Journal of state modifications. This is the backbone of - // Snapshot and RevertToSnapshot. - journal *journal - validRevisions []revision - nextRevisionId int - // Measurements gathered during execution for debugging purposes - AccountReads time.Duration - AccountHashes time.Duration - AccountUpdates time.Duration - AccountCommits time.Duration - StorageReads time.Duration - StorageHashes time.Duration - StorageUpdates time.Duration - StorageCommits time.Duration - SnapshotAccountReads time.Duration - SnapshotStorageReads time.Duration - SnapshotCommits time.Duration - TrieDBCommits time.Duration - - AccountUpdated int - StorageUpdated int - AccountDeleted int - StorageDeleted int - - // Testing hooks - onCommit func(states *triestate.Set) // Hook invoked when commit is performed + // Some fields remembered as they are used in tests + db Database + snaps ethstate.SnapshotTree } // New creates a new state from a given trie. -func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) { - var snap snapshot.Snapshot - if snaps != nil { - snap = snaps.Snapshot(root) - } - return NewWithSnapshot(root, db, snap) -} - -// NewWithSnapshot creates a new state from a given trie with the specified [snap] -// If [snap] doesn't have the same root as [root], then NewWithSnapshot will return -// an error. If snap is nil, then no snapshot will be used and CommitWithSnapshot -// cannot be called on the returned StateDB. -func NewWithSnapshot(root common.Hash, db Database, snap snapshot.Snapshot) (*StateDB, error) { - tr, err := db.OpenTrie(root) +func New(root common.Hash, db Database, snaps ethstate.SnapshotTree) (*StateDB, error) { + stateDB, err := ethstate.New(root, db, snaps) if err != nil { return nil, err } - sdb := &StateDB{ - db: db, - trie: tr, - originalRoot: root, - accounts: make(map[common.Hash][]byte), - storages: make(map[common.Hash]map[common.Hash][]byte), - accountsOrigin: make(map[common.Address][]byte), - storagesOrigin: make(map[common.Address]map[common.Hash][]byte), - stateObjects: make(map[common.Address]*stateObject), - stateObjectsPending: make(map[common.Address]struct{}), - stateObjectsDirty: make(map[common.Address]struct{}), - stateObjectsDestruct: make(map[common.Address]*types.StateAccount), - logs: make(map[common.Hash][]*types.Log), - preimages: make(map[common.Hash][]byte), - journal: newJournal(), - accessList: newAccessList(), - transientStorage: newTransientStorage(), - hasher: crypto.NewKeccakState(), - } - if snap != nil { - if snap.Root() != root { - return nil, fmt.Errorf("cannot create new statedb for root: %s, using snapshot with mismatched root: %s", root, snap.Root().Hex()) - } - sdb.snap = snap - } - return sdb, nil -} - -// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the -// state trie concurrently while the state is mutated so that when we reach the -// commit phase, most of the needed data is already hot. -func (s *StateDB) StartPrefetcher(namespace string, maxConcurrency int) { - if s.prefetcher != nil { - s.prefetcher.close() - s.prefetcher = nil - } - if s.snap != nil { - s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, maxConcurrency) - } -} - -// StopPrefetcher terminates a running prefetcher and reports any leftover stats -// from the gathered metrics. -func (s *StateDB) StopPrefetcher() { - if s.prefetcher != nil { - s.prefetcher.close() - s.prefetcher = nil - } + return &StateDB{ + StateDB: stateDB, + db: db, + snaps: snaps, + }, nil } -// setError remembers the first non-nil error it is called with. -func (s *StateDB) setError(err error) { - if s.dbErr == nil { - s.dbErr = err - } +type workerPool struct { + *utils.BoundedWorkers } -// Error returns the memorized database failure occurred earlier. -func (s *StateDB) Error() error { - return s.dbErr -} - -// AddLog adds a log with the specified parameters to the statedb -// Note: blockNumber is a required argument because StateDB does not -// know the current block number. -func (s *StateDB) AddLog(log *types.Log) { - s.journal.append(addLogChange{txhash: s.thash}) - - log.TxHash = s.thash - log.TxIndex = uint(s.txIndex) - log.Index = s.logSize - s.logs[s.thash] = append(s.logs[s.thash], log) - s.logSize++ +func (wp *workerPool) Done() { + // Done is guaranteed to only be called after all work is already complete, + // so we call Wait for goroutines to finish before returning. + wp.BoundedWorkers.Wait() } -// GetLogs returns the logs matching the specified transaction hash, and annotates -// them with the given blockNumber and blockHash. -func (s *StateDB) GetLogs(hash common.Hash, blockNumber uint64, blockHash common.Hash) []*types.Log { - logs := s.logs[hash] - for _, l := range logs { - l.BlockNumber = blockNumber - l.BlockHash = blockHash +func WithConcurrentWorkers(prefetchers int) ethstate.PrefetcherOption { + pool := &workerPool{ + BoundedWorkers: utils.NewBoundedWorkers(prefetchers), } - return logs -} - -func (s *StateDB) Logs() []*types.Log { - var logs []*types.Log - for _, lgs := range s.logs { - logs = append(logs, lgs...) - } - return logs -} - -// GetLogData returns the underlying topics and data from each log included in the StateDB -// Test helper function. -func (s *StateDB) GetLogData() ([][]common.Hash, [][]byte) { - var logData [][]byte - var topics [][]common.Hash - for _, lgs := range s.logs { - for _, log := range lgs { - topics = append(topics, log.Topics) - logData = append(logData, common.CopyBytes(log.Data)) - } - } - return topics, logData -} - -// AddPreimage records a SHA3 preimage seen by the VM. -func (s *StateDB) AddPreimage(hash common.Hash, preimage []byte) { - if _, ok := s.preimages[hash]; !ok { - s.journal.append(addPreimageChange{hash: hash}) - pi := make([]byte, len(preimage)) - copy(pi, preimage) - s.preimages[hash] = pi - } -} - -// Preimages returns a list of SHA3 preimages that have been submitted. -func (s *StateDB) Preimages() map[common.Hash][]byte { - return s.preimages -} - -// AddRefund adds gas to the refund counter -func (s *StateDB) AddRefund(gas uint64) { - s.journal.append(refundChange{prev: s.refund}) - s.refund += gas -} - -// SubRefund removes gas from the refund counter. -// This method will set the refund counter to 0 if the gas is greater than the current refund. -func (s *StateDB) SubRefund(gas uint64) { - s.journal.append(refundChange{prev: s.refund}) - if gas > s.refund { - log.Warn("Setting refund to 0", "currentRefund", s.refund, "gas", gas) - s.refund = 0 - return - } - s.refund -= gas -} - -// Exist reports whether the given account address exists in the state. -// Notably this also returns true for self-destructed accounts. -func (s *StateDB) Exist(addr common.Address) bool { - return s.getStateObject(addr) != nil -} - -// Empty returns whether the state object is either non-existent -// or empty according to the EIP161 specification (balance = nonce = code = 0) -func (s *StateDB) Empty(addr common.Address) bool { - so := s.getStateObject(addr) - return so == nil || so.empty() -} - -// GetBalance retrieves the balance from the given address or 0 if object not found -func (s *StateDB) GetBalance(addr common.Address) *uint256.Int { - stateObject := s.getStateObject(addr) - if stateObject != nil { - return stateObject.Balance() - } - return common.U2560 -} - -// GetNonce retrieves the nonce from the given address or 0 if object not found -func (s *StateDB) GetNonce(addr common.Address) uint64 { - stateObject := s.getStateObject(addr) - if stateObject != nil { - return stateObject.Nonce() - } - - return 0 -} - -// GetStorageRoot retrieves the storage root from the given address or empty -// if object not found. -func (s *StateDB) GetStorageRoot(addr common.Address) common.Hash { - stateObject := s.getStateObject(addr) - if stateObject != nil { - return stateObject.Root() - } - return common.Hash{} -} - -// TxIndex returns the current transaction index set by Prepare. -func (s *StateDB) TxIndex() int { - return s.txIndex -} - -func (s *StateDB) GetCode(addr common.Address) []byte { - stateObject := s.getStateObject(addr) - if stateObject != nil { - return stateObject.Code() - } - return nil -} - -func (s *StateDB) GetCodeSize(addr common.Address) int { - stateObject := s.getStateObject(addr) - if stateObject != nil { - return stateObject.CodeSize() - } - return 0 -} - -func (s *StateDB) GetCodeHash(addr common.Address) common.Hash { - stateObject := s.getStateObject(addr) - if stateObject != nil { - return common.BytesToHash(stateObject.CodeHash()) - } - return common.Hash{} + return ethstate.WithWorkerPools(func() ethstate.WorkerPool { return pool }) } // GetState retrieves a value from the given account's storage trie. func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { - stateObject := s.getStateObject(addr) - if stateObject != nil { - return stateObject.GetState(hash) - } - return common.Hash{} -} - -// GetCommittedState retrieves a value from the given account's committed storage trie. -func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash { - stateObject := s.getStateObject(addr) - if stateObject != nil { - return stateObject.GetCommittedState(hash) - } - return common.Hash{} -} - -// Database retrieves the low level database supporting the lower level trie ops. -func (s *StateDB) Database() Database { - return s.db -} - -func (s *StateDB) HasSelfDestructed(addr common.Address) bool { - stateObject := s.getStateObject(addr) - if stateObject != nil { - return stateObject.selfDestructed - } - return false -} - -/* - * SETTERS - */ - -// AddBalance adds amount to the account associated with addr. -func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int) { - stateObject := s.getOrNewStateObject(addr) - if stateObject != nil { - stateObject.AddBalance(amount) - } -} - -// SubBalance subtracts amount from the account associated with addr. -func (s *StateDB) SubBalance(addr common.Address, amount *uint256.Int) { - stateObject := s.getOrNewStateObject(addr) - if stateObject != nil { - stateObject.SubBalance(amount) - } -} - -func (s *StateDB) SetBalance(addr common.Address, amount *uint256.Int) { - stateObject := s.getOrNewStateObject(addr) - if stateObject != nil { - stateObject.SetBalance(amount) - } -} - -func (s *StateDB) SetNonce(addr common.Address, nonce uint64) { - stateObject := s.getOrNewStateObject(addr) - if stateObject != nil { - stateObject.SetNonce(nonce) - } -} - -func (s *StateDB) SetCode(addr common.Address, code []byte) { - stateObject := s.getOrNewStateObject(addr) - if stateObject != nil { - stateObject.SetCode(crypto.Keccak256Hash(code), code) - } + return s.StateDB.GetState(addr, hash) } func (s *StateDB) SetState(addr common.Address, key, value common.Hash) { - stateObject := s.getOrNewStateObject(addr) - if stateObject != nil { - stateObject.SetState(key, value) - } -} - -// SetStorage replaces the entire storage for the specified account with given -// storage. This function should only be used for debugging and the mutations -// must be discarded afterwards. -func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common.Hash) { - // SetStorage needs to wipe existing storage. We achieve this by pretending - // that the account self-destructed earlier in this block, by flagging - // it in stateObjectsDestruct. The effect of doing so is that storage lookups - // will not hit disk, since it is assumed that the disk-data is belonging - // to a previous incarnation of the object. - // - // TODO(rjl493456442) this function should only be supported by 'unwritable' - // state and all mutations made should all be discarded afterwards. - if _, ok := s.stateObjectsDestruct[addr]; !ok { - s.stateObjectsDestruct[addr] = nil - } - stateObject := s.getOrNewStateObject(addr) - for k, v := range storage { - stateObject.SetState(k, v) - } -} - -// SelfDestruct marks the given account as selfdestructed. -// This clears the account balance. -// -// The account's state object is still available until the state is committed, -// getStateObject will return a non-nil account after SelfDestruct. -func (s *StateDB) SelfDestruct(addr common.Address) { - stateObject := s.getStateObject(addr) - if stateObject == nil { - return - } - s.journal.append(selfDestructChange{ - account: &addr, - prev: stateObject.selfDestructed, - prevbalance: new(uint256.Int).Set(stateObject.Balance()), - }) - stateObject.markSelfdestructed() - stateObject.data.Balance = new(uint256.Int) -} - -func (s *StateDB) Selfdestruct6780(addr common.Address) { - stateObject := s.getStateObject(addr) - if stateObject == nil { - return - } - - if stateObject.created { - s.SelfDestruct(addr) - } -} - -// SetTransientState sets transient storage for a given account. It -// adds the change to the journal so that it can be rolled back -// to its previous value if there is a revert. -func (s *StateDB) SetTransientState(addr common.Address, key, value common.Hash) { - prev := s.GetTransientState(addr, key) - if prev == value { - return - } - s.journal.append(transientStorageChange{ - account: &addr, - key: key, - prevalue: prev, - }) - s.setTransientState(addr, key, value) -} - -// setTransientState is a lower level setter for transient storage. It -// is called during a revert to prevent modifications to the journal. -func (s *StateDB) setTransientState(addr common.Address, key, value common.Hash) { - s.transientStorage.Set(addr, key, value) -} - -// GetTransientState gets transient storage for a given account. -func (s *StateDB) GetTransientState(addr common.Address, key common.Hash) common.Hash { - return s.transientStorage.Get(addr, key) -} - -// -// Setting, updating & deleting state object methods. -// - -// updateStateObject writes the given object to the trie. -func (s *StateDB) updateStateObject(obj *stateObject) { - // Track the amount of time wasted on updating the account from the trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) - } - // Encode the account and update the account trie - addr := obj.Address() - if err := s.trie.UpdateAccount(addr, &obj.data); err != nil { - s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err)) - } - if obj.dirtyCode { - s.trie.UpdateContractCode(obj.Address(), common.BytesToHash(obj.CodeHash()), obj.code) - } - // Cache the data until commit. Note, this update mechanism is not symmetric - // to the deletion, because whereas it is enough to track account updates - // at commit time, deletions need tracking at transaction boundary level to - // ensure we capture state clearing. - s.accounts[obj.addrHash] = types.SlimAccountRLP(obj.data) - - // Track the original value of mutated account, nil means it was not present. - // Skip if it has been tracked (because updateStateObject may be called - // multiple times in a block). - if _, ok := s.accountsOrigin[obj.address]; !ok { - if obj.origin == nil { - s.accountsOrigin[obj.address] = nil - } else { - s.accountsOrigin[obj.address] = types.SlimAccountRLP(*obj.origin) - } - } -} - -// deleteStateObject removes the given object from the state trie. -func (s *StateDB) deleteStateObject(obj *stateObject) { - // Track the amount of time wasted on deleting the account from the trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) - } - // Delete the account from the trie - addr := obj.Address() - if err := s.trie.DeleteAccount(addr); err != nil { - s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err)) - } -} - -// getStateObject retrieves a state object given by the address, returning nil if -// the object is not found or was deleted in this execution context. If you need -// to differentiate between non-existent/just-deleted, use getDeletedStateObject. -func (s *StateDB) getStateObject(addr common.Address) *stateObject { - if obj := s.getDeletedStateObject(addr); obj != nil && !obj.deleted { - return obj - } - return nil -} - -// getDeletedStateObject is similar to getStateObject, but instead of returning -// nil for a deleted state object, it returns the actual object with the deleted -// flag set. This is needed by the state journal to revert to the correct s- -// destructed object instead of wiping all knowledge about the state object. -func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { - // Prefer live objects if any is available - if obj := s.stateObjects[addr]; obj != nil { - return obj - } - // If no live objects are available, attempt to use snapshots - var data *types.StateAccount - if s.snap != nil { - start := time.Now() - acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes())) - if metrics.EnabledExpensive { - s.SnapshotAccountReads += time.Since(start) - } - if err == nil { - if acc == nil { - return nil - } - data = &types.StateAccount{ - Nonce: acc.Nonce, - Balance: acc.Balance, - CodeHash: acc.CodeHash, - Root: common.BytesToHash(acc.Root), - } - if len(data.CodeHash) == 0 { - data.CodeHash = types.EmptyCodeHash.Bytes() - } - if data.Root == (common.Hash{}) { - data.Root = types.EmptyRootHash - } - } - } - // If snapshot unavailable or reading from it failed, load from the database - if data == nil { - start := time.Now() - var err error - data, err = s.trie.GetAccount(addr) - if metrics.EnabledExpensive { - s.AccountReads += time.Since(start) - } - if err != nil { - s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %w", addr.Bytes(), err)) - return nil - } - if data == nil { - return nil - } - } - // Insert into the live set - obj := newObject(s, addr, data) - s.setStateObject(obj) - return obj -} - -func (s *StateDB) setStateObject(object *stateObject) { - s.stateObjects[object.Address()] = object -} - -// getOrNewStateObject retrieves a state object or create a new state object if nil. -func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject { - stateObject := s.getStateObject(addr) - if stateObject == nil { - stateObject, _ = s.createObject(addr) - } - return stateObject -} - -// createObject creates a new state object. If there is an existing account with -// the given address, it is overwritten and returned as the second return value. -func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { - prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that! - newobj = newObject(s, addr, nil) - if prev == nil { - s.journal.append(createObjectChange{account: &addr}) - } else { - // The original account should be marked as destructed and all cached - // account and storage data should be cleared as well. Note, it must - // be done here, otherwise the destruction event of "original account" - // will be lost. - _, prevdestruct := s.stateObjectsDestruct[prev.address] - if !prevdestruct { - s.stateObjectsDestruct[prev.address] = prev.origin - } - // There may be some cached account/storage data already since IntermediateRoot - // will be called for each transaction before byzantium fork which will always - // cache the latest account/storage data. - prevAccount, ok := s.accountsOrigin[prev.address] - s.journal.append(resetObjectChange{ - account: &addr, - prev: prev, - prevdestruct: prevdestruct, - prevAccount: s.accounts[prev.addrHash], - prevStorage: s.storages[prev.addrHash], - prevAccountOriginExist: ok, - prevAccountOrigin: prevAccount, - prevStorageOrigin: s.storagesOrigin[prev.address], - }) - delete(s.accounts, prev.addrHash) - delete(s.storages, prev.addrHash) - delete(s.accountsOrigin, prev.address) - delete(s.storagesOrigin, prev.address) - } - s.setStateObject(newobj) - if prev != nil && !prev.deleted { - return newobj, prev - } - return newobj, nil -} - -// CreateAccount explicitly creates a state object. If a state object with the address -// already exists the balance is carried over to the new account. -// -// CreateAccount is called during the EVM CREATE operation. The situation might arise that -// a contract does the following: -// -// 1. sends funds to sha(account ++ (nonce + 1)) -// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1) -// -// Carrying over the balance ensures that Ether doesn't disappear. -func (s *StateDB) CreateAccount(addr common.Address) { - newObj, prev := s.createObject(addr) - if prev != nil { - newObj.setBalance(prev.data.Balance) - } -} - -// Copy creates a deep, independent copy of the state. -// Snapshots of the copied state cannot be applied to the copy. -func (s *StateDB) Copy() *StateDB { - // Copy all the basic fields, initialize the memory ones - state := &StateDB{ - db: s.db, - trie: s.db.CopyTrie(s.trie), - originalRoot: s.originalRoot, - accounts: make(map[common.Hash][]byte), - storages: make(map[common.Hash]map[common.Hash][]byte), - accountsOrigin: make(map[common.Address][]byte), - storagesOrigin: make(map[common.Address]map[common.Hash][]byte), - stateObjects: make(map[common.Address]*stateObject, len(s.journal.dirties)), - stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)), - stateObjectsDirty: make(map[common.Address]struct{}, len(s.journal.dirties)), - stateObjectsDestruct: make(map[common.Address]*types.StateAccount, len(s.stateObjectsDestruct)), - refund: s.refund, - logs: make(map[common.Hash][]*types.Log, len(s.logs)), - logSize: s.logSize, - preimages: make(map[common.Hash][]byte, len(s.preimages)), - journal: newJournal(), - hasher: crypto.NewKeccakState(), - - // In order for the block producer to be able to use and make additions - // to the snapshot tree, we need to copy that as well. Otherwise, any - // block mined by ourselves will cause gaps in the tree, and force the - // miner to operate trie-backed only. - snap: s.snap, - } - // Copy the dirty states, logs, and preimages - for addr := range s.journal.dirties { - // As documented [here](https://github.com/ethereum/go-ethereum/pull/16485#issuecomment-380438527), - // and in the Finalise-method, there is a case where an object is in the journal but not - // in the stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we need to check for - // nil - if object, exist := s.stateObjects[addr]; exist { - // Even though the original object is dirty, we are not copying the journal, - // so we need to make sure that any side-effect the journal would have caused - // during a commit (or similar op) is already applied to the copy. - state.stateObjects[addr] = object.deepCopy(state) - - state.stateObjectsDirty[addr] = struct{}{} // Mark the copy dirty to force internal (code/state) commits - state.stateObjectsPending[addr] = struct{}{} // Mark the copy pending to force external (account) commits - } - } - // Above, we don't copy the actual journal. This means that if the copy - // is copied, the loop above will be a no-op, since the copy's journal - // is empty. Thus, here we iterate over stateObjects, to enable copies - // of copies. - for addr := range s.stateObjectsPending { - if _, exist := state.stateObjects[addr]; !exist { - state.stateObjects[addr] = s.stateObjects[addr].deepCopy(state) - } - state.stateObjectsPending[addr] = struct{}{} - } - for addr := range s.stateObjectsDirty { - if _, exist := state.stateObjects[addr]; !exist { - state.stateObjects[addr] = s.stateObjects[addr].deepCopy(state) - } - state.stateObjectsDirty[addr] = struct{}{} - } - // Deep copy the destruction markers. - for addr, value := range s.stateObjectsDestruct { - state.stateObjectsDestruct[addr] = value - } - // Deep copy the state changes made in the scope of block - // along with their original values. - state.accounts = copySet(s.accounts) - state.storages = copy2DSet(s.storages) - state.accountsOrigin = copySet(state.accountsOrigin) - state.storagesOrigin = copy2DSet(state.storagesOrigin) - - // Deep copy the logs occurred in the scope of block - for hash, logs := range s.logs { - cpy := make([]*types.Log, len(logs)) - for i, l := range logs { - cpy[i] = new(types.Log) - *cpy[i] = *l - } - state.logs[hash] = cpy - } - // Deep copy the preimages occurred in the scope of block - for hash, preimage := range s.preimages { - state.preimages[hash] = preimage - } - // Do we need to copy the access list and transient storage? - // In practice: No. At the start of a transaction, these two lists are empty. - // In practice, we only ever copy state _between_ transactions/blocks, never - // in the middle of a transaction. However, it doesn't cost us much to copy - // empty lists, so we do it anyway to not blow up if we ever decide copy them - // in the middle of a transaction. - state.accessList = s.accessList.Copy() - state.transientStorage = s.transientStorage.Copy() - - // If there's a prefetcher running, make an inactive copy of it that can - // only access data but does not actively preload (since the user will not - // know that they need to explicitly terminate an active copy). - if s.prefetcher != nil { - state.prefetcher = s.prefetcher.copy() - } - return state -} - -// Snapshot returns an identifier for the current revision of the state. -func (s *StateDB) Snapshot() int { - id := s.nextRevisionId - s.nextRevisionId++ - s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()}) - return id -} - -// RevertToSnapshot reverts all state changes made since the given revision. -func (s *StateDB) RevertToSnapshot(revid int) { - // Find the snapshot in the stack of valid snapshots. - idx := sort.Search(len(s.validRevisions), func(i int) bool { - return s.validRevisions[i].id >= revid - }) - if idx == len(s.validRevisions) || s.validRevisions[idx].id != revid { - panic(fmt.Errorf("revision id %v cannot be reverted", revid)) - } - snapshot := s.validRevisions[idx].journalIndex - - // Replay the journal to undo changes and remove invalidated snapshots - s.journal.revert(s, snapshot) - s.validRevisions = s.validRevisions[:idx] -} - -// GetRefund returns the current value of the refund counter. -func (s *StateDB) GetRefund() uint64 { - return s.refund -} - -// Finalise finalises the state by removing the destructed objects and clears -// the journal as well as the refunds. Finalise, however, will not push any updates -// into the tries just yet. Only IntermediateRoot or Commit will do that. -func (s *StateDB) Finalise(deleteEmptyObjects bool) { - addressesToPrefetch := make([][]byte, 0, len(s.journal.dirties)) - for addr := range s.journal.dirties { - obj, exist := s.stateObjects[addr] - if !exist { - // ripeMD is 'touched' at block 1714175, in tx 0x1237f737031e40bcde4a8b7e717b2d15e3ecadfe49bb1bbc71ee9deb09c6fcf2 - // That tx goes out of gas, and although the notion of 'touched' does not exist there, the - // touch-event will still be recorded in the journal. Since ripeMD is a special snowflake, - // it will persist in the journal even though the journal is reverted. In this special circumstance, - // it may exist in `s.journal.dirties` but not in `s.stateObjects`. - // Thus, we can safely ignore it here - continue - } - if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) { - obj.deleted = true - - // We need to maintain account deletions explicitly (will remain - // set indefinitely). Note only the first occurred self-destruct - // event is tracked. - if _, ok := s.stateObjectsDestruct[obj.address]; !ok { - s.stateObjectsDestruct[obj.address] = obj.origin - } - // Note, we can't do this only at the end of a block because multiple - // transactions within the same block might self destruct and then - // resurrect an account; but the snapshotter needs both events. - delete(s.accounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a resurrect) - delete(s.storages, obj.addrHash) // Clear out any previously updated storage data (may be recreated via a resurrect) - delete(s.accountsOrigin, obj.address) // Clear out any previously updated account data (may be recreated via a resurrect) - delete(s.storagesOrigin, obj.address) // Clear out any previously updated storage data (may be recreated via a resurrect) - } else { - obj.finalise(true) // Prefetch slots in the background - } - obj.created = false - s.stateObjectsPending[addr] = struct{}{} - s.stateObjectsDirty[addr] = struct{}{} - - // At this point, also ship the address off to the precacher. The precacher - // will start loading tries, and when the change is eventually committed, - // the commit-phase will be a lot faster - addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure - } - if s.prefetcher != nil && len(addressesToPrefetch) > 0 { - s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch) - } - // Invalidate journal because reverting across transactions is not allowed. - s.clearJournalAndRefund() -} - -// IntermediateRoot computes the current root hash of the state trie. -// It is called in between transactions to get the root hash that -// goes into transaction receipts. -func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { - // Finalise all the dirty storage states and write them into the tries - s.Finalise(deleteEmptyObjects) - - // If there was a trie prefetcher operating, it gets aborted and irrevocably - // modified after we start retrieving tries. Remove it from the statedb after - // this round of use. - // - // This is weird pre-byzantium since the first tx runs with a prefetcher and - // the remainder without, but pre-byzantium even the initial prefetcher is - // useless, so no sleep lost. - prefetcher := s.prefetcher - if s.prefetcher != nil { - defer func() { - s.prefetcher.close() - s.prefetcher = nil - }() - } - // Although naively it makes sense to retrieve the account trie and then do - // the contract storage and account updates sequentially, that short circuits - // the account prefetcher. Instead, let's process all the storage updates - // first, giving the account prefetches just a few more milliseconds of time - // to pull useful data from disk. - for addr := range s.stateObjectsPending { - if obj := s.stateObjects[addr]; !obj.deleted { - obj.updateRoot() - } - } - // Now we're about to start to write changes to the trie. The trie is so far - // _untouched_. We can check with the prefetcher, if it can give us a trie - // which has the same root, but also has some content loaded into it. - if prefetcher != nil { - if trie := prefetcher.trie(common.Hash{}, s.originalRoot); trie != nil { - s.trie = trie - } - } - usedAddrs := make([][]byte, 0, len(s.stateObjectsPending)) - for addr := range s.stateObjectsPending { - if obj := s.stateObjects[addr]; obj.deleted { - s.deleteStateObject(obj) - s.AccountDeleted += 1 - } else { - s.updateStateObject(obj) - s.AccountUpdated += 1 - } - usedAddrs = append(usedAddrs, common.CopyBytes(addr[:])) // Copy needed for closure - } - if prefetcher != nil { - prefetcher.used(common.Hash{}, s.originalRoot, usedAddrs) - } - if len(s.stateObjectsPending) > 0 { - s.stateObjectsPending = make(map[common.Address]struct{}) - } - // Track the amount of time wasted on hashing the account trie - if metrics.EnabledExpensive { - defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) - } - return s.trie.Hash() + s.StateDB.SetState(addr, key, value) } // SetTxContext sets the current transaction hash and index which are @@ -976,443 +101,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { func (s *StateDB) SetTxContext(thash common.Hash, ti int) { s.thash = thash s.txIndex = ti -} - -func (s *StateDB) clearJournalAndRefund() { - if len(s.journal.entries) > 0 { - s.journal = newJournal() - s.refund = 0 - } - s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entries -} - -// fastDeleteStorage is the function that efficiently deletes the storage trie -// of a specific account. It leverages the associated state snapshot for fast -// storage iteration and constructs trie node deletion markers by creating -// stack trie with iterated slots. -func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (bool, common.StorageSize, map[common.Hash][]byte, *trienode.NodeSet, error) { - iter, _ := s.snap.StorageIterator(addrHash, common.Hash{}) - defer iter.Release() - - var ( - size common.StorageSize - nodes = trienode.NewNodeSet(addrHash) - slots = make(map[common.Hash][]byte) - ) - options := trie.NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - nodes.AddNode(path, trienode.NewDeleted()) - size += common.StorageSize(len(path)) - }) - stack := trie.NewStackTrie(options) - for iter.Next() { - if size > storageDeleteLimit { - return true, size, nil, nil, nil - } - slot := common.CopyBytes(iter.Slot()) - if err := iter.Error(); err != nil { // error might occur after Slot function - return false, 0, nil, nil, err - } - size += common.StorageSize(common.HashLength + len(slot)) - slots[iter.Hash()] = slot - - if err := stack.Update(iter.Hash().Bytes(), slot); err != nil { - return false, 0, nil, nil, err - } - } - if err := iter.Error(); err != nil { // error might occur during iteration - return false, 0, nil, nil, err - } - if stack.Hash() != root { - return false, 0, nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash()) - } - return false, size, slots, nodes, nil -} - -// slowDeleteStorage serves as a less-efficient alternative to "fastDeleteStorage," -// employed when the associated state snapshot is not available. It iterates the -// storage slots along with all internal trie nodes via trie directly. -func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (bool, common.StorageSize, map[common.Hash][]byte, *trienode.NodeSet, error) { - tr, err := s.db.OpenStorageTrie(s.originalRoot, addr, root, s.trie) - if err != nil { - return false, 0, nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err) - } - it, err := tr.NodeIterator(nil) - if err != nil { - return false, 0, nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err) - } - var ( - size common.StorageSize - nodes = trienode.NewNodeSet(addrHash) - slots = make(map[common.Hash][]byte) - ) - for it.Next(true) { - if size > storageDeleteLimit { - return true, size, nil, nil, nil - } - if it.Leaf() { - slots[common.BytesToHash(it.LeafKey())] = common.CopyBytes(it.LeafBlob()) - size += common.StorageSize(common.HashLength + len(it.LeafBlob())) - continue - } - if it.Hash() == (common.Hash{}) { - continue - } - size += common.StorageSize(len(it.Path())) - nodes.AddNode(it.Path(), trienode.NewDeleted()) - } - if err := it.Error(); err != nil { - return false, 0, nil, nil, err - } - return false, size, slots, nodes, nil -} - -// deleteStorage is designed to delete the storage trie of a designated account. -// It could potentially be terminated if the storage size is excessively large, -// potentially leading to an out-of-memory panic. The function will make an attempt -// to utilize an efficient strategy if the associated state snapshot is reachable; -// otherwise, it will resort to a less-efficient approach. -func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (bool, map[common.Hash][]byte, *trienode.NodeSet, error) { - var ( - start = time.Now() - err error - aborted bool - size common.StorageSize - slots map[common.Hash][]byte - nodes *trienode.NodeSet - ) - // The fast approach can be failed if the snapshot is not fully - // generated, or it's internally corrupted. Fallback to the slow - // one just in case. - if s.snap != nil { - aborted, size, slots, nodes, err = s.fastDeleteStorage(addrHash, root) - } - if s.snap == nil || err != nil { - aborted, size, slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) - } - if err != nil { - return false, nil, nil, err - } - if metrics.EnabledExpensive { - if aborted { - slotDeletionSkip.Inc(1) - } - n := int64(len(slots)) - - slotDeletionMaxCount.UpdateIfGt(int64(len(slots))) - slotDeletionMaxSize.UpdateIfGt(int64(size)) - - slotDeletionTimer.UpdateSince(start) - slotDeletionCount.Mark(n) - slotDeletionSize.Mark(int64(size)) - } - return aborted, slots, nodes, nil -} - -// handleDestruction processes all destruction markers and deletes the account -// and associated storage slots if necessary. There are four possible situations -// here: -// -// - the account was not existent and be marked as destructed -// -// - the account was not existent and be marked as destructed, -// however, it's resurrected later in the same block. -// -// - the account was existent and be marked as destructed -// -// - the account was existent and be marked as destructed, -// however it's resurrected later in the same block. -// -// In case (a), nothing needs be deleted, nil to nil transition can be ignored. -// -// In case (b), nothing needs be deleted, nil is used as the original value for -// newly created account and storages -// -// In case (c), **original** account along with its storages should be deleted, -// with their values be tracked as original value. -// -// In case (d), **original** account along with its storages should be deleted, -// with their values be tracked as original value. -func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.Address]struct{}, error) { - // Short circuit if geth is running with hash mode. This procedure can consume - // considerable time and storage deletion isn't supported in hash mode, thus - // preemptively avoiding unnecessary expenses. - incomplete := make(map[common.Address]struct{}) - if s.db.TrieDB().Scheme() == rawdb.HashScheme { - return incomplete, nil - } - for addr, prev := range s.stateObjectsDestruct { - // The original account was non-existing, and it's marked as destructed - // in the scope of block. It can be case (a) or (b). - // - for (a), skip it without doing anything. - // - for (b), track account's original value as nil. It may overwrite - // the data cached in s.accountsOrigin set by 'updateStateObject'. - addrHash := crypto.Keccak256Hash(addr[:]) - if prev == nil { - if _, ok := s.accounts[addrHash]; ok { - s.accountsOrigin[addr] = nil // case (b) - } - continue - } - // It can overwrite the data in s.accountsOrigin set by 'updateStateObject'. - s.accountsOrigin[addr] = types.SlimAccountRLP(*prev) // case (c) or (d) - - // Short circuit if the storage was empty. - if prev.Root == types.EmptyRootHash { - continue - } - // Remove storage slots belong to the account. - aborted, slots, set, err := s.deleteStorage(addr, addrHash, prev.Root) - if err != nil { - return nil, fmt.Errorf("failed to delete storage, err: %w", err) - } - // The storage is too huge to handle, skip it but mark as incomplete. - // For case (d), the account is resurrected might with a few slots - // created. In this case, wipe the entire storage state diff because - // of aborted deletion. - if aborted { - incomplete[addr] = struct{}{} - delete(s.storagesOrigin, addr) - continue - } - if s.storagesOrigin[addr] == nil { - s.storagesOrigin[addr] = slots - } else { - // It can overwrite the data in s.storagesOrigin[addrHash] set by - // 'object.updateTrie'. - for key, val := range slots { - s.storagesOrigin[addr][key] = val - } - } - if err := nodes.Merge(set); err != nil { - return nil, err - } - } - return incomplete, nil -} - -// Commit writes the state to the underlying in-memory trie database. -func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error) { - return s.commit(block, deleteEmptyObjects, nil, common.Hash{}, common.Hash{}) -} - -// CommitWithSnap writes the state to the underlying in-memory trie database and -// generates a snapshot layer for the newly committed state. -func (s *StateDB) CommitWithSnap(block uint64, deleteEmptyObjects bool, snaps *snapshot.Tree, blockHash, parentHash common.Hash) (common.Hash, error) { - return s.commit(block, deleteEmptyObjects, snaps, blockHash, parentHash) -} - -// Once the state is committed, tries cached in stateDB (including account -// trie, storage tries) will no longer be functional. A new state instance -// must be created with new root and updated database for accessing post- -// commit states. -// -// The associated block number of the state transition is also provided -// for more chain context. -func (s *StateDB) commit(block uint64, deleteEmptyObjects bool, snaps *snapshot.Tree, blockHash, parentHash common.Hash) (common.Hash, error) { - // Short circuit in case any database failure occurred earlier. - if s.dbErr != nil { - return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) - } - // Finalize any pending changes and merge everything into the tries - s.IntermediateRoot(deleteEmptyObjects) - - // Commit objects to the trie, measuring the elapsed time - var ( - accountTrieNodesUpdated int - accountTrieNodesDeleted int - storageTrieNodesUpdated int - storageTrieNodesDeleted int - nodes = trienode.NewMergedNodeSet() - codeWriter = s.db.DiskDB().NewBatch() - ) - // Handle all state deletions first - incomplete, err := s.handleDestruction(nodes) - if err != nil { - return common.Hash{}, err - } - // Handle all state updates afterwards - for addr := range s.stateObjectsDirty { - obj := s.stateObjects[addr] - if obj.deleted { - continue - } - // Write any contract code associated with the state object - if obj.code != nil && obj.dirtyCode { - rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) - obj.dirtyCode = false - } - // Write any storage changes in the state object to its storage trie - set, err := obj.commit() - if err != nil { - return common.Hash{}, err - } - // Merge the dirty nodes of storage trie into global set. It is possible - // that the account was destructed and then resurrected in the same block. - // In this case, the node set is shared by both accounts. - if set != nil { - if err := nodes.Merge(set); err != nil { - return common.Hash{}, err - } - updates, deleted := set.Size() - storageTrieNodesUpdated += updates - storageTrieNodesDeleted += deleted - } - } - if codeWriter.ValueSize() > 0 { - if err := codeWriter.Write(); err != nil { - log.Crit("Failed to commit dirty codes", "error", err) - } - } - // Write the account trie changes, measuring the amount of wasted time - var start time.Time - if metrics.EnabledExpensive { - start = time.Now() - } - root, set, err := s.trie.Commit(true) - if err != nil { - return common.Hash{}, err - } - // Merge the dirty nodes of account trie into global set - if set != nil { - if err := nodes.Merge(set); err != nil { - return common.Hash{}, err - } - accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size() - } - if metrics.EnabledExpensive { - s.AccountCommits += time.Since(start) - - accountUpdatedMeter.Mark(int64(s.AccountUpdated)) - storageUpdatedMeter.Mark(int64(s.StorageUpdated)) - accountDeletedMeter.Mark(int64(s.AccountDeleted)) - storageDeletedMeter.Mark(int64(s.StorageDeleted)) - accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated)) - accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted)) - storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated)) - storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted)) - s.AccountUpdated, s.AccountDeleted = 0, 0 - s.StorageUpdated, s.StorageDeleted = 0, 0 - } - // If snapshotting is enabled, update the snapshot tree with this new version - if snaps != nil { - start := time.Now() - if s.snap == nil { - log.Error(fmt.Sprintf("cannot commit with snaps without a pre-existing snap layer, parentHash: %s, blockHash: %s", parentHash, blockHash)) - } - if err := snaps.Update(blockHash, root, parentHash, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages); err != nil { - log.Warn("Failed to update snapshot tree", "to", root, "err", err) - } - if metrics.EnabledExpensive { - s.SnapshotCommits += time.Since(start) - } - s.snap = nil - } - if root == (common.Hash{}) { - root = types.EmptyRootHash - } - origin := s.originalRoot - if origin == (common.Hash{}) { - origin = types.EmptyRootHash - } - if root != origin { - start := time.Now() - set := triestate.New(s.accountsOrigin, s.storagesOrigin, incomplete) - if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil { - return common.Hash{}, err - } - s.originalRoot = root - if metrics.EnabledExpensive { - s.TrieDBCommits += time.Since(start) - } - if s.onCommit != nil { - s.onCommit(set) - } - } - // Clear all internal flags at the end of commit operation. - s.accounts = make(map[common.Hash][]byte) - s.storages = make(map[common.Hash]map[common.Hash][]byte) - s.accountsOrigin = make(map[common.Address][]byte) - s.storagesOrigin = make(map[common.Address]map[common.Hash][]byte) - s.stateObjectsDirty = make(map[common.Address]struct{}) - s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount) - return root, nil -} - -// Prepare handles the preparatory steps for executing a state transition with. -// This method must be invoked before state transition. -// -// Berlin fork: -// - Add sender to access list (2929) -// - Add destination to access list (2929) -// - Add precompiles to access list (2929) -// - Add the contents of the optional tx access list (2930) -// -// Potential EIPs: -// - Reset access list (Berlin) -// - Add coinbase to access list (EIP-3651/Durango) -// - Reset transient storage (EIP-1153) -func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) { - if rules.IsBerlin { - // Clear out any leftover from previous executions - al := newAccessList() - s.accessList = al - - al.AddAddress(sender) - if dst != nil { - al.AddAddress(*dst) - // If it's a create-tx, the destination will be added inside evm.create - } - for _, addr := range precompiles { - al.AddAddress(addr) - } - for _, el := range list { - al.AddAddress(el.Address) - for _, key := range el.StorageKeys { - al.AddSlot(el.Address, key) - } - } - if rules.IsShanghai { // EIP-3651: warm coinbase - al.AddAddress(coinbase) - } - } - // Reset transient storage at the beginning of transaction execution - s.transientStorage = newTransientStorage() -} - -// AddAddressToAccessList adds the given address to the access list -func (s *StateDB) AddAddressToAccessList(addr common.Address) { - if s.accessList.AddAddress(addr) { - s.journal.append(accessListAddAccountChange{&addr}) - } -} - -// AddSlotToAccessList adds the given (address, slot)-tuple to the access list -func (s *StateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) { - addrMod, slotMod := s.accessList.AddSlot(addr, slot) - if addrMod { - // In practice, this should not happen, since there is no way to enter the - // scope of 'address' without having the 'address' become already added - // to the access list (via call-variant, create, etc). - // Better safe than sorry, though - s.journal.append(accessListAddAccountChange{&addr}) - } - if slotMod { - s.journal.append(accessListAddSlotChange{ - address: &addr, - slot: &slot, - }) - } -} - -// AddressInAccessList returns true if the given address is in the access list. -func (s *StateDB) AddressInAccessList(addr common.Address) bool { - return s.accessList.ContainsAddress(addr) -} - -// SlotInAccessList returns true if the given (address, slot)-tuple is in the access list. -func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) { - return s.accessList.Contains(addr, slot) + s.StateDB.SetTxContext(thash, ti) } // GetTxHash returns the current tx hash on the StateDB set by SetTxContext. @@ -1420,37 +109,28 @@ func (s *StateDB) GetTxHash() common.Hash { return s.thash } -// convertAccountSet converts a provided account set from address keyed to hash keyed. -func (s *StateDB) convertAccountSet(set map[common.Address]*types.StateAccount) map[common.Hash]struct{} { - ret := make(map[common.Hash]struct{}, len(set)) - for addr := range set { - obj, exist := s.stateObjects[addr] - if !exist { - ret[crypto.Keccak256Hash(addr[:])] = struct{}{} - } else { - ret[obj.addrHash] = struct{}{} - } +func (s *StateDB) Copy() *StateDB { + return &StateDB{ + StateDB: s.StateDB.Copy(), + db: s.db, + snaps: s.snaps, + thash: s.thash, + txIndex: s.txIndex, } - return ret } -// copySet returns a deep-copied set. -func copySet[k comparable](set map[k][]byte) map[k][]byte { - copied := make(map[k][]byte, len(set)) - for key, val := range set { - copied[key] = common.CopyBytes(val) - } - return copied +// NormalizeCoinID ORs the 0th bit of the first byte in +// [coinID], which ensures this bit will be 1 and all other +// bits are left the same. +// This partitions multicoin storage from normal state storage. +func NormalizeCoinID(coinID *common.Hash) { + coinID[0] |= 0x01 } -// copy2DSet returns a two-dimensional deep-copied set. -func copy2DSet[k comparable](set map[k]map[common.Hash][]byte) map[k]map[common.Hash][]byte { - copied := make(map[k]map[common.Hash][]byte, len(set)) - for addr, subset := range set { - copied[addr] = make(map[common.Hash][]byte, len(subset)) - for key, val := range subset { - copied[addr][key] = common.CopyBytes(val) - } - } - return copied +// NormalizeStateKey ANDs the 0th bit of the first byte in +// [key], which ensures this bit will be 0 and all other bits +// are left the same. +// This partitions normal state storage from multicoin storage. +func NormalizeStateKey(key *common.Hash) { + key[0] &= 0xfe } diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go deleted file mode 100644 index 7bd3c0b602..0000000000 --- a/core/state/statedb_fuzz_test.go +++ /dev/null @@ -1,402 +0,0 @@ -// (c) 2024, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2023 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 state - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "math" - "math/rand" - "reflect" - "strings" - "testing" - "testing/quick" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/state/snapshot" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ava-labs/subnet-evm/triedb/pathdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" - "github.com/holiman/uint256" -) - -// A stateTest checks that the state changes are correctly captured. Instances -// of this test with pseudorandom content are created by Generate. -// -// The test works as follows: -// -// A list of states are created by applying actions. The state changes between -// each state instance are tracked and be verified. -type stateTest struct { - addrs []common.Address // all account addresses - actions [][]testAction // modifications to the state, grouped by block - chunk int // The number of actions per chunk - err error // failure details are reported through this field -} - -// newStateTestAction creates a random action that changes state. -func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction { - actions := []testAction{ - { - name: "SetBalance", - fn: func(a testAction, s *StateDB) { - s.SetBalance(addr, uint256.NewInt(uint64(a.args[0]))) - }, - args: make([]int64, 1), - }, - { - name: "SetNonce", - fn: func(a testAction, s *StateDB) { - s.SetNonce(addr, uint64(a.args[0])) - }, - args: make([]int64, 1), - }, - { - name: "SetState", - fn: func(a testAction, s *StateDB) { - var key, val common.Hash - binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) - binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) - s.SetState(addr, key, val) - }, - args: make([]int64, 2), - }, - { - name: "SetCode", - fn: func(a testAction, s *StateDB) { - code := make([]byte, 16) - binary.BigEndian.PutUint64(code, uint64(a.args[0])) - binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) - s.SetCode(addr, code) - }, - args: make([]int64, 2), - }, - { - name: "CreateAccount", - fn: func(a testAction, s *StateDB) { - s.CreateAccount(addr) - }, - }, - { - name: "Selfdestruct", - fn: func(a testAction, s *StateDB) { - s.SelfDestruct(addr) - }, - }, - } - var nonRandom = index != -1 - if index == -1 { - index = r.Intn(len(actions)) - } - action := actions[index] - var names []string - if !action.noAddr { - names = append(names, addr.Hex()) - } - for i := range action.args { - if nonRandom { - action.args[i] = rand.Int63n(10000) + 1 // set balance to non-zero - } else { - action.args[i] = rand.Int63n(10000) - } - names = append(names, fmt.Sprint(action.args[i])) - } - action.name += " " + strings.Join(names, ", ") - return action -} - -// Generate returns a new snapshot test of the given size. All randomness is -// derived from r. -func (*stateTest) Generate(r *rand.Rand, size int) reflect.Value { - addrs := make([]common.Address, 5) - for i := range addrs { - addrs[i][0] = byte(i) - } - actions := make([][]testAction, rand.Intn(5)+1) - - for i := 0; i < len(actions); i++ { - actions[i] = make([]testAction, size) - for j := range actions[i] { - if j == 0 { - // Always include a set balance action to make sure - // the state changes are not empty. - actions[i][j] = newStateTestAction(common.HexToAddress("0xdeadbeef"), r, 0) - continue - } - actions[i][j] = newStateTestAction(addrs[r.Intn(len(addrs))], r, -1) - } - } - chunk := int(math.Sqrt(float64(size))) - if size > 0 && chunk == 0 { - chunk = 1 - } - return reflect.ValueOf(&stateTest{ - addrs: addrs, - actions: actions, - chunk: chunk, - }) -} - -func (test *stateTest) String() string { - out := new(bytes.Buffer) - for i, actions := range test.actions { - fmt.Fprintf(out, "---- block %d ----\n", i) - for j, action := range actions { - if j%test.chunk == 0 { - fmt.Fprintf(out, "---- transaction %d ----\n", j/test.chunk) - } - fmt.Fprintf(out, "%4d: %s\n", j%test.chunk, action.name) - } - } - return out.String() -} - -func (test *stateTest) run() bool { - var ( - roots []common.Hash - accountList []map[common.Address][]byte - storageList []map[common.Address]map[common.Hash][]byte - onCommit = func(states *triestate.Set) { - accountList = append(accountList, copySet(states.Accounts)) - storageList = append(storageList, copy2DSet(states.Storages)) - } - disk = rawdb.NewMemoryDatabase() - tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults}) - sdb = NewDatabaseWithNodeDB(disk, tdb) - byzantium = rand.Intn(2) == 0 - ) - defer disk.Close() - defer tdb.Close() - - var snaps *snapshot.Tree - if rand.Intn(3) == 0 { - snaps, _ = snapshot.New(snapshot.Config{ - CacheSize: 1, - NoBuild: false, - AsyncBuild: false, - }, disk, tdb, common.Hash{}, types.EmptyRootHash) - } - for i, actions := range test.actions { - root := types.EmptyRootHash - if i != 0 { - root = roots[len(roots)-1] - } - state, err := New(root, sdb, snaps) - if err != nil { - panic(err) - } - state.onCommit = onCommit - - for i, action := range actions { - if i%test.chunk == 0 && i != 0 { - if byzantium { - state.Finalise(true) // call finalise at the transaction boundary - } else { - state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary - } - } - action.fn(action, state) - } - if byzantium { - state.Finalise(true) // call finalise at the transaction boundary - } else { - state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary - } - nroot, err := state.Commit(0, true) // call commit at the block boundary - if err != nil { - panic(err) - } - if nroot == root { - return true // filter out non-change state transition - } - roots = append(roots, nroot) - } - for i := 0; i < len(test.actions); i++ { - root := types.EmptyRootHash - if i != 0 { - root = roots[i-1] - } - test.err = test.verify(root, roots[i], tdb, accountList[i], storageList[i]) - if test.err != nil { - return false - } - } - return true -} - -// verifyAccountCreation this function is called once the state diff says that -// specific account was not present. A serial of checks will be performed to -// ensure the state diff is correct, includes: -// -// - the account was indeed not present in trie -// - the account is present in new trie, nil->nil is regarded as invalid -// - the slots transition is correct -func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Database, otr, ntr *trie.Trie, addr common.Address, slots map[common.Hash][]byte) error { - // Verify account change - addrHash := crypto.Keccak256Hash(addr.Bytes()) - oBlob, err := otr.Get(addrHash.Bytes()) - if err != nil { - return err - } - nBlob, err := ntr.Get(addrHash.Bytes()) - if err != nil { - return err - } - if len(oBlob) != 0 { - return fmt.Errorf("unexpected account in old trie, %x", addrHash) - } - if len(nBlob) == 0 { - return fmt.Errorf("missing account in new trie, %x", addrHash) - } - - // Verify storage changes - var nAcct types.StateAccount - if err := rlp.DecodeBytes(nBlob, &nAcct); err != nil { - return err - } - // Account has no slot, empty slot set is expected - if nAcct.Root == types.EmptyRootHash { - if len(slots) != 0 { - return fmt.Errorf("unexpected slot changes %x", addrHash) - } - return nil - } - // Account has slots, ensure all new slots are contained - st, err := trie.New(trie.StorageTrieID(next, addrHash, nAcct.Root), db) - if err != nil { - return err - } - for key, val := range slots { - st.Update(key.Bytes(), val) - } - if st.Hash() != types.EmptyRootHash { - return errors.New("invalid slot changes") - } - return nil -} - -// verifyAccountUpdate this function is called once the state diff says that -// specific account was present. A serial of checks will be performed to -// ensure the state diff is correct, includes: -// -// - the account was indeed present in trie -// - the account in old trie matches the provided value -// - the slots transition is correct -func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database, otr, ntr *trie.Trie, addr common.Address, origin []byte, slots map[common.Hash][]byte) error { - // Verify account change - addrHash := crypto.Keccak256Hash(addr.Bytes()) - oBlob, err := otr.Get(addrHash.Bytes()) - if err != nil { - return err - } - nBlob, err := ntr.Get(addrHash.Bytes()) - if err != nil { - return err - } - if len(oBlob) == 0 { - return fmt.Errorf("missing account in old trie, %x", addrHash) - } - full, err := types.FullAccountRLP(origin) - if err != nil { - return err - } - if !bytes.Equal(full, oBlob) { - return fmt.Errorf("account value is not matched, %x", addrHash) - } - - // Decode accounts - var ( - oAcct types.StateAccount - nAcct types.StateAccount - nRoot common.Hash - ) - if err := rlp.DecodeBytes(oBlob, &oAcct); err != nil { - return err - } - if len(nBlob) == 0 { - nRoot = types.EmptyRootHash - } else { - if err := rlp.DecodeBytes(nBlob, &nAcct); err != nil { - return err - } - nRoot = nAcct.Root - } - - // Verify storage - st, err := trie.New(trie.StorageTrieID(next, addrHash, nRoot), db) - if err != nil { - return err - } - for key, val := range slots { - st.Update(key.Bytes(), val) - } - if st.Hash() != oAcct.Root { - return errors.New("invalid slot changes") - } - return nil -} - -func (test *stateTest) verify(root common.Hash, next common.Hash, db *triedb.Database, accountsOrigin map[common.Address][]byte, storagesOrigin map[common.Address]map[common.Hash][]byte) error { - otr, err := trie.New(trie.StateTrieID(root), db) - if err != nil { - return err - } - ntr, err := trie.New(trie.StateTrieID(next), db) - if err != nil { - return err - } - for addr, account := range accountsOrigin { - var err error - if len(account) == 0 { - err = test.verifyAccountCreation(next, db, otr, ntr, addr, storagesOrigin[addr]) - } else { - err = test.verifyAccountUpdate(next, db, otr, ntr, addr, accountsOrigin[addr], storagesOrigin[addr]) - } - if err != nil { - return err - } - } - return nil -} - -func TestStateChanges(t *testing.T) { - config := &quick.Config{MaxCount: 1000} - err := quick.Check((*stateTest).run, config) - if cerr, ok := err.(*quick.CheckError); ok { - test := cerr.In[0].(*stateTest) - t.Errorf("%v:\n%s", test.err, test) - } else if err != nil { - t.Error(err) - } -} diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go deleted file mode 100644 index 6788346fcf..0000000000 --- a/core/state/statedb_test.go +++ /dev/null @@ -1,1201 +0,0 @@ -// (c) 2019-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 state - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "math" - "math/rand" - "reflect" - "strings" - "sync" - "testing" - "testing/quick" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/state/snapshot" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ava-labs/subnet-evm/triedb/hashdb" - "github.com/ava-labs/subnet-evm/triedb/pathdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" - "github.com/holiman/uint256" -) - -// Tests that updating a state trie does not leak any database writes prior to -// actually committing the state. -func TestUpdateLeaks(t *testing.T) { - // Create an empty state database - var ( - db = rawdb.NewMemoryDatabase() - tdb = triedb.NewDatabase(db, nil) - ) - state, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(db, tdb), nil) - - // Update it with some accounts - for i := byte(0); i < 255; i++ { - addr := common.BytesToAddress([]byte{i}) - state.AddBalance(addr, uint256.NewInt(uint64(11*i))) - state.SetNonce(addr, uint64(42*i)) - if i%2 == 0 { - state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) - } - if i%3 == 0 { - state.SetCode(addr, []byte{i, i, i, i, i}) - } - } - - root := state.IntermediateRoot(false) - if err := tdb.Commit(root, false); err != nil { - t.Errorf("can not commit trie %v to persistent database", root.Hex()) - } - - // Ensure that no data was leaked into the database - it := db.NewIterator(nil, nil) - for it.Next() { - t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value()) - } - it.Release() -} - -// Tests that no intermediate state of an object is stored into the database, -// only the one right before the commit. -func TestIntermediateLeaks(t *testing.T) { - // Create two state databases, one transitioning to the final state, the other final from the beginning - transDb := rawdb.NewMemoryDatabase() - finalDb := rawdb.NewMemoryDatabase() - transNdb := triedb.NewDatabase(transDb, nil) - finalNdb := triedb.NewDatabase(finalDb, nil) - transState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(transDb, transNdb), nil) - finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil) - - modify := func(state *StateDB, addr common.Address, i, tweak byte) { - state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(tweak))) - state.SetNonce(addr, uint64(42*i+tweak)) - if i%2 == 0 { - state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) - state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) - } - if i%3 == 0 { - state.SetCode(addr, []byte{i, i, i, i, i, tweak}) - } - } - - // Modify the transient state. - for i := byte(0); i < 255; i++ { - modify(transState, common.Address{i}, i, 0) - } - // Write modifications to trie. - transState.IntermediateRoot(false) - - // Overwrite all the data with new values in the transient database. - for i := byte(0); i < 255; i++ { - modify(transState, common.Address{i}, i, 99) - modify(finalState, common.Address{i}, i, 99) - } - - // Commit and cross check the databases. - transRoot, err := transState.Commit(0, false) - if err != nil { - t.Fatalf("failed to commit transition state: %v", err) - } - if err = transNdb.Commit(transRoot, false); err != nil { - t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) - } - - finalRoot, err := finalState.Commit(0, false) - if err != nil { - t.Fatalf("failed to commit final state: %v", err) - } - if err = finalNdb.Commit(finalRoot, false); err != nil { - t.Errorf("can not commit trie %v to persistent database", finalRoot.Hex()) - } - - it := finalDb.NewIterator(nil, nil) - for it.Next() { - key, fvalue := it.Key(), it.Value() - tvalue, err := transDb.Get(key) - if err != nil { - t.Errorf("entry missing from the transition database: %x -> %x", key, fvalue) - } - if !bytes.Equal(fvalue, tvalue) { - t.Errorf("value mismatch at key %x: %x in transition database, %x in final database", key, tvalue, fvalue) - } - } - it.Release() - - it = transDb.NewIterator(nil, nil) - for it.Next() { - key, tvalue := it.Key(), it.Value() - fvalue, err := finalDb.Get(key) - if err != nil { - t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value()) - } - if !bytes.Equal(fvalue, tvalue) { - t.Errorf("value mismatch at key %x: %x in transition database, %x in final database", key, tvalue, fvalue) - } - } -} - -// TestCopy tests that copying a StateDB object indeed makes the original and -// the copy independent of each other. This test is a regression test against -// https://github.com/ethereum/go-ethereum/pull/15549. -func TestCopy(t *testing.T) { - // Create a random state test to copy and modify "independently" - orig, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) - - for i := byte(0); i < 255; i++ { - obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i})) - obj.AddBalance(uint256.NewInt(uint64(i))) - orig.updateStateObject(obj) - } - orig.Finalise(false) - - // Copy the state - copy := orig.Copy() - - // Copy the copy state - ccopy := copy.Copy() - - // modify all in memory - for i := byte(0); i < 255; i++ { - origObj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i})) - copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i})) - ccopyObj := ccopy.getOrNewStateObject(common.BytesToAddress([]byte{i})) - - origObj.AddBalance(uint256.NewInt(2 * uint64(i))) - copyObj.AddBalance(uint256.NewInt(3 * uint64(i))) - ccopyObj.AddBalance(uint256.NewInt(4 * uint64(i))) - - orig.updateStateObject(origObj) - copy.updateStateObject(copyObj) - ccopy.updateStateObject(copyObj) - } - - // Finalise the changes on all concurrently - finalise := func(wg *sync.WaitGroup, db *StateDB) { - defer wg.Done() - db.Finalise(true) - } - - var wg sync.WaitGroup - wg.Add(3) - go finalise(&wg, orig) - go finalise(&wg, copy) - go finalise(&wg, ccopy) - wg.Wait() - - // Verify that the three states have been updated independently - for i := byte(0); i < 255; i++ { - origObj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i})) - copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i})) - ccopyObj := ccopy.getOrNewStateObject(common.BytesToAddress([]byte{i})) - - if want := uint256.NewInt(3 * uint64(i)); origObj.Balance().Cmp(want) != 0 { - t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) - } - if want := uint256.NewInt(4 * uint64(i)); copyObj.Balance().Cmp(want) != 0 { - t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want) - } - if want := uint256.NewInt(5 * uint64(i)); ccopyObj.Balance().Cmp(want) != 0 { - t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, ccopyObj.Balance(), want) - } - } -} - -func TestSnapshotRandom(t *testing.T) { - config := &quick.Config{MaxCount: 1000} - err := quick.Check((*snapshotTest).run, config) - if cerr, ok := err.(*quick.CheckError); ok { - test := cerr.In[0].(*snapshotTest) - t.Errorf("%v:\n%s", test.err, test) - } else if err != nil { - t.Error(err) - } -} - -// A snapshotTest checks that reverting StateDB snapshots properly undoes all changes -// captured by the snapshot. Instances of this test with pseudorandom content are created -// by Generate. -// -// The test works as follows: -// -// A new state is created and all actions are applied to it. Several snapshots are taken -// in between actions. The test then reverts each snapshot. For each snapshot the actions -// leading up to it are replayed on a fresh, empty state. The behaviour of all public -// accessor methods on the reverted state must match the return value of the equivalent -// methods on the replayed state. -type snapshotTest struct { - addrs []common.Address // all account addresses - actions []testAction // modifications to the state - snapshots []int // actions indexes at which snapshot is taken - err error // failure details are reported through this field -} - -type testAction struct { - name string - fn func(testAction, *StateDB) - args []int64 - noAddr bool -} - -// newTestAction creates a random action that changes state. -func newTestAction(addr common.Address, r *rand.Rand) testAction { - actions := []testAction{ - { - name: "SetBalance", - fn: func(a testAction, s *StateDB) { - s.SetBalance(addr, uint256.NewInt(uint64(a.args[0]))) - }, - args: make([]int64, 1), - }, - { - name: "AddBalance", - fn: func(a testAction, s *StateDB) { - s.AddBalance(addr, uint256.NewInt(uint64(a.args[0]))) - }, - args: make([]int64, 1), - }, - { - name: "SetNonce", - fn: func(a testAction, s *StateDB) { - s.SetNonce(addr, uint64(a.args[0])) - }, - args: make([]int64, 1), - }, - { - name: "SetState", - fn: func(a testAction, s *StateDB) { - var key, val common.Hash - binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) - binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) - s.SetState(addr, key, val) - }, - args: make([]int64, 2), - }, - { - name: "SetCode", - fn: func(a testAction, s *StateDB) { - code := make([]byte, 16) - binary.BigEndian.PutUint64(code, uint64(a.args[0])) - binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) - s.SetCode(addr, code) - }, - args: make([]int64, 2), - }, - { - name: "CreateAccount", - fn: func(a testAction, s *StateDB) { - s.CreateAccount(addr) - }, - }, - { - name: "SelfDestruct", - fn: func(a testAction, s *StateDB) { - s.SelfDestruct(addr) - }, - }, - { - name: "AddRefund", - fn: func(a testAction, s *StateDB) { - s.AddRefund(uint64(a.args[0])) - }, - args: make([]int64, 1), - noAddr: true, - }, - { - name: "AddLog", - fn: func(a testAction, s *StateDB) { - data := make([]byte, 2) - binary.BigEndian.PutUint16(data, uint16(a.args[0])) - s.AddLog(&types.Log{Address: addr, Data: data}) - }, - args: make([]int64, 1), - }, - { - name: "AddPreimage", - fn: func(a testAction, s *StateDB) { - preimage := []byte{1} - hash := common.BytesToHash(preimage) - s.AddPreimage(hash, preimage) - }, - args: make([]int64, 1), - }, - { - name: "AddAddressToAccessList", - fn: func(a testAction, s *StateDB) { - s.AddAddressToAccessList(addr) - }, - }, - { - name: "AddSlotToAccessList", - fn: func(a testAction, s *StateDB) { - s.AddSlotToAccessList(addr, - common.Hash{byte(a.args[0])}) - }, - args: make([]int64, 1), - }, - { - name: "SetTransientState", - fn: func(a testAction, s *StateDB) { - var key, val common.Hash - binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) - binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) - s.SetTransientState(addr, key, val) - }, - args: make([]int64, 2), - }, - } - action := actions[r.Intn(len(actions))] - var nameargs []string - if !action.noAddr { - nameargs = append(nameargs, addr.Hex()) - } - for i := range action.args { - action.args[i] = rand.Int63n(100) - nameargs = append(nameargs, fmt.Sprint(action.args[i])) - } - action.name += strings.Join(nameargs, ", ") - return action -} - -// Generate returns a new snapshot test of the given size. All randomness is -// derived from r. -func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value { - // Generate random actions. - addrs := make([]common.Address, 50) - for i := range addrs { - addrs[i][0] = byte(i) - } - actions := make([]testAction, size) - for i := range actions { - addr := addrs[r.Intn(len(addrs))] - actions[i] = newTestAction(addr, r) - } - // Generate snapshot indexes. - nsnapshots := int(math.Sqrt(float64(size))) - if size > 0 && nsnapshots == 0 { - nsnapshots = 1 - } - snapshots := make([]int, nsnapshots) - snaplen := len(actions) / nsnapshots - for i := range snapshots { - // Try to place the snapshots some number of actions apart from each other. - snapshots[i] = (i * snaplen) + r.Intn(snaplen) - } - return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil}) -} - -func (test *snapshotTest) String() string { - out := new(bytes.Buffer) - sindex := 0 - for i, action := range test.actions { - if len(test.snapshots) > sindex && i == test.snapshots[sindex] { - fmt.Fprintf(out, "---- snapshot %d ----\n", sindex) - sindex++ - } - fmt.Fprintf(out, "%4d: %s\n", i, action.name) - } - return out.String() -} - -func (test *snapshotTest) run() bool { - // Run all actions and create snapshots. - var ( - state, _ = New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) - snapshotRevs = make([]int, len(test.snapshots)) - sindex = 0 - checkstates = make([]*StateDB, len(test.snapshots)) - ) - for i, action := range test.actions { - if len(test.snapshots) > sindex && i == test.snapshots[sindex] { - snapshotRevs[sindex] = state.Snapshot() - checkstates[sindex] = state.Copy() - sindex++ - } - action.fn(action, state) - } - // Revert all snapshots in reverse order. Each revert must yield a state - // that is equivalent to fresh state with all actions up the snapshot applied. - for sindex--; sindex >= 0; sindex-- { - state.RevertToSnapshot(snapshotRevs[sindex]) - if err := test.checkEqual(state, checkstates[sindex]); err != nil { - test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err) - return false - } - } - return true -} - -func forEachStorage(s *StateDB, addr common.Address, cb func(key, value common.Hash) bool) error { - so := s.getStateObject(addr) - if so == nil { - return nil - } - tr, err := so.getTrie() - if err != nil { - return err - } - trieIt, err := tr.NodeIterator(nil) - if err != nil { - return err - } - it := trie.NewIterator(trieIt) - - for it.Next() { - key := common.BytesToHash(s.trie.GetKey(it.Key)) - if value, dirty := so.dirtyStorage[key]; dirty { - if !cb(key, value) { - return nil - } - continue - } - - if len(it.Value) > 0 { - _, content, _, err := rlp.Split(it.Value) - if err != nil { - return err - } - if !cb(key, common.BytesToHash(content)) { - return nil - } - } - } - return nil -} - -// checkEqual checks that methods of state and checkstate return the same values. -func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { - for _, addr := range test.addrs { - var err error - checkeq := func(op string, a, b interface{}) bool { - if err == nil && !reflect.DeepEqual(a, b) { - err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b) - return false - } - return true - } - // Check basic accessor methods. - checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) - checkeq("HasSelfdestructed", state.HasSelfDestructed(addr), checkstate.HasSelfDestructed(addr)) - checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) - checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) - checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) - checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr)) - checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) - // Check storage. - if obj := state.getStateObject(addr); obj != nil { - forEachStorage(state, addr, func(key, value common.Hash) bool { - return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) - }) - forEachStorage(checkstate, addr, func(key, value common.Hash) bool { - return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) - }) - } - if err != nil { - return err - } - } - - if state.GetRefund() != checkstate.GetRefund() { - return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", - state.GetRefund(), checkstate.GetRefund()) - } - if !reflect.DeepEqual(state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) { - return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", - state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) - } - return nil -} - -func TestTouchDelete(t *testing.T) { - s := newStateEnv() - s.state.getOrNewStateObject(common.Address{}) - root, _ := s.state.Commit(0, false) - s.state, _ = NewWithSnapshot(root, s.state.db, s.state.snap) - - snapshot := s.state.Snapshot() - s.state.AddBalance(common.Address{}, new(uint256.Int)) - - if len(s.state.journal.dirties) != 1 { - t.Fatal("expected one dirty state object") - } - s.state.RevertToSnapshot(snapshot) - if len(s.state.journal.dirties) != 0 { - t.Fatal("expected no dirty state object") - } -} - -// TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. -// See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512 -func TestCopyOfCopy(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) - addr := common.HexToAddress("aaaa") - state.SetBalance(addr, uint256.NewInt(42)) - - if got := state.Copy().GetBalance(addr).Uint64(); got != 42 { - t.Fatalf("1st copy fail, expected 42, got %v", got) - } - if got := state.Copy().Copy().GetBalance(addr).Uint64(); got != 42 { - t.Fatalf("2nd copy fail, expected 42, got %v", got) - } -} - -// Tests a regression where committing a copy lost some internal meta information, -// leading to corrupted subsequent copies. -// -// See https://github.com/ethereum/go-ethereum/issues/20106. -func TestCopyCommitCopy(t *testing.T) { - tdb := NewDatabase(rawdb.NewMemoryDatabase()) - state, _ := New(types.EmptyRootHash, tdb, nil) - - // Create an account and check if the retrieved balance is correct - addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") - skey := common.HexToHash("aaa") - sval := common.HexToHash("bbb") - - state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie - - if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { - t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) - } - if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := state.GetState(addr, skey); val != sval { - t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { - t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) - } - // Copy the non-committed state database and check pre/post commit balance - copyOne := state.Copy() - if balance := copyOne.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { - t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42) - } - if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("first copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := copyOne.GetState(addr, skey); val != sval { - t.Fatalf("first copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { - t.Fatalf("first copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) - } - // Copy the copy and check the balance once more - copyTwo := copyOne.Copy() - if balance := copyTwo.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { - t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42) - } - if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("second copy code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := copyTwo.GetState(addr, skey); val != sval { - t.Fatalf("second copy non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) { - t.Fatalf("second copy committed storage slot mismatch: have %x, want %x", val, sval) - } - // Commit state, ensure states can be loaded from disk - root, _ := state.Commit(0, false) - state, _ = New(root, tdb, nil) - if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { - t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42) - } - if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("state post-commit code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := state.GetState(addr, skey); val != sval { - t.Fatalf("state post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := state.GetCommittedState(addr, skey); val != sval { - t.Fatalf("state post-commit committed storage slot mismatch: have %x, want %x", val, sval) - } -} - -// Tests a regression where committing a copy lost some internal meta information, -// leading to corrupted subsequent copies. -// -// See https://github.com/ethereum/go-ethereum/issues/20106. -func TestCopyCopyCommitCopy(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) - - // Create an account and check if the retrieved balance is correct - addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") - skey := common.HexToHash("aaa") - sval := common.HexToHash("bbb") - - state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie - - if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { - t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) - } - if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := state.GetState(addr, skey); val != sval { - t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { - t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) - } - // Copy the non-committed state database and check pre/post commit balance - copyOne := state.Copy() - if balance := copyOne.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { - t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42) - } - if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("first copy code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := copyOne.GetState(addr, skey); val != sval { - t.Fatalf("first copy non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { - t.Fatalf("first copy committed storage slot mismatch: have %x, want %x", val, common.Hash{}) - } - // Copy the copy and check the balance once more - copyTwo := copyOne.Copy() - if balance := copyTwo.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { - t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42) - } - if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("second copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := copyTwo.GetState(addr, skey); val != sval { - t.Fatalf("second copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) { - t.Fatalf("second copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) - } - // Copy the copy-copy and check the balance once more - copyThree := copyTwo.Copy() - if balance := copyThree.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { - t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42) - } - if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("third copy code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := copyThree.GetState(addr, skey); val != sval { - t.Fatalf("third copy non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := copyThree.GetCommittedState(addr, skey); val != (common.Hash{}) { - t.Fatalf("third copy committed storage slot mismatch: have %x, want %x", val, sval) - } -} - -// TestCommitCopy tests the copy from a committed state is not functional. -func TestCommitCopy(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) - - // Create an account and check if the retrieved balance is correct - addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") - skey := common.HexToHash("aaa") - sval := common.HexToHash("bbb") - - state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie - - if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { - t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) - } - if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { - t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) - } - if val := state.GetState(addr, skey); val != sval { - t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) - } - if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { - t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) - } - // Copy the committed state database, the copied one is not functional. - state.Commit(0, true) - copied := state.Copy() - if balance := copied.GetBalance(addr); balance.Cmp(uint256.NewInt(0)) != 0 { - t.Fatalf("unexpected balance: have %v", balance) - } - if code := copied.GetCode(addr); code != nil { - t.Fatalf("unexpected code: have %x", code) - } - if val := copied.GetState(addr, skey); val != (common.Hash{}) { - t.Fatalf("unexpected storage slot: have %x", val) - } - if val := copied.GetCommittedState(addr, skey); val != (common.Hash{}) { - t.Fatalf("unexpected storage slot: have %x", val) - } - if !errors.Is(copied.Error(), trie.ErrCommitted) { - t.Fatalf("unexpected state error, %v", copied.Error()) - } -} - -// TestDeleteCreateRevert tests a weird state transition corner case that we hit -// while changing the internals of StateDB. The workflow is that a contract is -// self-destructed, then in a follow-up transaction (but same block) it's created -// again and the transaction reverted. -// -// The original StateDB implementation flushed dirty objects to the tries after -// each transaction, so this works ok. The rework accumulated writes in memory -// first, but the journal wiped the entire state object on create-revert. -func TestDeleteCreateRevert(t *testing.T) { - // Create an initial state with a single contract - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) - - addr := common.BytesToAddress([]byte("so")) - state.SetBalance(addr, uint256.NewInt(1)) - - root, _ := state.Commit(0, false) - state, _ = NewWithSnapshot(root, state.db, state.snap) - - // Simulate self-destructing in one transaction, then create-reverting in another - state.SelfDestruct(addr) - state.Finalise(true) - - id := state.Snapshot() - state.SetBalance(addr, uint256.NewInt(2)) - state.RevertToSnapshot(id) - - // Commit the entire state and make sure we don't crash and have the correct state - root, _ = state.Commit(0, true) - state, _ = NewWithSnapshot(root, state.db, state.snap) - - if state.getStateObject(addr) != nil { - t.Fatalf("self-destructed contract came alive") - } -} - -// TestMissingTrieNodes tests that if the StateDB fails to load parts of the trie, -// the Commit operation fails with an error -// If we are missing trie nodes, we should not continue writing to the trie -func TestMissingTrieNodes(t *testing.T) { - testMissingTrieNodes(t, rawdb.HashScheme) - testMissingTrieNodes(t, rawdb.PathScheme) -} - -func testMissingTrieNodes(t *testing.T, scheme string) { - // Create an initial state with a few accounts - var ( - tdb *triedb.Database - memDb = rawdb.NewMemoryDatabase() - ) - if scheme == rawdb.PathScheme { - tdb = triedb.NewDatabase(memDb, &triedb.Config{PathDB: &pathdb.Config{ - CleanCacheSize: 0, - DirtyCacheSize: 0, - }}) // disable caching - } else { - tdb = triedb.NewDatabase(memDb, &triedb.Config{HashDB: &hashdb.Config{ - CleanCacheSize: 0, - }}) // disable caching - } - db := NewDatabaseWithNodeDB(memDb, tdb) - - var root common.Hash - state, _ := New(types.EmptyRootHash, db, nil) - addr := common.BytesToAddress([]byte("so")) - { - state.SetBalance(addr, uint256.NewInt(1)) - state.SetCode(addr, []byte{1, 2, 3}) - a2 := common.BytesToAddress([]byte("another")) - state.SetBalance(a2, uint256.NewInt(100)) - state.SetCode(a2, []byte{1, 2, 4}) - root, _ = state.Commit(0, false) - t.Logf("root: %x", root) - // force-flush - tdb.Commit(root, false) - } - // Create a new state on the old root - state, _ = New(root, db, nil) - // Now we clear out the memdb - it := memDb.NewIterator(nil, nil) - for it.Next() { - k := it.Key() - // Leave the root intact - if !bytes.Equal(k, root[:]) { - t.Logf("key: %x", k) - memDb.Delete(k) - } - } - balance := state.GetBalance(addr) - // The removed elem should lead to it returning zero balance - if exp, got := uint64(0), balance.Uint64(); got != exp { - t.Errorf("expected %d, got %d", exp, got) - } - // Modify the state - state.SetBalance(addr, uint256.NewInt(2)) - root, err := state.Commit(0, false) - if err == nil { - t.Fatalf("expected error, got root :%x", root) - } -} - -func TestStateDBAccessList(t *testing.T) { - // Some helpers - addr := func(a string) common.Address { - return common.HexToAddress(a) - } - slot := func(a string) common.Hash { - return common.HexToHash(a) - } - - memDb := rawdb.NewMemoryDatabase() - db := NewDatabase(memDb) - state, _ := New(types.EmptyRootHash, db, nil) - state.accessList = newAccessList() - - verifyAddrs := func(astrings ...string) { - t.Helper() - // convert to common.Address form - var addresses []common.Address - var addressMap = make(map[common.Address]struct{}) - for _, astring := range astrings { - address := addr(astring) - addresses = append(addresses, address) - addressMap[address] = struct{}{} - } - // Check that the given addresses are in the access list - for _, address := range addresses { - if !state.AddressInAccessList(address) { - t.Fatalf("expected %x to be in access list", address) - } - } - // Check that only the expected addresses are present in the access list - for address := range state.accessList.addresses { - if _, exist := addressMap[address]; !exist { - t.Fatalf("extra address %x in access list", address) - } - } - } - verifySlots := func(addrString string, slotStrings ...string) { - if !state.AddressInAccessList(addr(addrString)) { - t.Fatalf("scope missing address/slots %v", addrString) - } - var address = addr(addrString) - // convert to common.Hash form - var slots []common.Hash - var slotMap = make(map[common.Hash]struct{}) - for _, slotString := range slotStrings { - s := slot(slotString) - slots = append(slots, s) - slotMap[s] = struct{}{} - } - // Check that the expected items are in the access list - for i, s := range slots { - if _, slotPresent := state.SlotInAccessList(address, s); !slotPresent { - t.Fatalf("input %d: scope missing slot %v (address %v)", i, s, addrString) - } - } - // Check that no extra elements are in the access list - index := state.accessList.addresses[address] - if index >= 0 { - stateSlots := state.accessList.slots[index] - for s := range stateSlots { - if _, slotPresent := slotMap[s]; !slotPresent { - t.Fatalf("scope has extra slot %v (address %v)", s, addrString) - } - } - } - } - - state.AddAddressToAccessList(addr("aa")) // 1 - state.AddSlotToAccessList(addr("bb"), slot("01")) // 2,3 - state.AddSlotToAccessList(addr("bb"), slot("02")) // 4 - verifyAddrs("aa", "bb") - verifySlots("bb", "01", "02") - - // Make a copy - stateCopy1 := state.Copy() - if exp, got := 4, state.journal.length(); exp != got { - t.Fatalf("journal length mismatch: have %d, want %d", got, exp) - } - - // same again, should cause no journal entries - state.AddSlotToAccessList(addr("bb"), slot("01")) - state.AddSlotToAccessList(addr("bb"), slot("02")) - state.AddAddressToAccessList(addr("aa")) - if exp, got := 4, state.journal.length(); exp != got { - t.Fatalf("journal length mismatch: have %d, want %d", got, exp) - } - // some new ones - state.AddSlotToAccessList(addr("bb"), slot("03")) // 5 - state.AddSlotToAccessList(addr("aa"), slot("01")) // 6 - state.AddSlotToAccessList(addr("cc"), slot("01")) // 7,8 - state.AddAddressToAccessList(addr("cc")) - if exp, got := 8, state.journal.length(); exp != got { - t.Fatalf("journal length mismatch: have %d, want %d", got, exp) - } - - verifyAddrs("aa", "bb", "cc") - verifySlots("aa", "01") - verifySlots("bb", "01", "02", "03") - verifySlots("cc", "01") - - // now start rolling back changes - state.journal.revert(state, 7) - if _, ok := state.SlotInAccessList(addr("cc"), slot("01")); ok { - t.Fatalf("slot present, expected missing") - } - verifyAddrs("aa", "bb", "cc") - verifySlots("aa", "01") - verifySlots("bb", "01", "02", "03") - - state.journal.revert(state, 6) - if state.AddressInAccessList(addr("cc")) { - t.Fatalf("addr present, expected missing") - } - verifyAddrs("aa", "bb") - verifySlots("aa", "01") - verifySlots("bb", "01", "02", "03") - - state.journal.revert(state, 5) - if _, ok := state.SlotInAccessList(addr("aa"), slot("01")); ok { - t.Fatalf("slot present, expected missing") - } - verifyAddrs("aa", "bb") - verifySlots("bb", "01", "02", "03") - - state.journal.revert(state, 4) - if _, ok := state.SlotInAccessList(addr("bb"), slot("03")); ok { - t.Fatalf("slot present, expected missing") - } - verifyAddrs("aa", "bb") - verifySlots("bb", "01", "02") - - state.journal.revert(state, 3) - if _, ok := state.SlotInAccessList(addr("bb"), slot("02")); ok { - t.Fatalf("slot present, expected missing") - } - verifyAddrs("aa", "bb") - verifySlots("bb", "01") - - state.journal.revert(state, 2) - if _, ok := state.SlotInAccessList(addr("bb"), slot("01")); ok { - t.Fatalf("slot present, expected missing") - } - verifyAddrs("aa", "bb") - - state.journal.revert(state, 1) - if state.AddressInAccessList(addr("bb")) { - t.Fatalf("addr present, expected missing") - } - verifyAddrs("aa") - - state.journal.revert(state, 0) - if state.AddressInAccessList(addr("aa")) { - t.Fatalf("addr present, expected missing") - } - if got, exp := len(state.accessList.addresses), 0; got != exp { - t.Fatalf("expected empty, got %d", got) - } - if got, exp := len(state.accessList.slots), 0; got != exp { - t.Fatalf("expected empty, got %d", got) - } - // Check the copy - // Make a copy - state = stateCopy1 - verifyAddrs("aa", "bb") - verifySlots("bb", "01", "02") - if got, exp := len(state.accessList.addresses), 2; got != exp { - t.Fatalf("expected empty, got %d", got) - } - if got, exp := len(state.accessList.slots), 1; got != exp { - t.Fatalf("expected empty, got %d", got) - } -} - -// Tests that account and storage tries are flushed in the correct order and that -// no data loss occurs. -func TestFlushOrderDataLoss(t *testing.T) { - // Create a state trie with many accounts and slots - var ( - memdb = rawdb.NewMemoryDatabase() - triedb = triedb.NewDatabase(memdb, nil) - statedb = NewDatabaseWithNodeDB(memdb, triedb) - state, _ = New(types.EmptyRootHash, statedb, nil) - ) - for a := byte(0); a < 10; a++ { - state.CreateAccount(common.Address{a}) - for s := byte(0); s < 10; s++ { - state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s}) - } - } - root, err := state.Commit(0, false) - if err != nil { - t.Fatalf("failed to commit state trie: %v", err) - } - triedb.Reference(root, common.Hash{}) - if err := triedb.Cap(1024); err != nil { - t.Fatalf("failed to cap trie dirty cache: %v", err) - } - if err := triedb.Commit(root, false); err != nil { - t.Fatalf("failed to commit state trie: %v", err) - } - // Reopen the state trie from flushed disk and verify it - state, err = New(root, NewDatabase(memdb), nil) - if err != nil { - t.Fatalf("failed to reopen state trie: %v", err) - } - for a := byte(0); a < 10; a++ { - for s := byte(0); s < 10; s++ { - if have := state.GetState(common.Address{a}, common.Hash{a, s}); have != (common.Hash{a, s}) { - t.Errorf("account %d: slot %d: state mismatch: have %x, want %x", a, s, have, common.Hash{a, s}) - } - } - } -} - -func TestStateDBTransientStorage(t *testing.T) { - memDb := rawdb.NewMemoryDatabase() - db := NewDatabase(memDb) - state, _ := New(types.EmptyRootHash, db, nil) - - key := common.Hash{0x01} - value := common.Hash{0x02} - addr := common.Address{} - - state.SetTransientState(addr, key, value) - if exp, got := 1, state.journal.length(); exp != got { - t.Fatalf("journal length mismatch: have %d, want %d", got, exp) - } - // the retrieved value should equal what was set - if got := state.GetTransientState(addr, key); got != value { - t.Fatalf("transient storage mismatch: have %x, want %x", got, value) - } - - // revert the transient state being set and then check that the - // value is now the empty hash - state.journal.revert(state, 0) - if got, exp := state.GetTransientState(addr, key), (common.Hash{}); exp != got { - t.Fatalf("transient storage mismatch: have %x, want %x", got, exp) - } - - // set transient state and then copy the statedb and ensure that - // the transient state is copied - state.SetTransientState(addr, key, value) - cpy := state.Copy() - if got := cpy.GetTransientState(addr, key); got != value { - t.Fatalf("transient storage mismatch: have %x, want %x", got, value) - } -} - -func TestResetObject(t *testing.T) { - var ( - disk = rawdb.NewMemoryDatabase() - tdb = triedb.NewDatabase(disk, nil) - db = NewDatabaseWithNodeDB(disk, tdb) - snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, common.Hash{}, types.EmptyRootHash) - state, _ = New(types.EmptyRootHash, db, snaps) - addr = common.HexToAddress("0x1") - slotA = common.HexToHash("0x1") - slotB = common.HexToHash("0x2") - ) - // Initialize account with balance and storage in first transaction. - state.SetBalance(addr, uint256.NewInt(1)) - state.SetState(addr, slotA, common.BytesToHash([]byte{0x1})) - state.IntermediateRoot(true) - - // Reset account and mutate balance and storages - state.CreateAccount(addr) - state.SetBalance(addr, uint256.NewInt(2)) - state.SetState(addr, slotB, common.BytesToHash([]byte{0x2})) - root, _ := state.CommitWithSnap(0, true, snaps, common.Hash{}, common.Hash{}) - - // Ensure the original account is wiped properly - snap := snaps.Snapshot(root) - slot, _ := snap.Storage(crypto.Keccak256Hash(addr.Bytes()), crypto.Keccak256Hash(slotA.Bytes())) - if len(slot) != 0 { - t.Fatalf("Unexpected storage slot") - } - slot, _ = snap.Storage(crypto.Keccak256Hash(addr.Bytes()), crypto.Keccak256Hash(slotB.Bytes())) - if !bytes.Equal(slot, []byte{0x2}) { - t.Fatalf("Unexpected storage slot value %v", slot) - } -} - -func TestDeleteStorage(t *testing.T) { - var ( - disk = rawdb.NewMemoryDatabase() - tdb = triedb.NewDatabase(disk, nil) - db = NewDatabaseWithNodeDB(disk, tdb) - snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, common.Hash{}, types.EmptyRootHash) - state, _ = New(types.EmptyRootHash, db, snaps) - addr = common.HexToAddress("0x1") - ) - // Initialize account and populate storage - state.SetBalance(addr, uint256.NewInt(1)) - state.CreateAccount(addr) - for i := 0; i < 1000; i++ { - slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32()) - value := common.Hash(uint256.NewInt(uint64(10 * i)).Bytes32()) - state.SetState(addr, slot, value) - } - root, _ := state.CommitWithSnap(0, true, snaps, common.Hash{}, common.Hash{}) - // Init phase done, create two states, one with snap and one without - fastState, _ := New(root, db, snaps) - slowState, _ := New(root, db, nil) - - obj := fastState.getOrNewStateObject(addr) - storageRoot := obj.data.Root - - _, _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) - if err != nil { - t.Fatal(err) - } - - _, _, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) - if err != nil { - t.Fatal(err) - } - check := func(set *trienode.NodeSet) string { - var a []string - set.ForEachWithOrder(func(path string, n *trienode.Node) { - if n.Hash != (common.Hash{}) { - t.Fatal("delete should have empty hashes") - } - if len(n.Blob) != 0 { - t.Fatal("delete should have have empty blobs") - } - a = append(a, fmt.Sprintf("%x", path)) - }) - return strings.Join(a, ",") - } - slowRes := check(slowNodes) - fastRes := check(fastNodes) - if slowRes != fastRes { - t.Fatalf("difference found:\nfast: %v\nslow: %v\n", fastRes, slowRes) - } -} diff --git a/core/state/transient_storage.go b/core/state/transient_storage.go deleted file mode 100644 index b5ee4f461e..0000000000 --- a/core/state/transient_storage.go +++ /dev/null @@ -1,65 +0,0 @@ -// (c) 2023, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 state - -import ( - "github.com/ethereum/go-ethereum/common" -) - -// transientStorage is a representation of EIP-1153 "Transient Storage". -type transientStorage map[common.Address]Storage - -// newTransientStorage creates a new instance of a transientStorage. -func newTransientStorage() transientStorage { - return make(transientStorage) -} - -// Set sets the transient-storage `value` for `key` at the given `addr`. -func (t transientStorage) Set(addr common.Address, key, value common.Hash) { - if _, ok := t[addr]; !ok { - t[addr] = make(Storage) - } - t[addr][key] = value -} - -// Get gets the transient storage for `key` at the given `addr`. -func (t transientStorage) Get(addr common.Address, key common.Hash) common.Hash { - val, ok := t[addr] - if !ok { - return common.Hash{} - } - return val[key] -} - -// Copy does a deep copy of the transientStorage -func (t transientStorage) Copy() transientStorage { - storage := make(transientStorage) - for key, value := range t { - storage[key] = value.Copy() - } - return storage -} diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go deleted file mode 100644 index 6c6ddeab07..0000000000 --- a/core/state/trie_prefetcher.go +++ /dev/null @@ -1,640 +0,0 @@ -// (c) 2019-2020, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2020 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 state - -import ( - "sync" - "time" - - "github.com/ava-labs/subnet-evm/metrics" - "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" -) - -// triePrefetchMetricsPrefix is the prefix under which to publish the metrics. -const triePrefetchMetricsPrefix = "trie/prefetch/" - -// triePrefetcher is an active prefetcher, which receives accounts or storage -// items and does trie-loading of them. The goal is to get as much useful content -// into the caches as possible. -// -// Note, the prefetcher's API is not thread safe. -type triePrefetcher struct { - db Database // Database to fetch trie nodes through - root common.Hash // Root hash of the account trie for metrics - fetches map[string]Trie // Partially or fully fetched tries. Only populated for inactive copies. - fetchers map[string]*subfetcher // Subfetchers for each trie - - maxConcurrency int - workers *utils.BoundedWorkers - - subfetcherWorkersMeter metrics.Meter - subfetcherWaitTimer metrics.Counter - subfetcherCopiesMeter metrics.Meter - - accountLoadMeter metrics.Meter - accountDupMeter metrics.Meter - accountSkipMeter metrics.Meter - accountWasteMeter metrics.Meter - - storageFetchersMeter metrics.Meter - storageLoadMeter metrics.Meter - storageLargestLoadMeter metrics.Meter - storageDupMeter metrics.Meter - storageSkipMeter metrics.Meter - storageWasteMeter metrics.Meter -} - -func newTriePrefetcher(db Database, root common.Hash, namespace string, maxConcurrency int) *triePrefetcher { - prefix := triePrefetchMetricsPrefix + namespace - return &triePrefetcher{ - db: db, - root: root, - fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map - - maxConcurrency: maxConcurrency, - workers: utils.NewBoundedWorkers(maxConcurrency), // Scale up as needed to [maxConcurrency] - - subfetcherWorkersMeter: metrics.GetOrRegisterMeter(prefix+"/subfetcher/workers", nil), - subfetcherWaitTimer: metrics.GetOrRegisterCounter(prefix+"/subfetcher/wait", nil), - subfetcherCopiesMeter: metrics.GetOrRegisterMeter(prefix+"/subfetcher/copies", nil), - - accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil), - accountDupMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup", nil), - accountSkipMeter: metrics.GetOrRegisterMeter(prefix+"/account/skip", nil), - accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil), - - storageFetchersMeter: metrics.GetOrRegisterMeter(prefix+"/storage/fetchers", nil), - storageLoadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load", nil), - storageLargestLoadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/lload", nil), - storageDupMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup", nil), - storageSkipMeter: metrics.GetOrRegisterMeter(prefix+"/storage/skip", nil), - storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil), - } -} - -// close iterates over all the subfetchers, aborts any that were left spinning -// and reports the stats to the metrics subsystem. -func (p *triePrefetcher) close() { - // If the prefetcher is an inactive one, bail out - if p.fetches != nil { - return - } - - // Collect stats from all fetchers - var ( - storageFetchers int64 - largestLoad int64 - ) - for _, fetcher := range p.fetchers { - fetcher.abort() // safe to call multiple times (should be a no-op on happy path) - - if metrics.Enabled { - p.subfetcherCopiesMeter.Mark(int64(fetcher.copies())) - - if fetcher.root == p.root { - p.accountLoadMeter.Mark(int64(len(fetcher.seen))) - p.accountDupMeter.Mark(int64(fetcher.dups)) - p.accountSkipMeter.Mark(int64(fetcher.skips())) - - for _, key := range fetcher.used { - delete(fetcher.seen, string(key)) - } - p.accountWasteMeter.Mark(int64(len(fetcher.seen))) - } else { - storageFetchers++ - oseen := int64(len(fetcher.seen)) - if oseen > largestLoad { - largestLoad = oseen - } - p.storageLoadMeter.Mark(oseen) - p.storageDupMeter.Mark(int64(fetcher.dups)) - p.storageSkipMeter.Mark(int64(fetcher.skips())) - - for _, key := range fetcher.used { - delete(fetcher.seen, string(key)) - } - p.storageWasteMeter.Mark(int64(len(fetcher.seen))) - } - } - } - if metrics.Enabled { - p.storageFetchersMeter.Mark(storageFetchers) - p.storageLargestLoadMeter.Mark(largestLoad) - } - - // Stop all workers once fetchers are aborted (otherwise - // could stop while waiting) - // - // Record number of workers that were spawned during this run - workersUsed := int64(p.workers.Wait()) - if metrics.Enabled { - p.subfetcherWorkersMeter.Mark(workersUsed) - } - - // Clear out all fetchers (will crash on a second call, deliberate) - p.fetchers = nil -} - -// copy creates a deep-but-inactive copy of the trie prefetcher. Any trie data -// already loaded will be copied over, but no goroutines will be started. This -// is mostly used in the miner which creates a copy of it's actively mutated -// state to be sealed while it may further mutate the state. -func (p *triePrefetcher) copy() *triePrefetcher { - copy := &triePrefetcher{ - db: p.db, - root: p.root, - fetches: make(map[string]Trie), // Active prefetchers use the fetchers map - - subfetcherWorkersMeter: p.subfetcherWorkersMeter, - subfetcherWaitTimer: p.subfetcherWaitTimer, - subfetcherCopiesMeter: p.subfetcherCopiesMeter, - - accountLoadMeter: p.accountLoadMeter, - accountDupMeter: p.accountDupMeter, - accountSkipMeter: p.accountSkipMeter, - accountWasteMeter: p.accountWasteMeter, - - storageFetchersMeter: p.storageFetchersMeter, - storageLoadMeter: p.storageLoadMeter, - storageLargestLoadMeter: p.storageLargestLoadMeter, - storageDupMeter: p.storageDupMeter, - storageSkipMeter: p.storageSkipMeter, - storageWasteMeter: p.storageWasteMeter, - } - // If the prefetcher is already a copy, duplicate the data - if p.fetches != nil { - for root, fetch := range p.fetches { - if fetch == nil { - continue - } - copy.fetches[root] = p.db.CopyTrie(fetch) - } - return copy - } - // Otherwise we're copying an active fetcher, retrieve the current states - for id, fetcher := range p.fetchers { - copy.fetches[id] = fetcher.peek() - } - return copy -} - -// prefetch schedules a batch of trie items to prefetch. -func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) { - // If the prefetcher is an inactive one, bail out - if p.fetches != nil { - return - } - - // Active fetcher, schedule the retrievals - id := p.trieID(owner, root) - fetcher := p.fetchers[id] - if fetcher == nil { - fetcher = newSubfetcher(p, owner, root, addr) - p.fetchers[id] = fetcher - } - fetcher.schedule(keys) -} - -// trie returns the trie matching the root hash, or nil if the prefetcher doesn't -// have it. -func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie { - // If the prefetcher is inactive, return from existing deep copies - id := p.trieID(owner, root) - if p.fetches != nil { - trie := p.fetches[id] - if trie == nil { - return nil - } - return p.db.CopyTrie(trie) - } - - // Otherwise the prefetcher is active, bail if no trie was prefetched for this root - fetcher := p.fetchers[id] - if fetcher == nil { - return nil - } - - // Wait for the fetcher to finish and shutdown orchestrator, if it exists - start := time.Now() - fetcher.wait() - if metrics.Enabled { - p.subfetcherWaitTimer.Inc(time.Since(start).Milliseconds()) - } - - // Return a copy of one of the prefetched tries - trie := fetcher.peek() - if trie == nil { - return nil - } - return trie -} - -// used marks a batch of state items used to allow creating statistics as to -// how useful or wasteful the prefetcher is. -func (p *triePrefetcher) used(owner common.Hash, root common.Hash, used [][]byte) { - if fetcher := p.fetchers[p.trieID(owner, root)]; fetcher != nil { - fetcher.used = used - } -} - -// trieID returns an unique trie identifier consists the trie owner and root hash. -func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string { - trieID := make([]byte, common.HashLength*2) - copy(trieID, owner.Bytes()) - copy(trieID[common.HashLength:], root.Bytes()) - return string(trieID) -} - -// subfetcher is a trie fetcher goroutine responsible for pulling entries for a -// single trie. It is spawned when a new root is encountered and lives until the -// main prefetcher is paused and either all requested items are processed or if -// the trie being worked on is retrieved from the prefetcher. -type subfetcher struct { - p *triePrefetcher - - db Database // Database to load trie nodes through - state common.Hash // Root hash of the state to prefetch - owner common.Hash // Owner of the trie, usually account hash - root common.Hash // Root hash of the trie to prefetch - addr common.Address // Address of the account that the trie belongs to - - to *trieOrchestrator // Orchestrate concurrent fetching of a single trie - - seen map[string]struct{} // Tracks the entries already loaded - dups int // Number of duplicate preload tasks - used [][]byte // Tracks the entries used in the end -} - -// newSubfetcher creates a goroutine to prefetch state items belonging to a -// particular root hash. -func newSubfetcher(p *triePrefetcher, owner common.Hash, root common.Hash, addr common.Address) *subfetcher { - sf := &subfetcher{ - p: p, - db: p.db, - state: p.root, - owner: owner, - root: root, - addr: addr, - seen: make(map[string]struct{}), - } - sf.to = newTrieOrchestrator(sf) - if sf.to != nil { - go sf.to.processTasks() - } - // We return [sf] here to ensure we don't try to re-create if - // we aren't able to setup a [newTrieOrchestrator] the first time. - return sf -} - -// schedule adds a batch of trie keys to the queue to prefetch. -// This should never block, so an array is used instead of a channel. -// -// This is not thread-safe. -func (sf *subfetcher) schedule(keys [][]byte) { - // Append the tasks to the current queue - tasks := make([][]byte, 0, len(keys)) - for _, key := range keys { - // Check if keys already seen - sk := string(key) - if _, ok := sf.seen[sk]; ok { - sf.dups++ - continue - } - sf.seen[sk] = struct{}{} - tasks = append(tasks, key) - } - - // After counting keys, exit if they can't be prefetched - if sf.to == nil { - return - } - - // Add tasks to queue for prefetching - sf.to.enqueueTasks(tasks) -} - -// peek tries to retrieve a deep copy of the fetcher's trie in whatever form it -// is currently. -func (sf *subfetcher) peek() Trie { - if sf.to == nil { - return nil - } - return sf.to.copyBase() -} - -// wait must only be called if [triePrefetcher] has not been closed. If this happens, -// workers will not finish. -func (sf *subfetcher) wait() { - if sf.to == nil { - // Unable to open trie - return - } - sf.to.wait() -} - -func (sf *subfetcher) abort() { - if sf.to == nil { - // Unable to open trie - return - } - sf.to.abort() -} - -func (sf *subfetcher) skips() int { - if sf.to == nil { - // Unable to open trie - return 0 - } - return sf.to.skipCount() -} - -func (sf *subfetcher) copies() int { - if sf.to == nil { - // Unable to open trie - return 0 - } - return sf.to.copies -} - -// trieOrchestrator is not thread-safe. -type trieOrchestrator struct { - sf *subfetcher - - // base is an unmodified Trie we keep for - // creating copies for each worker goroutine. - // - // We care more about quick copies than good copies - // because most (if not all) of the nodes that will be populated - // in the copy will come from the underlying triedb cache. Ones - // that don't come from this cache probably had to be fetched - // from disk anyways. - base Trie - baseLock sync.Mutex - - tasksAllowed bool - skips int // number of tasks skipped - pendingTasks [][]byte - taskLock sync.Mutex - - processingTasks sync.WaitGroup - - wake chan struct{} - stop chan struct{} - stopOnce sync.Once - loopTerm chan struct{} - - copies int - copyChan chan Trie - copySpawner chan struct{} -} - -func newTrieOrchestrator(sf *subfetcher) *trieOrchestrator { - // Start by opening the trie and stop processing if it fails - var ( - base Trie - err error - ) - if sf.owner == (common.Hash{}) { - base, err = sf.db.OpenTrie(sf.root) - if err != nil { - log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) - return nil - } - } else { - // The trie argument can be nil as verkle doesn't support prefetching - // yet. TODO FIX IT(rjl493456442), otherwise code will panic here. - base, err = sf.db.OpenStorageTrie(sf.state, sf.addr, sf.root, nil) - if err != nil { - log.Warn("Trie prefetcher failed opening trie", "root", sf.root, "err", err) - return nil - } - } - - // Instantiate trieOrchestrator - to := &trieOrchestrator{ - sf: sf, - base: base, - - tasksAllowed: true, - wake: make(chan struct{}, 1), - stop: make(chan struct{}), - loopTerm: make(chan struct{}), - - copyChan: make(chan Trie, sf.p.maxConcurrency), - copySpawner: make(chan struct{}, sf.p.maxConcurrency), - } - - // Create initial trie copy - to.copies++ - to.copySpawner <- struct{}{} - to.copyChan <- to.copyBase() - return to -} - -func (to *trieOrchestrator) copyBase() Trie { - to.baseLock.Lock() - defer to.baseLock.Unlock() - - return to.sf.db.CopyTrie(to.base) -} - -func (to *trieOrchestrator) skipCount() int { - to.taskLock.Lock() - defer to.taskLock.Unlock() - - return to.skips -} - -func (to *trieOrchestrator) enqueueTasks(tasks [][]byte) { - to.taskLock.Lock() - defer to.taskLock.Unlock() - - if len(tasks) == 0 { - return - } - - // Add tasks to [pendingTasks] - if !to.tasksAllowed { - to.skips += len(tasks) - return - } - to.processingTasks.Add(len(tasks)) - to.pendingTasks = append(to.pendingTasks, tasks...) - - // Wake up processor - select { - case to.wake <- struct{}{}: - default: - } -} - -func (to *trieOrchestrator) handleStop(remaining int) { - to.taskLock.Lock() - to.skips += remaining - to.taskLock.Unlock() - to.processingTasks.Add(-remaining) -} - -func (to *trieOrchestrator) processTasks() { - defer close(to.loopTerm) - - for { - // Determine if we should process or exit - select { - case <-to.wake: - case <-to.stop: - return - } - - // Get current tasks - to.taskLock.Lock() - tasks := to.pendingTasks - to.pendingTasks = nil - to.taskLock.Unlock() - - // Enqueue more work as soon as trie copies are available - lt := len(tasks) - for i := 0; i < lt; i++ { - // Try to stop as soon as possible, if channel is closed - remaining := lt - i - select { - case <-to.stop: - to.handleStop(remaining) - return - default: - } - - // Try to create to get an active copy first (select is non-deterministic, - // so we may end up creating a new copy when we don't need to) - var t Trie - select { - case t = <-to.copyChan: - default: - // Wait for an available copy or create one, if we weren't - // able to get a previously created copy - select { - case <-to.stop: - to.handleStop(remaining) - return - case t = <-to.copyChan: - case to.copySpawner <- struct{}{}: - to.copies++ - t = to.copyBase() - } - } - - // Enqueue work, unless stopped. - fTask := tasks[i] - f := func() { - // Perform task - var err error - if len(fTask) == common.AddressLength { - _, err = t.GetAccount(common.BytesToAddress(fTask)) - } else { - _, err = t.GetStorage(to.sf.addr, fTask) - } - if err != nil { - log.Error("Trie prefetcher failed fetching", "root", to.sf.root, "err", err) - } - to.processingTasks.Done() - - // Return copy when we are done with it, so someone else can use it - // - // channel is buffered and will not block - to.copyChan <- t - } - - // Enqueue task for processing (may spawn new goroutine - // if not at [maxConcurrency]) - // - // If workers are stopped before calling [Execute], this function may - // panic. - to.sf.p.workers.Execute(f) - } - } -} - -func (to *trieOrchestrator) stopAcceptingTasks() { - to.taskLock.Lock() - defer to.taskLock.Unlock() - - if !to.tasksAllowed { - return - } - to.tasksAllowed = false - - // We don't clear [to.pendingTasks] here because - // it will be faster to prefetch them even though we - // are still waiting. -} - -// wait stops accepting new tasks and waits for ongoing tasks to complete. If -// wait is called, it is not necessary to call [abort]. -// -// It is safe to call wait multiple times. -func (to *trieOrchestrator) wait() { - // Prevent more tasks from being enqueued - to.stopAcceptingTasks() - - // Wait for processing tasks to complete - to.processingTasks.Wait() - - // Stop orchestrator loop - to.stopOnce.Do(func() { - close(to.stop) - }) - <-to.loopTerm -} - -// abort stops any ongoing tasks and shuts down the orchestrator loop. If abort -// is called, it is not necessary to call [wait]. -// -// It is safe to call abort multiple times. -func (to *trieOrchestrator) abort() { - // Prevent more tasks from being enqueued - to.stopAcceptingTasks() - - // Stop orchestrator loop - to.stopOnce.Do(func() { - close(to.stop) - }) - <-to.loopTerm - - // Capture any dangling pending tasks (processTasks - // may exit before enqueing all pendingTasks) - to.taskLock.Lock() - pendingCount := len(to.pendingTasks) - to.skips += pendingCount - to.pendingTasks = nil - to.taskLock.Unlock() - to.processingTasks.Add(-pendingCount) - - // Wait for processing tasks to complete - to.processingTasks.Wait() -} diff --git a/core/state/trie_prefetcher_extra_test.go b/core/state/trie_prefetcher_extra_test.go new file mode 100644 index 0000000000..ef75fe2396 --- /dev/null +++ b/core/state/trie_prefetcher_extra_test.go @@ -0,0 +1,196 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package state + +import ( + "crypto/rand" + "encoding/binary" + "fmt" + "os" + "path" + "strconv" + "testing" + + "github.com/ava-labs/avalanchego/database" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + ethmetrics "github.com/ava-labs/libevm/metrics" + "github.com/ava-labs/libevm/triedb" + "github.com/ava-labs/subnet-evm/core/rawdb" + "github.com/ava-labs/subnet-evm/core/state/snapshot" + "github.com/ava-labs/subnet-evm/core/types" + "github.com/ava-labs/subnet-evm/metrics" + "github.com/ava-labs/subnet-evm/triedb/hashdb" + "github.com/stretchr/testify/require" +) + +const ( + namespace = "chain" + + // triePrefetchMetricsPrefix is the prefix for trie prefetcher metrics + // and MUST match upstream for the benchmark to work. + triePrefetchMetricsPrefix = "trie/prefetch/" +) + +// BenchmarkPrefetcherDatabase benchmarks the performance of the trie +// prefetcher. By default, a state with 100k storage keys is created and stored +// in a temporary directory. Setting the TEST_DB_KVS and TEST_DB_DIR environment +// variables modifies the defaults. The benchmark measures the time to update +// the trie after 100, 200, and 500 storage slot updates per iteration, +// simulating a block with that number of storage slot updates. For performance +// reasons, when making changes involving the trie prefetcher, this benchmark +// should be run against a state including around 100m storage entries. +func BenchmarkPrefetcherDatabase(b *testing.B) { + require := require.New(b) + metricsEnabled := ethmetrics.Enabled + ethmetrics.Enabled = true + defer func() { ethmetrics.Enabled = metricsEnabled }() + + dir := b.TempDir() + if env := os.Getenv("TEST_DB_DIR"); env != "" { + dir = env + } + wantKVs := 100_000 + if env := os.Getenv("TEST_DB_KVS"); env != "" { + var err error + wantKVs, err = strconv.Atoi(env) + require.NoError(err) + } + + levelDB, err := rawdb.NewLevelDBDatabase(path.Join(dir, "level.db"), 0, 0, "", false) + require.NoError(err) + + root := types.EmptyRootHash + count := uint64(0) + block := uint64(0) + + rootKey := []byte("root") + countKey := []byte("count") + blockKey := []byte("block") + got, err := levelDB.Get(rootKey) + if err == nil { // on success + root = common.BytesToHash(got) + } + got, err = levelDB.Get(countKey) + if err == nil { // on success + count = binary.BigEndian.Uint64(got) + } + got, err = levelDB.Get(blockKey) + if err == nil { // on success + block = binary.BigEndian.Uint64(got) + } + + // Make a trie on the levelDB + address1 := common.Address{42} + address2 := common.Address{43} + addBlock := func(db Database, snaps *snapshot.Tree, kvsPerBlock int, prefetchers int) { + _, root, err = addKVs(db, snaps, address1, address2, root, block, kvsPerBlock, prefetchers) + require.NoError(err) + count += uint64(kvsPerBlock) + block++ + } + + lastCommit := block + commit := func(levelDB ethdb.Database, snaps *snapshot.Tree, db Database) { + require.NoError(db.TrieDB().Commit(root, false)) + + for i := lastCommit + 1; i <= block; i++ { + require.NoError(snaps.Flatten(fakeHash(i))) + } + lastCommit = block + + // update the tracking keys + require.NoError(levelDB.Put(rootKey, root.Bytes())) + require.NoError(database.PutUInt64(levelDB, blockKey, block)) + require.NoError(database.PutUInt64(levelDB, countKey, count)) + } + + tdbConfig := &triedb.Config{ + DBOverride: hashdb.Config{ + CleanCacheSize: 3 * 1024 * 1024 * 1024, + }.BackendConstructor, + } + db := NewDatabaseWithConfig(levelDB, tdbConfig) + snaps := snapshot.NewTestTree(levelDB, fakeHash(block), root) + for count < uint64(wantKVs) { + previous := root + addBlock(db, snaps, 100_000, 0) // Note this updates root and count + b.Logf("Root: %v, kvs: %d, block: %d", root, count, block) + + // Commit every 10 blocks or on the last iteration + if block%10 == 0 || count >= uint64(wantKVs) { + commit(levelDB, snaps, db) + b.Logf("Root: %v, kvs: %d, block: %d (committed)", root, count, block) + } + if previous != root { + require.NoError(db.TrieDB().Dereference(previous)) + } else { + b.Fatal("root did not change") + } + } + require.NoError(levelDB.Close()) + b.Logf("Starting benchmarks") + b.Logf("Root: %v, kvs: %d, block: %d", root, count, block) + for _, updates := range []int{100, 200, 500} { + for _, prefetchers := range []int{0, 1, 4, 16} { + b.Run(fmt.Sprintf("updates_%d_prefetchers_%d", updates, prefetchers), func(b *testing.B) { + startRoot, startBlock, startCount := root, block, count + defer func() { root, block, count = startRoot, startBlock, startCount }() + + levelDB, err := rawdb.NewLevelDBDatabase(path.Join(dir, "level.db"), 0, 0, "", false) + require.NoError(err) + snaps := snapshot.NewTestTree(levelDB, fakeHash(block), root) + db := NewDatabaseWithConfig(levelDB, tdbConfig) + getMetric := func(metric string) int64 { + meter := metrics.GetOrRegisterMeter(triePrefetchMetricsPrefix+namespace+"/storage/"+metric, nil) + return meter.Snapshot().Count() + } + startLoads := getMetric("load") + for i := 0; i < b.N; i++ { + addBlock(db, snaps, updates, prefetchers) + } + require.NoError(levelDB.Close()) + b.ReportMetric(float64(getMetric("load")-startLoads)/float64(b.N), "loads") + }) + } + } +} + +func fakeHash(block uint64) common.Hash { + return common.BytesToHash(binary.BigEndian.AppendUint64(nil, block)) +} + +// addKVs adds count random key-value pairs to the state trie of address1 and +// address2 (each count/2) and returns the new state db and root. +func addKVs( + db Database, snaps *snapshot.Tree, + address1, address2 common.Address, root common.Hash, block uint64, + count int, prefetchers int, +) (*StateDB, common.Hash, error) { + statedb, err := New(root, db, snaps) + if err != nil { + return nil, common.Hash{}, fmt.Errorf("creating state with snapshot: %w", err) + } + if prefetchers > 0 { + statedb.StartPrefetcher(namespace, WithConcurrentWorkers(prefetchers)) + defer statedb.StopPrefetcher() + } + for _, address := range []common.Address{address1, address2} { + statedb.SetNonce(address, 1) + for i := 0; i < count/2; i++ { + key := make([]byte, 32) + value := make([]byte, 32) + rand.Read(key) + rand.Read(value) + + statedb.SetState(address, common.BytesToHash(key), common.BytesToHash(value)) + } + } + blockHashes := snapshot.WithBlockHashes(fakeHash(block+1), fakeHash(block)) + root, err = statedb.Commit(block+1, true, blockHashes) + if err != nil { + return nil, common.Hash{}, fmt.Errorf("committing with snap: %w", err) + } + return statedb, root, nil +} diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go deleted file mode 100644 index b8edcbb6a8..0000000000 --- a/core/state/trie_prefetcher_test.go +++ /dev/null @@ -1,124 +0,0 @@ -// (c) 2019-2020, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2021 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 state - -import ( - "math/big" - "testing" - "time" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/holiman/uint256" -) - -const maxConcurrency = 4 - -func filledStateDB() *StateDB { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) - - // Create an account and check if the retrieved balance is correct - addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") - skey := common.HexToHash("aaa") - sval := common.HexToHash("bbb") - - state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie - state.SetCode(addr, []byte("hello")) // Change an external metadata - state.SetState(addr, skey, sval) // Change the storage trie - for i := 0; i < 100; i++ { - sk := common.BigToHash(big.NewInt(int64(i))) - state.SetState(addr, sk, sk) // Change the storage trie - } - return state -} - -func TestCopyAndClose(t *testing.T) { - db := filledStateDB() - prefetcher := newTriePrefetcher(db.db, db.originalRoot, "", maxConcurrency) - skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - time.Sleep(1 * time.Second) - a := prefetcher.trie(common.Hash{}, db.originalRoot) - prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - b := prefetcher.trie(common.Hash{}, db.originalRoot) - cpy := prefetcher.copy() - cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - c := cpy.trie(common.Hash{}, db.originalRoot) - prefetcher.close() - cpy2 := cpy.copy() - cpy2.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - d := cpy2.trie(common.Hash{}, db.originalRoot) - cpy.close() - cpy2.close() - if a.Hash() != b.Hash() || a.Hash() != c.Hash() || a.Hash() != d.Hash() { - t.Fatalf("Invalid trie, hashes should be equal: %v %v %v %v", a.Hash(), b.Hash(), c.Hash(), d.Hash()) - } -} - -func TestUseAfterClose(t *testing.T) { - db := filledStateDB() - prefetcher := newTriePrefetcher(db.db, db.originalRoot, "", maxConcurrency) - skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - a := prefetcher.trie(common.Hash{}, db.originalRoot) - prefetcher.close() - b := prefetcher.trie(common.Hash{}, db.originalRoot) - if a == nil { - t.Fatal("Prefetching before close should not return nil") - } - if b != nil { - t.Fatal("Trie after close should return nil") - } -} - -func TestCopyClose(t *testing.T) { - db := filledStateDB() - prefetcher := newTriePrefetcher(db.db, db.originalRoot, "", maxConcurrency) - skey := common.HexToHash("aaa") - prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}) - cpy := prefetcher.copy() - a := prefetcher.trie(common.Hash{}, db.originalRoot) - b := cpy.trie(common.Hash{}, db.originalRoot) - prefetcher.close() - c := prefetcher.trie(common.Hash{}, db.originalRoot) - d := cpy.trie(common.Hash{}, db.originalRoot) - if a == nil { - t.Fatal("Prefetching before close should not return nil") - } - if b == nil { - t.Fatal("Copy trie should return nil") - } - if c != nil { - t.Fatal("Trie after close should return nil") - } - if d == nil { - t.Fatal("Copy trie should not return nil") - } -} diff --git a/core/state_manager.go b/core/state_manager.go index a22f51041c..7218daf42d 100644 --- a/core/state_manager.go +++ b/core/state_manager.go @@ -31,9 +31,9 @@ import ( "math/rand" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" ) func init() { diff --git a/core/state_manager_test.go b/core/state_manager_test.go index 65c56dcf7e..2c11be4891 100644 --- a/core/state_manager_test.go +++ b/core/state_manager_test.go @@ -9,7 +9,7 @@ import ( "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/assert" ) diff --git a/core/state_processor.go b/core/state_processor.go index 789162bf13..4a97a631c0 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -31,6 +31,10 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/core/extstate" "github.com/ava-labs/subnet-evm/core/state" @@ -39,10 +43,6 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/stateupgrade" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" ) // StateProcessor is a basic Processor, which takes care of transitioning diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 971e9678e5..40203c5a1e 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -32,6 +32,10 @@ import ( "testing" "github.com/ava-labs/avalanchego/upgrade" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" @@ -39,11 +43,7 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" - "github.com/ava-labs/subnet-evm/trie" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) diff --git a/core/state_transition.go b/core/state_transition.go index fc0376f6ec..18fa39f41d 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -31,17 +31,15 @@ import ( "math" "math/big" - "github.com/ava-labs/subnet-evm/constants" + "github.com/ava-labs/libevm/common" + cmath "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto/kzg4844" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" - "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/utils" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" - cmath "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/holiman/uint256" ) @@ -333,18 +331,6 @@ func (st *StateTransition) buyGas() error { return nil } -// TODO: Probably can be removed -- extremely unlikely someone has private keys -// to known hashes. -// IsProhibited returns true if [addr] is in the prohibited list of addresses which should -// not be allowed as an EOA or newly created contract address. -func IsProhibited(addr common.Address) bool { - if addr == constants.BlackholeAddr { - return true - } - - return modules.ReservedAddress(addr) -} - func (st *StateTransition) preCheck() error { // Only check transactions that are not fake msg := st.msg @@ -367,10 +353,6 @@ func (st *StateTransition) preCheck() error { return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA, msg.From.Hex(), codeHash) } - // Make sure the sender is not prohibited - if IsProhibited(msg.From) { - return fmt.Errorf("%w: address %v", vmerrs.ErrAddrProhibited, msg.From) - } // Check that the sender is on the tx allow list if enabled if params.GetExtra(st.evm.ChainConfig()).IsPrecompileEnabled(txallowlist.ContractAddress, st.evm.Context.Time) { diff --git a/core/test_blockchain.go b/core/test_blockchain.go index 736dff1634..5e7f394a02 100644 --- a/core/test_blockchain.go +++ b/core/test_blockchain.go @@ -10,6 +10,9 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" @@ -20,9 +23,6 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contracts/deployerallowlist" "github.com/ava-labs/subnet-evm/precompile/contracts/feemanager" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/holiman/uint256" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/core/trie_stress_bench_test.go b/core/trie_stress_bench_test.go index faaea2ca10..11b01bfa11 100644 --- a/core/trie_stress_bench_test.go +++ b/core/trie_stress_bench_test.go @@ -31,11 +31,11 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) diff --git a/core/txindexer.go b/core/txindexer.go index 178f31d05f..9d99e1a2ef 100644 --- a/core/txindexer.go +++ b/core/txindexer.go @@ -20,9 +20,9 @@ import ( "fmt" "time" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" ) // TxIndexProgress is the struct describing the progress for transaction indexing. diff --git a/core/txindexer_test.go b/core/txindexer_test.go index 39d71d49ce..b430c97e90 100644 --- a/core/txindexer_test.go +++ b/core/txindexer_test.go @@ -21,13 +21,13 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/stretchr/testify/require" ) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 470a2b4e39..6546dc885b 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -39,6 +39,10 @@ import ( "sync" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" "github.com/ava-labs/subnet-evm/core" @@ -47,10 +51,6 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/metrics" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/billy" "github.com/holiman/uint256" ) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index e366f9cf53..1cb56b48ce 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -39,6 +39,12 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/crypto/kzg4844" + "github.com/ava-labs/libevm/ethdb/memorydb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" @@ -48,12 +54,6 @@ import ( "github.com/ava-labs/subnet-evm/core/txpool" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/kzg4844" - "github.com/ethereum/go-ethereum/ethdb/memorydb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/billy" "github.com/holiman/uint256" ) diff --git a/core/txpool/blobpool/config.go b/core/txpool/blobpool/config.go index 5df7885fb3..d7b94535a7 100644 --- a/core/txpool/blobpool/config.go +++ b/core/txpool/blobpool/config.go @@ -27,7 +27,7 @@ package blobpool import ( - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" ) // Config are the configuration parameters of the blob transaction pool. diff --git a/core/txpool/blobpool/evictheap.go b/core/txpool/blobpool/evictheap.go index 0824ddf735..7c7525371c 100644 --- a/core/txpool/blobpool/evictheap.go +++ b/core/txpool/blobpool/evictheap.go @@ -32,7 +32,7 @@ import ( "math" "sort" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/holiman/uint256" ) diff --git a/core/txpool/blobpool/evictheap_test.go b/core/txpool/blobpool/evictheap_test.go index 622a3869ea..9b7c0680bf 100644 --- a/core/txpool/blobpool/evictheap_test.go +++ b/core/txpool/blobpool/evictheap_test.go @@ -31,8 +31,8 @@ import ( mrand "math/rand" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" ) diff --git a/core/txpool/blobpool/interface.go b/core/txpool/blobpool/interface.go index d5603cf566..ced9bf3c50 100644 --- a/core/txpool/blobpool/interface.go +++ b/core/txpool/blobpool/interface.go @@ -29,11 +29,11 @@ package blobpool import ( "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" ) // BlockChain defines the minimal set of methods needed to back a blob pool with diff --git a/core/txpool/blobpool/limbo.go b/core/txpool/blobpool/limbo.go index 26d28f36cc..fbbaa674f2 100644 --- a/core/txpool/blobpool/limbo.go +++ b/core/txpool/blobpool/limbo.go @@ -29,10 +29,10 @@ package blobpool import ( "errors" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/billy" ) diff --git a/core/txpool/legacypool/journal.go b/core/txpool/legacypool/journal.go index 3e5d43e123..cc81b03409 100644 --- a/core/txpool/legacypool/journal.go +++ b/core/txpool/legacypool/journal.go @@ -32,10 +32,10 @@ import ( "io/fs" "os" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) // errNoActiveJournal is returned if a transaction is attempted to be inserted diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 16b9f27dbf..42ee81b741 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -36,6 +36,10 @@ import ( "sync/atomic" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/prque" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core" @@ -46,10 +50,6 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/contracts/feemanager" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/prque" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" "github.com/holiman/uint256" ) diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index 30e2fc8057..a36bdb02df 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -30,12 +30,12 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/event" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/event" "github.com/holiman/uint256" ) diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index fcf48749f4..035ffdac22 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -39,6 +39,10 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/rawdb" @@ -46,10 +50,6 @@ import ( "github.com/ava-labs/subnet-evm/core/txpool" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/event" "github.com/holiman/uint256" ) diff --git a/core/txpool/legacypool/list.go b/core/txpool/legacypool/list.go index 59bff71d4e..7bf2966ed1 100644 --- a/core/txpool/legacypool/list.go +++ b/core/txpool/legacypool/list.go @@ -35,8 +35,8 @@ import ( "sync/atomic" "time" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" "golang.org/x/exp/slices" ) diff --git a/core/txpool/legacypool/list_test.go b/core/txpool/legacypool/list_test.go index 28670fe953..a37120a5a9 100644 --- a/core/txpool/legacypool/list_test.go +++ b/core/txpool/legacypool/list_test.go @@ -31,9 +31,9 @@ import ( "math/rand" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/holiman/uint256" ) diff --git a/core/txpool/legacypool/noncer.go b/core/txpool/legacypool/noncer.go index b0280882ff..e2ef634a14 100644 --- a/core/txpool/legacypool/noncer.go +++ b/core/txpool/legacypool/noncer.go @@ -29,8 +29,8 @@ package legacypool import ( "sync" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/state" - "github.com/ethereum/go-ethereum/common" ) // noncer is a tiny virtual state database to manage the executable nonces of diff --git a/core/txpool/subpool.go b/core/txpool/subpool.go index 5459154090..e1668ca573 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -30,10 +30,10 @@ import ( "math/big" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/event" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/event" "github.com/holiman/uint256" ) diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index e65babe5a3..a06f7f7387 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -33,12 +33,12 @@ import ( "sync" "sync/atomic" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/metrics" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" ) var ( diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 8328b2a3f8..be02e7949f 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -31,15 +31,15 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto/kzg4844" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto/kzg4844" - "github.com/ethereum/go-ethereum/log" ) var ( diff --git a/core/types.go b/core/types.go index 3975611959..31a608585d 100644 --- a/core/types.go +++ b/core/types.go @@ -27,9 +27,9 @@ package core import ( + "github.com/ava-labs/libevm/core/vm" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/core/vm" ) // Validator is an interface which defines the standard for block validation. It diff --git a/core/types/account.go b/core/types/account.go index bb0f4ca02e..efc0927770 100644 --- a/core/types/account.go +++ b/core/types/account.go @@ -23,9 +23,9 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" ) //go:generate go run github.com/fjl/gencodec -type Account -field-override accountMarshaling -out gen_account.go diff --git a/core/types/block.go b/core/types/block.go index 81393e52ee..29963da626 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -34,9 +34,9 @@ import ( "reflect" "sync/atomic" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/rlp" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/rlp" ) // A BlockNonce is a 64-bit hash which proves (combined with the @@ -67,7 +67,7 @@ func (n *BlockNonce) UnmarshalText(input []byte) error { } //go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go -//go:generate go run github.com/ethereum/go-ethereum/rlp/rlpgen -type Header -out gen_header_rlp.go +//go:generate go run github.com/ava-labs/libevm/rlp/rlpgen -type Header -out gen_header_rlp.go // Header represents a block header in the Ethereum blockchain. type Header struct { diff --git a/core/types/block_test.go b/core/types/block_test.go index 67fc3b5adc..8a004c93be 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -32,12 +32,12 @@ import ( "reflect" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/params" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/internal/blocktest" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" ) func TestBlockEncoding(t *testing.T) { diff --git a/core/types/gen_account.go b/core/types/gen_account.go index 4e475896a7..c3c7fb3fdf 100644 --- a/core/types/gen_account.go +++ b/core/types/gen_account.go @@ -7,9 +7,9 @@ import ( "errors" "math/big" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" ) var _ = (*accountMarshaling)(nil) diff --git a/core/types/gen_account_rlp.go b/core/types/gen_account_rlp.go deleted file mode 100644 index 3d2f67ab0f..0000000000 --- a/core/types/gen_account_rlp.go +++ /dev/null @@ -1,24 +0,0 @@ -// Code generated by rlpgen. DO NOT EDIT. - -package types - -import ( - "io" - - "github.com/ethereum/go-ethereum/rlp" -) - -func (obj *StateAccount) EncodeRLP(_w io.Writer) error { - w := rlp.NewEncoderBuffer(_w) - _tmp0 := w.List() - w.WriteUint64(obj.Nonce) - if obj.Balance == nil { - w.Write(rlp.EmptyString) - } else { - w.WriteUint256(obj.Balance) - } - w.WriteBytes(obj.Root[:]) - w.WriteBytes(obj.CodeHash) - w.ListEnd(_tmp0) - return w.Flush() -} diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index 0bc26511f0..3921526a6b 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -7,8 +7,8 @@ import ( "errors" "math/big" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" ) var _ = (*headerMarshaling)(nil) diff --git a/core/types/gen_header_rlp.go b/core/types/gen_header_rlp.go index 6553c079ca..8ad0c44146 100644 --- a/core/types/gen_header_rlp.go +++ b/core/types/gen_header_rlp.go @@ -2,7 +2,7 @@ package types -import "github.com/ethereum/go-ethereum/rlp" +import "github.com/ava-labs/libevm/rlp" import "io" func (obj *Header) EncodeRLP(_w io.Writer) error { diff --git a/core/types/hashes.go b/core/types/hashes.go index 8ed4dd152b..f40d2e7336 100644 --- a/core/types/hashes.go +++ b/core/types/hashes.go @@ -27,9 +27,9 @@ package types import ( - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" ) var ( diff --git a/core/types/hashing.go b/core/types/hashing.go index c7e03a2b03..b6b631c7bc 100644 --- a/core/types/hashing.go +++ b/core/types/hashing.go @@ -30,9 +30,9 @@ import ( "bytes" "sync" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/rlp" "golang.org/x/crypto/sha3" ) diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index af2f72a8d5..b299b7181c 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -34,14 +34,14 @@ import ( mrand "math/rand" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" ) func TestDeriveSha(t *testing.T) { diff --git a/core/types/imports.go b/core/types/imports.go index 42f7f55576..81c661d959 100644 --- a/core/types/imports.go +++ b/core/types/imports.go @@ -4,74 +4,74 @@ package types import ( - gethtypes "github.com/ethereum/go-ethereum/core/types" + ethtypes "github.com/ava-labs/libevm/core/types" ) // The following types are used directly as their upstream definitions. // So we list them all here to avoid having many individual files. type ( - AccessList = gethtypes.AccessList - AccessTuple = gethtypes.AccessTuple - AccessListTx = gethtypes.AccessListTx - Bloom = gethtypes.Bloom - Receipt = gethtypes.Receipt - Receipts = gethtypes.Receipts - ReceiptForStorage = gethtypes.ReceiptForStorage - LegacyTx = gethtypes.LegacyTx - DynamicFeeTx = gethtypes.DynamicFeeTx - BlobTx = gethtypes.BlobTx - BlobTxSidecar = gethtypes.BlobTxSidecar - Signer = gethtypes.Signer - HomesteadSigner = gethtypes.HomesteadSigner - FrontierSigner = gethtypes.FrontierSigner + AccessList = ethtypes.AccessList + AccessTuple = ethtypes.AccessTuple + AccessListTx = ethtypes.AccessListTx + Bloom = ethtypes.Bloom + Receipt = ethtypes.Receipt + Receipts = ethtypes.Receipts + ReceiptForStorage = ethtypes.ReceiptForStorage + LegacyTx = ethtypes.LegacyTx + DynamicFeeTx = ethtypes.DynamicFeeTx + BlobTx = ethtypes.BlobTx + BlobTxSidecar = ethtypes.BlobTxSidecar + Signer = ethtypes.Signer + HomesteadSigner = ethtypes.HomesteadSigner + FrontierSigner = ethtypes.FrontierSigner - Transaction = gethtypes.Transaction - Transactions = gethtypes.Transactions - TxByNonce = gethtypes.TxByNonce - TxData = gethtypes.TxData + Transaction = ethtypes.Transaction + Transactions = ethtypes.Transactions + TxByNonce = ethtypes.TxByNonce + TxData = ethtypes.TxData ) // The following constants are used directly as their upstream definitions. const ( - BloomBitLength = gethtypes.BloomBitLength - BloomByteLength = gethtypes.BloomByteLength - ReceiptStatusFailed = gethtypes.ReceiptStatusFailed - ReceiptStatusSuccessful = gethtypes.ReceiptStatusSuccessful + BloomBitLength = ethtypes.BloomBitLength + BloomByteLength = ethtypes.BloomByteLength + ReceiptStatusFailed = ethtypes.ReceiptStatusFailed + ReceiptStatusSuccessful = ethtypes.ReceiptStatusSuccessful // Transaction types. - LegacyTxType = gethtypes.LegacyTxType - AccessListTxType = gethtypes.AccessListTxType - DynamicFeeTxType = gethtypes.DynamicFeeTxType - BlobTxType = gethtypes.BlobTxType + LegacyTxType = ethtypes.LegacyTxType + AccessListTxType = ethtypes.AccessListTxType + DynamicFeeTxType = ethtypes.DynamicFeeTxType + BlobTxType = ethtypes.BlobTxType ) // The following functions are used directly as their upstream definitions. var ( - BloomLookup = gethtypes.BloomLookup - BytesToBloom = gethtypes.BytesToBloom - CreateBloom = gethtypes.CreateBloom - NewReceipt = gethtypes.NewReceipt - NewContractCreation = gethtypes.NewContractCreation - NewTransaction = gethtypes.NewTransaction + BloomLookup = ethtypes.BloomLookup + BytesToBloom = ethtypes.BytesToBloom + CreateBloom = ethtypes.CreateBloom + NewReceipt = ethtypes.NewReceipt + NewContractCreation = ethtypes.NewContractCreation + NewTransaction = ethtypes.NewTransaction // Signers - NewEIP155Signer = gethtypes.NewEIP155Signer - NewEIP2930Signer = gethtypes.NewEIP2930Signer - NewLondonSigner = gethtypes.NewLondonSigner - NewCancunSigner = gethtypes.NewCancunSigner - MakeSigner = gethtypes.MakeSigner - LatestSigner = gethtypes.LatestSigner - LatestSignerForChainID = gethtypes.LatestSignerForChainID - SignTx = gethtypes.SignTx - SignNewTx = gethtypes.SignNewTx - MustSignNewTx = gethtypes.MustSignNewTx - Sender = gethtypes.Sender + NewEIP155Signer = ethtypes.NewEIP155Signer + NewEIP2930Signer = ethtypes.NewEIP2930Signer + NewLondonSigner = ethtypes.NewLondonSigner + NewCancunSigner = ethtypes.NewCancunSigner + MakeSigner = ethtypes.MakeSigner + LatestSigner = ethtypes.LatestSigner + LatestSignerForChainID = ethtypes.LatestSignerForChainID + SignTx = ethtypes.SignTx + SignNewTx = ethtypes.SignNewTx + MustSignNewTx = ethtypes.MustSignNewTx + Sender = ethtypes.Sender // Transactions - NewTx = gethtypes.NewTx - TxDifference = gethtypes.TxDifference + NewTx = ethtypes.NewTx + TxDifference = ethtypes.TxDifference // Errors - ErrTxTypeNotSupported = gethtypes.ErrTxTypeNotSupported - ErrGasFeeCapTooLow = gethtypes.ErrGasFeeCapTooLow + ErrTxTypeNotSupported = ethtypes.ErrTxTypeNotSupported + ErrGasFeeCapTooLow = ethtypes.ErrGasFeeCapTooLow ) diff --git a/core/types/log.go b/core/types/log.go index 74c8d343f5..5ddb090034 100644 --- a/core/types/log.go +++ b/core/types/log.go @@ -26,11 +26,11 @@ package types -import gethtypes "github.com/ethereum/go-ethereum/core/types" +import ethtypes "github.com/ava-labs/libevm/core/types" // Log represents a contract log event. These events are generated by the LOG opcode and // stored/indexed by the node. -type Log = gethtypes.Log +type Log = ethtypes.Log // FlattenLogs converts a nested array of logs to a single array of logs. func FlattenLogs(list [][]*Log) []*Log { diff --git a/core/types/rlp_fuzzer_test.go b/core/types/rlp_fuzzer_test.go index a3b9f72436..4e3645874a 100644 --- a/core/types/rlp_fuzzer_test.go +++ b/core/types/rlp_fuzzer_test.go @@ -22,7 +22,7 @@ import ( "math/big" "testing" - "github.com/ethereum/go-ethereum/rlp" + "github.com/ava-labs/libevm/rlp" "github.com/holiman/uint256" ) diff --git a/core/types/state_account.go b/core/types/state_account.go index 96c270a944..20dd6a0f2d 100644 --- a/core/types/state_account.go +++ b/core/types/state_account.go @@ -27,105 +27,19 @@ package types import ( - "bytes" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" - "github.com/holiman/uint256" + ethtypes "github.com/ava-labs/libevm/core/types" ) -//go:generate go run github.com/ethereum/go-ethereum/rlp/rlpgen -type StateAccount -out gen_account_rlp.go - -// StateAccount is the Ethereum consensus representation of accounts. -// These objects are stored in the main account trie. -type StateAccount struct { - Nonce uint64 - Balance *uint256.Int - Root common.Hash // merkle root of the storage trie - CodeHash []byte -} - -// NewEmptyStateAccount constructs an empty state account. -func NewEmptyStateAccount() *StateAccount { - return &StateAccount{ - Balance: new(uint256.Int), - Root: EmptyRootHash, - CodeHash: EmptyCodeHash.Bytes(), - } -} - -// Copy returns a deep-copied state account object. -func (acct *StateAccount) Copy() *StateAccount { - var balance *uint256.Int - if acct.Balance != nil { - balance = new(uint256.Int).Set(acct.Balance) - } - return &StateAccount{ - Nonce: acct.Nonce, - Balance: balance, - Root: acct.Root, - CodeHash: common.CopyBytes(acct.CodeHash), - } -} - -// SlimAccount is a modified version of an Account, where the root is replaced -// with a byte slice. This format can be used to represent full-consensus format -// or slim format which replaces the empty root and code hash as nil byte slice. -type SlimAccount struct { - Nonce uint64 - Balance *uint256.Int - Root []byte // Nil if root equals to types.EmptyRootHash - CodeHash []byte // Nil if hash equals to types.EmptyCodeHash -} - -// SlimAccountRLP encodes the state account in 'slim RLP' format. -func SlimAccountRLP(account StateAccount) []byte { - slim := SlimAccount{ - Nonce: account.Nonce, - Balance: account.Balance, - } - if account.Root != EmptyRootHash { - slim.Root = account.Root[:] - } - if !bytes.Equal(account.CodeHash, EmptyCodeHash[:]) { - slim.CodeHash = account.CodeHash - } - data, err := rlp.EncodeToBytes(slim) - if err != nil { - panic(err) - } - return data -} - -// FullAccount decodes the data on the 'slim RLP' format and returns -// the consensus format account. -func FullAccount(data []byte) (*StateAccount, error) { - var slim SlimAccount - if err := rlp.DecodeBytes(data, &slim); err != nil { - return nil, err - } - var account StateAccount - account.Nonce, account.Balance = slim.Nonce, slim.Balance - - // Interpret the storage root and code hash in slim format. - if len(slim.Root) == 0 { - account.Root = EmptyRootHash - } else { - account.Root = common.BytesToHash(slim.Root) - } - if len(slim.CodeHash) == 0 { - account.CodeHash = EmptyCodeHash[:] - } else { - account.CodeHash = slim.CodeHash - } - return &account, nil -} +type ( + // Import these types from the go-ethereum package + StateAccount = ethtypes.StateAccount + SlimAccount = ethtypes.SlimAccount +) -// FullAccountRLP converts data on the 'slim RLP' format into the full RLP-format. -func FullAccountRLP(data []byte) ([]byte, error) { - account, err := FullAccount(data) - if err != nil { - return nil, err - } - return rlp.EncodeToBytes(account) -} +var ( + // Import these functions from the go-ethereum package + NewEmptyStateAccount = ethtypes.NewEmptyStateAccount + SlimAccountRLP = ethtypes.SlimAccountRLP + FullAccount = ethtypes.FullAccount + FullAccountRLP = ethtypes.FullAccountRLP +) diff --git a/core/types/types_test.go b/core/types/types_test.go index 7b68db9b4b..7620aafb7f 100644 --- a/core/types/types_test.go +++ b/core/types/types_test.go @@ -30,9 +30,9 @@ import ( "math/big" "testing" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/rlp" ) type devnull struct{ len int } diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 3ed45e0e30..e42a5d64ed 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -27,8 +27,8 @@ package runtime import ( + "github.com/ava-labs/libevm/core/vm" "github.com/ava-labs/subnet-evm/core" - "github.com/ethereum/go-ethereum/core/vm" ) func NewEnv(cfg *Config) *vm.EVM { diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index bd06c02410..c7b25ddea5 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -30,13 +30,13 @@ import ( "math" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" "github.com/holiman/uint256" ) diff --git a/core/vm/runtime/runtime_example_test.go b/core/vm/runtime/runtime_example_test.go index eece05b09b..4baa6137c1 100644 --- a/core/vm/runtime/runtime_example_test.go +++ b/core/vm/runtime/runtime_example_test.go @@ -29,8 +29,8 @@ package runtime_test import ( "fmt" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/vm/runtime" - "github.com/ethereum/go-ethereum/common" ) func ExampleExecute() { diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index f4e05c19cf..653a6cbdae 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -33,6 +33,10 @@ import ( "strings" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/asm" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/eth/tracers/logger" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/core" @@ -41,13 +45,9 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/eth/tracers" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/asm" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/logger" // force-load js tracers to trigger registration - _ "github.com/ethereum/go-ethereum/eth/tracers/js" + _ "github.com/ava-labs/libevm/eth/tracers/js" "github.com/holiman/uint256" ) diff --git a/eth/api.go b/eth/api.go index 5842cb5625..dbea129203 100644 --- a/eth/api.go +++ b/eth/api.go @@ -27,7 +27,7 @@ package eth import ( - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) // EthereumAPI provides an API to access Ethereum full node-related information. diff --git a/eth/api_admin.go b/eth/api_admin.go index 4a5237b3a9..3e25d62e0e 100644 --- a/eth/api_admin.go +++ b/eth/api_admin.go @@ -34,9 +34,9 @@ import ( "os" "strings" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/rlp" ) // AdminAPI is the collection of Ethereum full node related APIs for node diff --git a/eth/api_backend.go b/eth/api_backend.go index 3063dc0ba3..4845ded25e 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -32,6 +32,11 @@ import ( "math/big" "time" + "github.com/ava-labs/libevm/accounts" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/event" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/dummy" @@ -44,11 +49,6 @@ import ( "github.com/ava-labs/subnet-evm/eth/tracers" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" ) var ErrUnfinalizedData = errors.New("cannot query unfinalized data") diff --git a/eth/api_backend_test.go b/eth/api_backend_test.go index 0d608f5085..4b9be62dbc 100644 --- a/eth/api_backend_test.go +++ b/eth/api_backend_test.go @@ -30,9 +30,9 @@ import ( "fmt" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/eth/api_debug.go b/eth/api_debug.go index d70957bb66..067523775f 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -32,17 +32,17 @@ import ( "fmt" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/internal/ethapi" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) // DebugAPI is the collection of Ethereum full node APIs for debugging the diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index 218f686337..02d339ca10 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -33,16 +33,16 @@ import ( "strings" "testing" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/triedb" "github.com/holiman/uint256" "github.com/davecgh/go-spew/spew" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "golang.org/x/exp/slices" ) diff --git a/eth/backend.go b/eth/backend.go index 76a24f3edd..d42fc3a709 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -35,6 +35,12 @@ import ( "time" "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/libevm/accounts" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/bloombits" @@ -53,12 +59,6 @@ import ( "github.com/ava-labs/subnet-evm/node" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" ) // Config contains the configuration options of the ETH protocol. diff --git a/eth/bloombits.go b/eth/bloombits.go index 5d814b3ff6..40fb97de96 100644 --- a/eth/bloombits.go +++ b/eth/bloombits.go @@ -29,8 +29,8 @@ package eth import ( "time" + "github.com/ava-labs/libevm/common/bitutil" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common/bitutil" ) const ( diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index d8549b26af..6a25e64cdd 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -29,13 +29,13 @@ package ethconfig import ( "time" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/txpool/blobpool" "github.com/ava-labs/subnet-evm/core/txpool/legacypool" "github.com/ava-labs/subnet-evm/eth/gasprice" "github.com/ava-labs/subnet-evm/miner" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" ) // DefaultFullGPOConfig contains default gasprice oracle settings for full node. diff --git a/eth/filters/api.go b/eth/filters/api.go index 0748822b97..8393e5555e 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -35,13 +35,13 @@ import ( "sync" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/event" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/interfaces" "github.com/ava-labs/subnet-evm/internal/ethapi" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/event" ) var ( diff --git a/eth/filters/api_test.go b/eth/filters/api_test.go index d2f7ec0e69..5f6f0a386d 100644 --- a/eth/filters/api_test.go +++ b/eth/filters/api_test.go @@ -21,8 +21,8 @@ import ( "fmt" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" ) func TestUnmarshalJSONNewFilterArgs(t *testing.T) { diff --git a/eth/filters/bench_test.go b/eth/filters/bench_test.go index 73b7255540..b25775b42d 100644 --- a/eth/filters/bench_test.go +++ b/eth/filters/bench_test.go @@ -32,12 +32,12 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/bitutil" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/core/bloombits" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/bitutil" - "github.com/ethereum/go-ethereum/ethdb" ) func BenchmarkBloomBits512(b *testing.B) { diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 4edcebc79b..d84bbfe333 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -32,10 +32,10 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/bloombits" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" ) // Filter can be used to retrieve and filter logs. diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index c388632391..941e056129 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -34,16 +34,16 @@ import ( "sync" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/bloombits" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/interfaces" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" ) // Config represents the configuration of the filter system. diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index fa4c3cb355..70028206d5 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -37,6 +37,9 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/event" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/bloombits" @@ -46,9 +49,6 @@ import ( "github.com/ava-labs/subnet-evm/internal/ethapi" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" "github.com/stretchr/testify/require" ) diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 5c373f895d..76ed3e1941 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -34,6 +34,10 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core" @@ -41,10 +45,6 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index 4a6eae3710..23c492391c 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -33,14 +33,14 @@ import ( "math" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/log" ) // Options are the contextual parameters to execute the requested call. diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index c85e53308d..7c70ae9b6b 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -33,10 +33,10 @@ import ( "math/big" "slices" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" ) var ( diff --git a/eth/gasprice/feehistory_test.go b/eth/gasprice/feehistory_test.go index 7ff971e2ed..34da967adb 100644 --- a/eth/gasprice/feehistory_test.go +++ b/eth/gasprice/feehistory_test.go @@ -36,9 +36,9 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/stretchr/testify/require" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" ) func TestFeeHistory(t *testing.T) { diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 2967a5a55d..d880c1ccc3 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -33,6 +33,11 @@ import ( "sync" "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/lru" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core" @@ -40,11 +45,6 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/contracts/feemanager" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/lru" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" "golang.org/x/exp/slices" ) diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 526877256c..a9a2b21119 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -32,6 +32,10 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/event" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core" @@ -41,10 +45,6 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contracts/feemanager" "github.com/ava-labs/subnet-evm/rpc" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/event" "github.com/stretchr/testify/require" ) diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 397007a2cb..cd9a661a08 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -32,16 +32,16 @@ import ( "fmt" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/eth/tracers" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/log" ) // noopReleaser is returned in case there is no operation expected diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 30ed864244..e37cc2787b 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -37,6 +37,13 @@ import ( "sync" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/eth/tracers/logger" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/state" @@ -44,13 +51,6 @@ import ( "github.com/ava-labs/subnet-evm/internal/ethapi" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/logger" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) const ( diff --git a/eth/tracers/api_extra_test.go b/eth/tracers/api_extra_test.go index 84434eed52..bbeaafd015 100644 --- a/eth/tracers/api_extra_test.go +++ b/eth/tracers/api_extra_test.go @@ -12,16 +12,16 @@ import ( "sync/atomic" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/eth/tracers/logger" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/internal/ethapi" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/stretchr/testify/require" ) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index e81bd74444..75babfc3ed 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -37,6 +37,12 @@ import ( "sync/atomic" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/eth/tracers/logger" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core" @@ -46,12 +52,6 @@ import ( "github.com/ava-labs/subnet-evm/internal/ethapi" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/logger" - "github.com/ethereum/go-ethereum/ethdb" "golang.org/x/exp/slices" ) diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index 552ee7ac53..e235b4c5e6 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -21,20 +21,20 @@ import ( "errors" "fmt" - "github.com/ethereum/go-ethereum/core/vm" - gethtracers "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ava-labs/libevm/core/vm" + ethtracers "github.com/ava-labs/libevm/eth/tracers" ) // Context contains some contextual infos for a transaction execution that is not // available from within the EVM object. -type Context = gethtracers.Context +type Context = ethtracers.Context // Tracer interface extends vm.EVMLogger and additionally // allows collecting the tracing result. -type Tracer = gethtracers.Tracer +type Tracer = ethtracers.Tracer // DefaultDirectory is the collection of tracers bundled by default. -var DefaultDirectory = gethtracers.DefaultDirectory +var DefaultDirectory = ethtracers.DefaultDirectory const ( memoryPadLimit = 1024 * 1024 diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index e91ae3a2bb..b8dffad3b9 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -30,15 +30,15 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/eth/tracers/logger" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/tests" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/logger" ) func BenchmarkTransactionTrace(b *testing.B) { diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 87d608f030..a87c10df8e 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -34,14 +34,13 @@ import ( "fmt" "math/big" - "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/interfaces" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" // Force-load precompiles to trigger registration _ "github.com/ava-labs/subnet-evm/precompile/registry" @@ -92,7 +91,6 @@ type Client interface { SubscribeNewHead(context.Context, chan<- *types.Header) (interfaces.Subscription, error) NetworkID(context.Context) (*big.Int, error) BalanceAt(context.Context, common.Address, *big.Int) (*big.Int, error) - AssetBalanceAt(context.Context, common.Address, ids.ID, *big.Int) (*big.Int, error) BalanceAtHash(ctx context.Context, account common.Address, blockHash common.Hash) (*big.Int, error) StorageAt(context.Context, common.Address, common.Hash, *big.Int) ([]byte, error) StorageAtHash(ctx context.Context, account common.Address, key common.Hash, blockHash common.Hash) ([]byte, error) @@ -479,14 +477,6 @@ func (ec *client) BalanceAt(ctx context.Context, account common.Address, blockNu return (*big.Int)(&result), err } -// AssetBalanceAt returns the [assetID] balance of the given account -// The block number can be nil, in which case the balance is taken from the latest known block. -func (ec *client) AssetBalanceAt(ctx context.Context, account common.Address, assetID ids.ID, blockNumber *big.Int) (*big.Int, error) { - var result hexutil.Big - err := ec.c.CallContext(ctx, &result, "eth_getAssetBalance", account, ToBlockNumArg(blockNumber), assetID) - return (*big.Int)(&result), err -} - // BalanceAtHash returns the wei balance of the given account. func (ec *client) BalanceAtHash(ctx context.Context, account common.Address, blockHash common.Hash) (*big.Int, error) { var result hexutil.Big diff --git a/ethclient/signer.go b/ethclient/signer.go index 919aff1158..2b5b400348 100644 --- a/ethclient/signer.go +++ b/ethclient/signer.go @@ -30,8 +30,8 @@ import ( "errors" "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" ) // senderFromServer is a types.Signer that remembers the sender address returned by the RPC diff --git a/ethclient/simulated/backend.go b/ethclient/simulated/backend.go index 3e563f0402..6b167e5c8c 100644 --- a/ethclient/simulated/backend.go +++ b/ethclient/simulated/backend.go @@ -22,6 +22,7 @@ import ( "time" "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/constants" "github.com/ava-labs/subnet-evm/core" @@ -34,7 +35,6 @@ import ( "github.com/ava-labs/subnet-evm/node" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" ) var _ eth.PushGossiper = (*fakePushGossiper)(nil) diff --git a/ethclient/simulated/backend_test.go b/ethclient/simulated/backend_test.go index 080bbb6960..2b5b552ee9 100644 --- a/ethclient/simulated/backend_test.go +++ b/ethclient/simulated/backend_test.go @@ -24,12 +24,12 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) diff --git a/ethclient/subnetevmclient/subnet_evm_client.go b/ethclient/subnetevmclient/subnet_evm_client.go index d5794c8164..de2189aae0 100644 --- a/ethclient/subnetevmclient/subnet_evm_client.go +++ b/ethclient/subnetevmclient/subnet_evm_client.go @@ -33,12 +33,12 @@ import ( "runtime" "runtime/debug" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/interfaces" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" ) // Client is a wrapper around rpc.Client that implements geth-specific functionality. diff --git a/examples/sign-uptime-message/main.go b/examples/sign-uptime-message/main.go new file mode 100644 index 0000000000..94929bc2da --- /dev/null +++ b/examples/sign-uptime-message/main.go @@ -0,0 +1,124 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package main + +import ( + "context" + "log" + "net/netip" + "time" + + "github.com/prometheus/client_golang/prometheus" + "google.golang.org/protobuf/proto" + + "github.com/ava-labs/avalanchego/api/info" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/network/p2p" + "github.com/ava-labs/avalanchego/network/peer" + "github.com/ava-labs/avalanchego/proto/pb/sdk" + "github.com/ava-labs/avalanchego/snow/networking/router" + "github.com/ava-labs/avalanchego/utils/compression" + "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/avalanchego/wallet/subnet/primary" + "github.com/ava-labs/subnet-evm/warp/messages" + + p2pmessage "github.com/ava-labs/avalanchego/message" +) + +// An example application demonstrating how to request a signature for +// an uptime message from a node running locally. +func main() { + uri := primary.LocalAPIURI + // The following IDs are placeholders and should be replaced with real values + // before running the code. + // The validationID is for the validation period that the uptime message is signed for. + validationID := ids.FromStringOrPanic("p3NUAY4PbcAnyCyvUTjGVjezNEQCdnVdfAbJcZScvKpxP5tJr") + // The sourceChainID is the ID of the chain. + sourceChainID := ids.FromStringOrPanic("2UZWB4xjNadRcHSpXarQoCryiVdcGWoT5w1dUztNfMKkAd2hJX") + reqUptime := uint64(3486) + infoClient := info.NewClient(uri) + networkID, err := infoClient.GetNetworkID(context.Background()) + if err != nil { + log.Fatalf("failed to fetch network ID: %s\n", err) + } + + validatorUptime, err := messages.NewValidatorUptime(validationID, reqUptime) + if err != nil { + log.Fatalf("failed to create validatorUptime message: %s\n", err) + } + + addressedCall, err := payload.NewAddressedCall( + nil, + validatorUptime.Bytes(), + ) + if err != nil { + log.Fatalf("failed to create AddressedCall message: %s\n", err) + } + + unsignedWarp, err := warp.NewUnsignedMessage( + networkID, + sourceChainID, + addressedCall.Bytes(), + ) + if err != nil { + log.Fatalf("failed to create unsigned Warp message: %s\n", err) + } + + p, err := peer.StartTestPeer( + context.Background(), + netip.AddrPortFrom( + netip.AddrFrom4([4]byte{127, 0, 0, 1}), + 9651, + ), + networkID, + router.InboundHandlerFunc(func(_ context.Context, msg p2pmessage.InboundMessage) { + log.Printf("received %s: %s", msg.Op(), msg.Message()) + }), + ) + if err != nil { + log.Fatalf("failed to start peer: %s\n", err) + } + + messageBuilder, err := p2pmessage.NewCreator( + logging.NoLog{}, + prometheus.NewRegistry(), + compression.TypeZstd, + time.Hour, + ) + if err != nil { + log.Fatalf("failed to create message builder: %s\n", err) + } + + appRequestPayload, err := proto.Marshal(&sdk.SignatureRequest{ + Message: unsignedWarp.Bytes(), + }) + if err != nil { + log.Fatalf("failed to marshal SignatureRequest: %s\n", err) + } + + appRequest, err := messageBuilder.AppRequest( + sourceChainID, + 0, + time.Hour, + p2p.PrefixMessage( + p2p.ProtocolPrefix(p2p.SignatureRequestHandlerID), + appRequestPayload, + ), + ) + if err != nil { + log.Fatalf("failed to create AppRequest: %s\n", err) + } + + p.Send(context.Background(), appRequest) + + time.Sleep(5 * time.Second) + + p.StartClose() + err = p.AwaitClosed(context.Background()) + if err != nil { + log.Fatalf("failed to close peer: %s\n", err) + } +} diff --git a/go.mod b/go.mod index 8277e37c64..84398572a3 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,11 @@ go 1.22.8 require ( github.com/VictoriaMetrics/fastcache v1.12.1 github.com/antithesishq/antithesis-sdk-go v0.3.8 - github.com/ava-labs/avalanchego v1.11.13-0.20241026214739-acb3d7d102a0 + github.com/ava-labs/avalanchego v1.12.1-0.20250109213120-2fb6d3f63236 + github.com/ava-labs/libevm v1.13.14-0.1.0.rc-2 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 - github.com/ethereum/go-ethereum v1.13.14 - github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 github.com/go-cmd/cmd v1.4.1 github.com/gorilla/rpc v1.2.0 github.com/gorilla/websocket v1.5.0 @@ -33,11 +32,13 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.25.7 go.uber.org/goleak v1.3.0 - go.uber.org/mock v0.4.0 - golang.org/x/crypto v0.26.0 + go.uber.org/mock v0.5.0 + go.uber.org/zap v1.26.0 + golang.org/x/crypto v0.31.0 golang.org/x/exp v0.0.0-20231127185646-65229373498e - golang.org/x/sync v0.8.0 - golang.org/x/sys v0.24.0 + golang.org/x/mod v0.18.0 + golang.org/x/sync v0.10.0 + golang.org/x/sys v0.28.0 golang.org/x/time v0.3.0 google.golang.org/protobuf v1.34.2 gopkg.in/natefinch/lumberjack.v2 v2.0.0 @@ -47,7 +48,7 @@ require ( github.com/DataDog/zstd v1.5.2 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect - github.com/ava-labs/coreth v0.13.8 // indirect + github.com/ava-labs/coreth v0.13.9-0.20250109212847-a0898a97c321 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect @@ -70,13 +71,18 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect + github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gofrs/flock v0.8.1 // indirect @@ -84,6 +90,8 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/google/renameio/v2 v2.0.0 // indirect github.com/google/uuid v1.6.0 // indirect @@ -92,19 +100,26 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huin/goupnp v1.3.0 // indirect - github.com/jackpal/gateway v1.0.6 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.15.15 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.6 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mr-tron/base58 v1.2.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect @@ -123,7 +138,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect github.com/subosito/gotenv v1.3.0 // indirect - github.com/supranational/blst v0.3.11 // indirect + github.com/supranational/blst v0.3.13 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect @@ -138,22 +153,27 @@ require ( go.opentelemetry.io/otel/trace v1.22.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.26.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/tools v0.22.0 // indirect gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect google.golang.org/grpc v1.66.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.29.0 // indirect + k8s.io/apimachinery v0.29.0 // indirect + k8s.io/client-go v0.29.0 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect rsc.io/tmplfunc v0.0.3 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) - -replace github.com/ethereum/go-ethereum => github.com/ava-labs/go-ethereum v0.0.0-20241007222654-0752a11d4aee - -// replace github.com/ethereum/go-ethereum => ../../git2/go-ethereum diff --git a/go.sum b/go.sum index c721c10bcf..12fce58e4f 100644 --- a/go.sum +++ b/go.sum @@ -60,12 +60,14 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax github.com/antithesishq/antithesis-sdk-go v0.3.8 h1:OvGoHxIcOXFJLyn9IJQ5DzByZ3YVAWNBc394ObzDRb8= github.com/antithesishq/antithesis-sdk-go v0.3.8/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ava-labs/avalanchego v1.11.13-0.20241026214739-acb3d7d102a0 h1:1T9OnvZP6XZ62EVWlfmrI8rrudyE6bM2Zt51pCHfS5o= -github.com/ava-labs/avalanchego v1.11.13-0.20241026214739-acb3d7d102a0/go.mod h1:gYlTU42Q4b29hzhUN22yclym5qwB3Si0jh4+LTn7DZM= -github.com/ava-labs/coreth v0.13.8 h1:f14X3KgwHl9LwzfxlN6S4bbn5VA2rhEsNnHaRLSTo/8= -github.com/ava-labs/coreth v0.13.8/go.mod h1:t3BSv/eQv0AlDPMfEDCMMoD/jq1RkUsbFzQAFg5qBcE= -github.com/ava-labs/go-ethereum v0.0.0-20241007222654-0752a11d4aee h1:MRxEz28vnWuOVsmOhAkr0mH26v1nvRkdYMKuoknW67g= -github.com/ava-labs/go-ethereum v0.0.0-20241007222654-0752a11d4aee/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU= +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/ava-labs/avalanchego v1.12.1-0.20250109213120-2fb6d3f63236 h1:s2tPHtOjMJLfqC7n4QB4QwbWMUJAiZWImUmMjcDQD+E= +github.com/ava-labs/avalanchego v1.12.1-0.20250109213120-2fb6d3f63236/go.mod h1:yGx8w2ZkxQRpv+I3WszsvtZk1bGSwkrmL3CudLEQNec= +github.com/ava-labs/coreth v0.13.9-0.20250109212847-a0898a97c321 h1:Ou3VYMpQT/9VxRVZpFSpOEq9kN2SdIto9ta1GOdQ+04= +github.com/ava-labs/coreth v0.13.9-0.20250109212847-a0898a97c321/go.mod h1:RHovHXYBauSKgWEg0wlu37kL0vFXDdINGTwbdiQn5EE= +github.com/ava-labs/libevm v1.13.14-0.1.0.rc-2 h1:CVbn0hSsPCl6gCkTCnqwuN4vtJgdVbkCqLXzYAE7qF8= +github.com/ava-labs/libevm v1.13.14-0.1.0.rc-2/go.mod h1:yBctIV/wnxXTF38h95943jvpuk4aj07TrjbpoGor6LQ= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -175,6 +177,8 @@ github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -214,6 +218,7 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -222,6 +227,12 @@ github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AE github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 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/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -280,6 +291,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -290,6 +303,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -328,6 +342,7 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= @@ -363,15 +378,17 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/ github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= -github.com/jackpal/gateway v1.0.6 h1:/MJORKvJEwNVldtGVJC2p2cwCnsSoLn3hl3zxmZT7tk= -github.com/jackpal/gateway v1.0.6/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -408,6 +425,8 @@ github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -441,13 +460,22 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh 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/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= @@ -550,6 +578,7 @@ github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobt github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -559,12 +588,13 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= -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/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= +github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= @@ -630,8 +660,8 @@ go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lI go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -649,8 +679,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -689,8 +719,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -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.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -735,8 +765,8 @@ golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -746,6 +776,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -758,8 +790,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -827,12 +859,12 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -843,8 +875,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +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/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -906,8 +938,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -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= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1026,6 +1058,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -1037,6 +1071,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -1054,8 +1089,26 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= +k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= +k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= +k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= +k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= +k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/interfaces/interfaces.go b/interfaces/interfaces.go index 1bbb369603..aa4efd7c03 100644 --- a/interfaces/interfaces.go +++ b/interfaces/interfaces.go @@ -32,9 +32,9 @@ import ( "errors" "math/big" + ethereum "github.com/ava-labs/libevm" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" ) // NotFound is returned by API methods if the requested item does not exist. diff --git a/internal/blocktest/test_hash.go b/internal/blocktest/test_hash.go index 014e9ff4b0..4dae6f75f7 100644 --- a/internal/blocktest/test_hash.go +++ b/internal/blocktest/test_hash.go @@ -35,7 +35,7 @@ package blocktest import ( "hash" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "golang.org/x/crypto/sha3" ) diff --git a/internal/debug/api.go b/internal/debug/api.go index 6ac4f5110b..044a601f3c 100644 --- a/internal/debug/api.go +++ b/internal/debug/api.go @@ -45,7 +45,7 @@ import ( "sync" "time" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" "github.com/hashicorp/go-bexpr" "golang.org/x/exp/slog" ) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index dfb23fa863..1613b6bc27 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -36,8 +36,8 @@ import ( "path/filepath" "runtime" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/internal/flags" - "github.com/ethereum/go-ethereum/log" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "github.com/urfave/cli/v2" diff --git a/internal/debug/trace.go b/internal/debug/trace.go index 12f7bfdb05..dd9a873595 100644 --- a/internal/debug/trace.go +++ b/internal/debug/trace.go @@ -31,7 +31,7 @@ import ( "os" "runtime/trace" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" ) // StartGoTrace turns on tracing, writing to the given file. diff --git a/internal/ethapi/addrlock.go b/internal/ethapi/addrlock.go index 2d00fdd2e7..2cd32605c1 100644 --- a/internal/ethapi/addrlock.go +++ b/internal/ethapi/addrlock.go @@ -29,7 +29,7 @@ package ethapi import ( "sync" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) type AddrLocker struct { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4f46fc8ae5..8b4a2c1b9f 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -35,6 +35,18 @@ import ( "strings" "time" + "github.com/ava-labs/libevm/accounts" + "github.com/ava-labs/libevm/accounts/keystore" + "github.com/ava-labs/libevm/accounts/scwallet" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/eth/tracers/logger" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/state" @@ -42,19 +54,7 @@ import ( "github.com/ava-labs/subnet-evm/eth/gasestimator" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ava-labs/subnet-evm/trie" "github.com/davecgh/go-spew/spew" - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/accounts/scwallet" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/tracers/logger" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" "github.com/tyler-smith/go-bip39" ) diff --git a/internal/ethapi/api_extra.go b/internal/ethapi/api_extra.go index ca2166f139..fa7f20f066 100644 --- a/internal/ethapi/api_extra.go +++ b/internal/ethapi/api_extra.go @@ -8,14 +8,14 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/rlp" ) func (s *BlockChainAPI) GetChainConfig(ctx context.Context) *params.ChainConfigWithUpgradesJSON { diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 0fb9345424..7f8aa87426 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -42,6 +42,15 @@ import ( "time" "github.com/ava-labs/avalanchego/upgrade" + "github.com/ava-labs/libevm/accounts" + "github.com/ava-labs/libevm/accounts/keystore" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/crypto/kzg4844" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/event" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/dummy" @@ -54,15 +63,6 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/crypto/kzg4844" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" "github.com/holiman/uint256" "github.com/stretchr/testify/require" "golang.org/x/exp/slices" diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index c0233a2271..d9610db098 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -32,6 +32,11 @@ import ( "math/big" "time" + "github.com/ava-labs/libevm/accounts" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/event" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/core" @@ -40,11 +45,6 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" ) // Backend interface provides the common API services (that are provided by diff --git a/internal/ethapi/errors.go b/internal/ethapi/errors.go index 68327efb2c..8418eb9e7f 100644 --- a/internal/ethapi/errors.go +++ b/internal/ethapi/errors.go @@ -29,9 +29,9 @@ package ethapi import ( "fmt" + "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common/hexutil" ) // revertError is an API error that encompasses an EVM revert with JSON error diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index b23de035cb..dc6b5f2026 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -34,16 +34,16 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/crypto/kzg4844" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto/kzg4844" - "github.com/ethereum/go-ethereum/log" "github.com/holiman/uint256" ) @@ -277,7 +277,7 @@ func (args *TransactionArgs) setCancunFeeDefaults(ctx context.Context, head *typ return nil } -// setSubnetEVMFeeDefaults fills in reasonable default fee values for unspecified fields. +// setSubnetEVMFeeDefault fills in reasonable default fee values for unspecified fields. func (args *TransactionArgs) setSubnetEVMFeeDefault(ctx context.Context, head *types.Header, b feeBackend) error { // Set maxPriorityFeePerGas if it is missing. if args.MaxPriorityFeePerGas == nil { diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index c1f95930fb..f966d02340 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -33,10 +33,10 @@ import ( "reflect" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" ) var _ feeBackend = &backendMock{} diff --git a/internal/flags/flags.go b/internal/flags/flags.go index 167a485ab7..4c1c6590fb 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -38,7 +38,7 @@ import ( "strings" "syscall" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ava-labs/libevm/common/math" "github.com/urfave/cli/v2" ) diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index dc54193ec9..74ee63c430 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -33,9 +33,9 @@ import ( "sort" "strings" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/internal/version" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/log" "github.com/mattn/go-isatty" "github.com/urfave/cli/v2" ) diff --git a/internal/shutdowncheck/shutdown_tracker.go b/internal/shutdowncheck/shutdown_tracker.go index 25613ef784..41b8117a30 100644 --- a/internal/shutdowncheck/shutdown_tracker.go +++ b/internal/shutdowncheck/shutdown_tracker.go @@ -29,10 +29,10 @@ package shutdowncheck import ( "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" ) // ShutdownTracker is a service that reports previous unclean shutdowns diff --git a/libevm/options/options.go b/libevm/options/options.go new file mode 100644 index 0000000000..af7bc751a9 --- /dev/null +++ b/libevm/options/options.go @@ -0,0 +1,42 @@ +// Copyright 2024 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 options provides a generic mechanism for defining configuration of +// arbitrary types. +package options + +// An Option configures values of arbitrary type. +type Option[T any] interface { + Configure(*T) +} + +// As applies Options to a zero-value T, which it then returns. +func As[T any](opts ...Option[T]) *T { + var t T + for _, o := range opts { + o.Configure(&t) + } + return &t +} + +// A Func converts a function into an [Option], using itself as the Configure +// method. +type Func[T any] func(*T) + +var _ Option[struct{}] = Func[struct{}](nil) + +// Configure implements the [Option] interface. +func (f Func[T]) Configure(t *T) { f(t) } diff --git a/libevm/sync/sync.go b/libevm/sync/sync.go new file mode 100644 index 0000000000..7621e20d79 --- /dev/null +++ b/libevm/sync/sync.go @@ -0,0 +1,52 @@ +// Copyright 2024 the subnet-evm 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 sync extends the standard library's sync package. +package sync + +import "sync" + +// Aliases of stdlib sync's types to avoid having to import it alongside this +// package. +type ( + Cond = sync.Cond + Locker = sync.Locker + Map = sync.Map + Mutex = sync.Mutex + Once = sync.Once + RWMutex = sync.RWMutex + WaitGroup = sync.WaitGroup +) + +// A Pool is a type-safe wrapper around [sync.Pool]. +type Pool[T any] struct { + New func() T + pool sync.Pool + once Once +} + +// Get is equivalent to [sync.Pool.Get]. +func (p *Pool[T]) Get() T { + p.once.Do(func() { // Do() guarantees at least once, not just only once + p.pool.New = func() any { return p.New() } + }) + return p.pool.Get().(T) //nolint:forcetypeassert +} + +// Put is equivalent to [sync.Pool.Put]. +func (p *Pool[T]) Put(t T) { + p.pool.Put(t) +} diff --git a/metrics/cpu_enabled.go b/metrics/cpu_enabled.go index 7b5fe4d207..34f450e1ab 100644 --- a/metrics/cpu_enabled.go +++ b/metrics/cpu_enabled.go @@ -30,7 +30,7 @@ package metrics import ( - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" "github.com/shirou/gopsutil/cpu" ) diff --git a/metrics/cputime_unix.go b/metrics/cputime_unix.go index 5a479d8aa8..c02303bdce 100644 --- a/metrics/cputime_unix.go +++ b/metrics/cputime_unix.go @@ -32,7 +32,7 @@ package metrics import ( syscall "golang.org/x/sys/unix" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" ) // getProcessCPUTime retrieves the process' CPU time since program startup. diff --git a/miner/miner.go b/miner/miner.go index a325bff0d2..7fddd69b2f 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -29,14 +29,14 @@ package miner import ( "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/event" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/txpool" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/event" ) // Backend wraps all methods required for mining. diff --git a/miner/ordering.go b/miner/ordering.go index 40bc68d032..150bef5a0b 100644 --- a/miner/ordering.go +++ b/miner/ordering.go @@ -30,9 +30,9 @@ import ( "container/heap" "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/txpool" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" ) diff --git a/miner/ordering_test.go b/miner/ordering_test.go index 2773affe22..61b88c8847 100644 --- a/miner/ordering_test.go +++ b/miner/ordering_test.go @@ -33,10 +33,10 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/core/txpool" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/holiman/uint256" ) diff --git a/miner/worker.go b/miner/worker.go index 93bc900f98..178dd3f9b7 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -38,6 +38,10 @@ import ( "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/event" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" @@ -48,10 +52,6 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/predicate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" "github.com/holiman/uint256" ) @@ -281,14 +281,15 @@ func (w *worker) commitNewWork(predicateContext *precompileconfig.PredicateConte } func (w *worker) createCurrentEnvironment(predicateContext *precompileconfig.PredicateContext, parent *types.Header, header *types.Header, tstart time.Time) (*environment, error) { - state, err := w.chain.StateAt(parent.Root) + currentState, err := w.chain.StateAt(parent.Root) if err != nil { return nil, err } - state.StartPrefetcher("miner", w.eth.BlockChain().CacheConfig().TriePrefetcherParallelism) + numPrefetchers := w.chain.CacheConfig().TriePrefetcherParallelism + currentState.StartPrefetcher("miner", state.WithConcurrentWorkers(numPrefetchers)) return &environment{ signer: types.MakeSigner(w.chainConfig, header.Number, header.Time), - state: state, + state: currentState, parent: parent, header: header, tcount: 0, @@ -435,7 +436,7 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac continue } // Abort transaction if it won't fit in the block and continue to search for a smaller - // transction that will fit. + // transaction that will fit. if totalTxsSize := env.size + tx.Size(); totalTxsSize > targetTxsSize { log.Trace("Skipping transaction that would exceed target size", "hash", tx.Hash(), "totalTxsSize", totalTxsSize, "txSize", tx.Size()) txs.Pop() diff --git a/node/api.go b/node/api.go index 10fb8e00e4..0d1e6d2547 100644 --- a/node/api.go +++ b/node/api.go @@ -27,10 +27,10 @@ package node import ( + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/internal/debug" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/crypto" ) // apis returns the collection of built-in RPC APIs. diff --git a/node/config.go b/node/config.go index 2640823f0b..f284f67813 100644 --- a/node/config.go +++ b/node/config.go @@ -31,10 +31,10 @@ import ( "os" "path/filepath" - "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/external" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/accounts" + "github.com/ava-labs/libevm/accounts/external" + "github.com/ava-labs/libevm/accounts/keystore" + "github.com/ava-labs/libevm/log" ) // Config represents a small collection of configuration values to fine tune the diff --git a/node/node.go b/node/node.go index 8ff82ae115..44a305bed8 100644 --- a/node/node.go +++ b/node/node.go @@ -27,8 +27,8 @@ package node import ( + "github.com/ava-labs/libevm/accounts" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/accounts" ) // Node is a container on which services can be registered. diff --git a/params/config.go b/params/config.go index dc1942ad9e..d53305618c 100644 --- a/params/config.go +++ b/params/config.go @@ -31,8 +31,8 @@ import ( "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/avalanchego/utils/constants" + ethparams "github.com/ava-labs/libevm/params" "github.com/ava-labs/subnet-evm/utils" - gethparams "github.com/ethereum/go-ethereum/params" ) // Guarantees extras initialisation before a call to [ChainConfig.Rules]. @@ -216,11 +216,11 @@ var ( // ChainConfig is stored in the database on a per block basis. This means // that any network, identified by its genesis block, can have its own // set of configuration options. -type ChainConfig = gethparams.ChainConfig +type ChainConfig = ethparams.ChainConfig // Rules wraps ChainConfig and is merely syntactic sugar or can be used for functions // that do not have or require information about the block. // // Rules is a one time interface meaning that it shouldn't be used in between transition // phases. -type Rules = gethparams.Rules +type Rules = ethparams.Rules diff --git a/params/config_extra.go b/params/config_extra.go index 807f592ef4..db9cf013e3 100644 --- a/params/config_extra.go +++ b/params/config_extra.go @@ -10,11 +10,11 @@ import ( "math/big" "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/libevm/common" + ethparams "github.com/ava-labs/libevm/params" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/predicate" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - gethparams "github.com/ethereum/go-ethereum/params" ) const ( @@ -265,7 +265,7 @@ func configTimestampEqual(x, y *uint64) bool { // ConfigCompatError is raised if the locally-stored blockchain is initialised with a // ChainConfig that would alter the past. -type ConfigCompatError = gethparams.ConfigCompatError +type ConfigCompatError = ethparams.ConfigCompatError func newTimestampCompatError(what string, storedtime, newtime *uint64) *ConfigCompatError { var rew *uint64 diff --git a/params/config_libevm.go b/params/config_libevm.go index 252da54aed..85691d4d72 100644 --- a/params/config_libevm.go +++ b/params/config_libevm.go @@ -6,28 +6,28 @@ package params import ( "math/big" + "github.com/ava-labs/libevm/common" + ethparams "github.com/ava-labs/libevm/params" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" - gethparams "github.com/ethereum/go-ethereum/params" ) // libevmInit would ideally be a regular init() function, but it MUST be run // before any calls to [ChainConfig.Rules]. See `config.go` for its call site. func libevmInit() any { - extras = gethparams.RegisterExtras(gethparams.Extras[*ChainConfigExtra, RulesExtra]{ + extras = ethparams.RegisterExtras(ethparams.Extras[*ChainConfigExtra, RulesExtra]{ ReuseJSONRoot: true, // Reuse the root JSON input when unmarshalling the extra payload. NewRules: constructRulesExtra, }) return nil } -var extras gethparams.ExtraPayloads[*ChainConfigExtra, RulesExtra] +var extras ethparams.ExtraPayloads[*ChainConfigExtra, RulesExtra] // constructRulesExtra acts as an adjunct to the [params.ChainConfig.Rules] // method. Its primary purpose is to construct the extra payload for the // [params.Rules] but it MAY also modify the [params.Rules]. -func constructRulesExtra(c *gethparams.ChainConfig, r *gethparams.Rules, cEx *ChainConfigExtra, blockNum *big.Int, isMerge bool, timestamp uint64) RulesExtra { +func constructRulesExtra(c *ethparams.ChainConfig, r *ethparams.Rules, cEx *ChainConfigExtra, blockNum *big.Int, isMerge bool, timestamp uint64) RulesExtra { var rules RulesExtra if cEx == nil { return rules diff --git a/params/config_test.go b/params/config_test.go index 53bc0e5764..4a7eb027c1 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -34,11 +34,11 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contracts/nativeminter" "github.com/ava-labs/subnet-evm/precompile/contracts/rewardmanager" "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) diff --git a/params/hooks_libevm.go b/params/hooks_libevm.go index 40d75c8778..f56241037c 100644 --- a/params/hooks_libevm.go +++ b/params/hooks_libevm.go @@ -8,25 +8,18 @@ import ( "math/big" "github.com/ava-labs/avalanchego/snow" - "github.com/ava-labs/subnet-evm/constants" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/libevm" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/contracts/deployerallowlist" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/predicate" - "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/libevm" "github.com/holiman/uint256" ) func (r RulesExtra) CanCreateContract(ac *libevm.AddressContext, gas uint64, state libevm.StateReader) (uint64, error) { - // IsProhibited - if ac.Self == constants.BlackholeAddr || modules.ReservedAddress(ac.Self) { - return gas, vmerrs.ErrAddrProhibited - } - // If the allow list is enabled, check that [ac.Origin] has permission to deploy a contract. if r.IsPrecompileEnabled(deployerallowlist.ContractAddress) { allowListRole := deployerallowlist.GetContractDeployerAllowListStatus(state, ac.Origin) diff --git a/params/precompile_config_test.go b/params/precompile_config_test.go index 8e4dc2f886..6be37b59fe 100644 --- a/params/precompile_config_test.go +++ b/params/precompile_config_test.go @@ -8,6 +8,7 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile/contracts/deployerallowlist" "github.com/ava-labs/subnet-evm/precompile/contracts/feemanager" @@ -15,7 +16,6 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contracts/rewardmanager" "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) diff --git a/params/precompile_upgrade.go b/params/precompile_upgrade.go index 6dc864798a..fd8b4ef410 100644 --- a/params/precompile_upgrade.go +++ b/params/precompile_upgrade.go @@ -8,10 +8,10 @@ import ( "errors" "fmt" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" ) var errNoKey = errors.New("PrecompileUpgrade cannot be empty") diff --git a/params/precompile_upgrade_test.go b/params/precompile_upgrade_test.go index c0fd87afb8..405304a1d6 100644 --- a/params/precompile_upgrade_test.go +++ b/params/precompile_upgrade_test.go @@ -6,10 +6,10 @@ package params import ( "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contracts/deployerallowlist" "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) diff --git a/params/protocol_params.go b/params/protocol_params.go index 0f85e6cd2f..89f8e033b1 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -29,7 +29,7 @@ package params import ( "math/big" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) const ( diff --git a/params/rules_extra.go b/params/rules_extra.go index 1bf729e9fc..8e11064c51 100644 --- a/params/rules_extra.go +++ b/params/rules_extra.go @@ -4,8 +4,8 @@ package params import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" ) func GetRulesExtra(r Rules) *RulesExtra { diff --git a/params/state_upgrade.go b/params/state_upgrade.go index b72a8da58b..03bb58ce6b 100644 --- a/params/state_upgrade.go +++ b/params/state_upgrade.go @@ -7,9 +7,9 @@ import ( "fmt" "reflect" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" ) // StateUpgrade describes the modifications to be made to the state during diff --git a/params/state_upgrade_test.go b/params/state_upgrade_test.go index ebb019faaa..ed812f9f4c 100644 --- a/params/state_upgrade_test.go +++ b/params/state_upgrade_test.go @@ -8,9 +8,9 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/stretchr/testify/require" ) diff --git a/peer/network.go b/peer/network.go index 7494db4656..7b806fffbe 100644 --- a/peer/network.go +++ b/peer/network.go @@ -12,7 +12,7 @@ import ( "golang.org/x/sync/semaphore" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" diff --git a/peer/peer_tracker.go b/peer/peer_tracker.go index b1a436c067..38e2b830a7 100644 --- a/peer/peer_tracker.go +++ b/peer/peer_tracker.go @@ -13,7 +13,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/version" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/metrics" ) diff --git a/plugin/evm/admin.go b/plugin/evm/admin.go index fd8d7f8d6e..746b6d8250 100644 --- a/plugin/evm/admin.go +++ b/plugin/evm/admin.go @@ -9,7 +9,7 @@ import ( "github.com/ava-labs/avalanchego/api" "github.com/ava-labs/avalanchego/utils/profiler" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" ) // Admin is the API service for admin API calls diff --git a/plugin/evm/api.go b/plugin/evm/api.go new file mode 100644 index 0000000000..01426d3432 --- /dev/null +++ b/plugin/evm/api.go @@ -0,0 +1,38 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "context" + "math/big" + + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" +) + +// SnowmanAPI introduces snowman specific functionality to the evm +type SnowmanAPI struct{ vm *VM } + +// GetAcceptedFrontReply defines the reply that will be sent from the +// GetAcceptedFront API call +type GetAcceptedFrontReply struct { + Hash common.Hash `json:"hash"` + Number *big.Int `json:"number"` +} + +// GetAcceptedFront returns the last accepted block's hash and height +func (api *SnowmanAPI) GetAcceptedFront(ctx context.Context) (*GetAcceptedFrontReply, error) { + blk := api.vm.blockChain.LastConsensusAcceptedBlock() + return &GetAcceptedFrontReply{ + Hash: blk.Hash(), + Number: blk.Number(), + }, nil +} + +// IssueBlock to the chain +func (api *SnowmanAPI) IssueBlock(ctx context.Context) error { + log.Info("Issuing a new block") + api.vm.builder.signalTxsReady() + return nil +} diff --git a/plugin/evm/block.go b/plugin/evm/block.go index 05b9746ed6..eae6c66ef9 100644 --- a/plugin/evm/block.go +++ b/plugin/evm/block.go @@ -10,8 +10,8 @@ import ( "fmt" "time" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/rawdb" @@ -55,18 +55,15 @@ func (b *Block) Accept(context.Context) error { // Although returning an error from Accept is considered fatal, it is good // practice to cleanup the batch we were modifying in the case of an error. - defer vm.db.Abort() + defer vm.versiondb.Abort() log.Debug(fmt.Sprintf("Accepting block %s (%s) at height %d", b.ID().Hex(), b.ID(), b.Height())) // Call Accept for relevant precompile logs. Note we do this prior to // calling Accept on the blockChain so any side effects (eg warp signatures) - // take place before the accepted log is emitted to subscribers. Use of the - // sharedMemoryWriter ensures shared memory requests generated by - // precompiles are committed atomically with the vm's lastAcceptedKey. + // take place before the accepted log is emitted to subscribers. rules := b.vm.chainConfig.Rules(b.ethBlock.Number(), params.IsMergeTODO, b.ethBlock.Timestamp()) - sharedMemoryWriter := NewSharedMemoryWriter() - if err := b.handlePrecompileAccept(*params.GetRulesExtra(rules), sharedMemoryWriter); err != nil { + if err := b.handlePrecompileAccept(*params.GetRulesExtra(rules)); err != nil { return err } if err := vm.blockChain.Accept(b.ethBlock); err != nil { @@ -77,24 +74,12 @@ func (b *Block) Accept(context.Context) error { return fmt.Errorf("failed to put %s as the last accepted block: %w", b.ID(), err) } - // Get pending operations on the vm's versionDB so we can apply them atomically - // with the shared memory requests. - vdbBatch, err := b.vm.db.CommitBatch() - if err != nil { - return fmt.Errorf("could not create commit batch processing block[%s]: %w", b.ID(), err) - } - - // Apply any shared memory requests that accumulated from processing the logs - // of the accepted block (generated by precompiles) atomically with other pending - // changes to the vm's versionDB. - return vm.ctx.SharedMemory.Apply(sharedMemoryWriter.requests, vdbBatch) + return b.vm.versiondb.Commit() } // handlePrecompileAccept calls Accept on any logs generated with an active precompile address that implements // contract.Accepter -// This function assumes that the Accept function will ONLY operate on state maintained in the VM's versiondb. -// This ensures that any DB operations are performed atomically with marking the block as accepted. -func (b *Block) handlePrecompileAccept(rules params.RulesExtra, sharedMemoryWriter *sharedMemoryWriter) error { +func (b *Block) handlePrecompileAccept(rules params.RulesExtra) error { // Short circuit early if there are no precompile accepters to execute if len(rules.AccepterPrecompiles) == 0 { return nil @@ -108,9 +93,8 @@ func (b *Block) handlePrecompileAccept(rules params.RulesExtra, sharedMemoryWrit return fmt.Errorf("failed to fetch receipts for accepted block with non-empty root hash (%s) (Block: %s, Height: %d)", b.ethBlock.ReceiptHash(), b.ethBlock.Hash(), b.ethBlock.NumberU64()) } acceptCtx := &precompileconfig.AcceptContext{ - SnowCtx: b.vm.ctx, - SharedMemory: sharedMemoryWriter, - Warp: b.vm.warpBackend, + SnowCtx: b.vm.ctx, + Warp: b.vm.warpBackend, } for _, receipt := range receipts { for logIdx, log := range receipt.Logs { @@ -216,7 +200,7 @@ func (b *Block) verify(predicateContext *precompileconfig.PredicateContext, writ // If the chain is still bootstrapping, we can assume that all blocks we are verifying have // been accepted by the network (so the predicate was validated by the network when the // block was originally verified). - if b.vm.bootstrapped { + if b.vm.bootstrapped.Get() { if err := b.verifyPredicates(predicateContext); err != nil { return fmt.Errorf("failed to verify predicates: %w", err) } diff --git a/plugin/evm/block_builder.go b/plugin/evm/block_builder.go index cdd5e63889..49b8dfd2f2 100644 --- a/plugin/evm/block_builder.go +++ b/plugin/evm/block_builder.go @@ -15,7 +15,7 @@ import ( "github.com/ava-labs/avalanchego/snow" commonEng "github.com/ava-labs/avalanchego/snow/engine/common" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" ) const ( diff --git a/plugin/evm/block_test.go b/plugin/evm/block_test.go index ba6bf4e779..0b582548c2 100644 --- a/plugin/evm/block_test.go +++ b/plugin/evm/block_test.go @@ -7,12 +7,12 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" ) @@ -93,5 +93,5 @@ func TestHandlePrecompileAccept(t *testing.T) { precompileAddr: mockAccepter, }, } - require.NoError(blk.handlePrecompileAccept(rules, nil)) + require.NoError(blk.handlePrecompileAccept(rules)) } diff --git a/plugin/evm/block_verification.go b/plugin/evm/block_verification.go index b97ebac64c..195e63e8ef 100644 --- a/plugin/evm/block_verification.go +++ b/plugin/evm/block_verification.go @@ -8,11 +8,11 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/trie" ) var legacyMinGasPrice = big.NewInt(params.MinGasPrice) diff --git a/plugin/evm/client.go b/plugin/evm/client.go index b91618fc4c..36a0ee675f 100644 --- a/plugin/evm/client.go +++ b/plugin/evm/client.go @@ -10,6 +10,7 @@ import ( "golang.org/x/exp/slog" "github.com/ava-labs/avalanchego/api" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/rpc" ) @@ -24,26 +25,28 @@ type Client interface { LockProfile(ctx context.Context, options ...rpc.Option) error SetLogLevel(ctx context.Context, level slog.Level, options ...rpc.Option) error GetVMConfig(ctx context.Context, options ...rpc.Option) (*Config, error) + GetCurrentValidators(ctx context.Context, nodeIDs []ids.NodeID, options ...rpc.Option) ([]CurrentValidator, error) } // Client implementation for interacting with EVM [chain] type client struct { - adminRequester rpc.EndpointRequester + adminRequester rpc.EndpointRequester + validatorsRequester rpc.EndpointRequester } // NewClient returns a Client for interacting with EVM [chain] func NewClient(uri, chain string) Client { + requestUri := fmt.Sprintf("%s/ext/bc/%s", uri, chain) return &client{ - adminRequester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/admin", uri, chain)), + adminRequester: rpc.NewEndpointRequester( + requestUri + "/admin", + ), + validatorsRequester: rpc.NewEndpointRequester( + requestUri + "/validators", + ), } } -// NewCChainClient returns a Client for interacting with the C Chain -func NewCChainClient(uri string) Client { - // TODO: Update for Subnet-EVM compatibility - return NewClient(uri, "C") -} - func (c *client) StartCPUProfiler(ctx context.Context, options ...rpc.Option) error { return c.adminRequester.SendRequest(ctx, "admin.startCPUProfiler", struct{}{}, &api.EmptyReply{}, options...) } @@ -73,3 +76,12 @@ func (c *client) GetVMConfig(ctx context.Context, options ...rpc.Option) (*Confi err := c.adminRequester.SendRequest(ctx, "admin.getVMConfig", struct{}{}, res, options...) return res.Config, err } + +// GetCurrentValidators returns the current validators +func (c *client) GetCurrentValidators(ctx context.Context, nodeIDs []ids.NodeID, options ...rpc.Option) ([]CurrentValidator, error) { + res := &GetCurrentValidatorsResponse{} + err := c.validatorsRequester.SendRequest(ctx, "validators.getCurrentValidators", &GetCurrentValidatorsRequest{ + NodeIDs: nodeIDs, + }, res, options...) + return res.Validators, err +} diff --git a/plugin/evm/config.go b/plugin/evm/config.go index d4a4b44af2..b006a10a83 100644 --- a/plugin/evm/config.go +++ b/plugin/evm/config.go @@ -9,10 +9,10 @@ import ( "time" "github.com/ava-labs/avalanchego/database/pebbledb" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/subnet-evm/core/txpool/legacypool" "github.com/ava-labs/subnet-evm/eth" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/spf13/cast" ) @@ -62,6 +62,7 @@ const ( defaultStateSyncMinBlocks = 300_000 defaultStateSyncRequestSize = 1024 // the number of key/values to ask peers for per request defaultDBType = pebbledb.Name + defaultValidatorAPIEnabled = true ) type PBool bool @@ -91,10 +92,11 @@ type Config struct { AirdropFile string `json:"airdrop"` // Subnet EVM APIs - SnowmanAPIEnabled bool `json:"snowman-api-enabled"` - AdminAPIEnabled bool `json:"admin-api-enabled"` - AdminAPIDir string `json:"admin-api-dir"` - WarpAPIEnabled bool `json:"warp-api-enabled"` + SnowmanAPIEnabled bool `json:"snowman-api-enabled"` + ValidatorsAPIEnabled bool `json:"validators-api-enabled"` + AdminAPIEnabled bool `json:"admin-api-enabled"` + AdminAPIDir string `json:"admin-api-dir"` + WarpAPIEnabled bool `json:"warp-api-enabled"` // EnabledEthAPIs is a list of Ethereum services that should be enabled // If none is specified, then we use the default list [defaultEnabledAPIs] @@ -297,6 +299,7 @@ func (c *Config) SetDefaults() { c.AllowUnprotectedTxHashes = defaultAllowUnprotectedTxHashes c.AcceptedCacheSize = defaultAcceptedCacheSize c.DatabaseType = defaultDBType + c.ValidatorsAPIEnabled = defaultValidatorAPIEnabled } func (d *Duration) UnmarshalJSON(data []byte) (err error) { diff --git a/plugin/evm/config_test.go b/plugin/evm/config_test.go index f5deb297ff..562b472525 100644 --- a/plugin/evm/config_test.go +++ b/plugin/evm/config_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/assert" ) diff --git a/plugin/evm/database/database.go b/plugin/evm/database/database.go new file mode 100644 index 0000000000..41f14a9dc4 --- /dev/null +++ b/plugin/evm/database/database.go @@ -0,0 +1,98 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package database + +import ( + "encoding/json" + "fmt" + "path/filepath" + + "github.com/ava-labs/avalanchego/api/metrics" + avalanchenode "github.com/ava-labs/avalanchego/config/node" + "github.com/ava-labs/avalanchego/database" + "github.com/ava-labs/avalanchego/database/leveldb" + "github.com/ava-labs/avalanchego/database/memdb" + "github.com/ava-labs/avalanchego/database/meterdb" + "github.com/ava-labs/avalanchego/database/pebbledb" + "github.com/ava-labs/avalanchego/database/versiondb" + "github.com/ava-labs/avalanchego/utils/logging" + "github.com/prometheus/client_golang/prometheus" +) + +const ( + dbMetricsPrefix = "db" +) + +// createDatabase returns a new database instance with the provided configuration +func NewStandaloneDatabase(dbConfig avalanchenode.DatabaseConfig, gatherer metrics.MultiGatherer, logger logging.Logger) (database.Database, error) { + dbRegisterer, err := metrics.MakeAndRegister( + gatherer, + dbMetricsPrefix, + ) + if err != nil { + return nil, err + } + var db database.Database + // start the db + switch dbConfig.Name { + case leveldb.Name: + dbPath := filepath.Join(dbConfig.Path, leveldb.Name) + db, err = leveldb.New(dbPath, dbConfig.Config, logger, dbRegisterer) + if err != nil { + return nil, fmt.Errorf("couldn't create %s at %s: %w", leveldb.Name, dbPath, err) + } + case memdb.Name: + db = memdb.New() + case pebbledb.Name: + dbPath := filepath.Join(dbConfig.Path, pebbledb.Name) + db, err = NewPebbleDB(dbPath, dbConfig.Config, logger, dbRegisterer) + if err != nil { + return nil, fmt.Errorf("couldn't create %s at %s: %w", pebbledb.Name, dbPath, err) + } + default: + return nil, fmt.Errorf( + "db-type was %q but should have been one of {%s, %s, %s}", + dbConfig.Name, + leveldb.Name, + memdb.Name, + pebbledb.Name, + ) + } + + if dbConfig.ReadOnly && dbConfig.Name != memdb.Name { + db = versiondb.New(db) + } + + meterDBReg, err := metrics.MakeAndRegister( + gatherer, + "meterdb", + ) + if err != nil { + return nil, err + } + + db, err = meterdb.New(meterDBReg, db) + if err != nil { + return nil, fmt.Errorf("failed to create meterdb: %w", err) + } + + return db, nil +} + +func NewPebbleDB(file string, configBytes []byte, log logging.Logger, dbRegisterer prometheus.Registerer) (database.Database, error) { + cfg := pebbledb.DefaultConfig + // Use no sync for pebble db + cfg.Sync = false + if len(configBytes) > 0 { + if err := json.Unmarshal(configBytes, &cfg); err != nil { + return nil, err + } + } + // Marshal the config back to bytes to ensure that new defaults are applied + newCfgBytes, err := json.Marshal(cfg) + if err != nil { + return nil, err + } + return pebbledb.New(file, newCfgBytes, log, dbRegisterer) +} diff --git a/plugin/evm/database.go b/plugin/evm/database/wrapped_database.go similarity index 53% rename from plugin/evm/database.go rename to plugin/evm/database/wrapped_database.go index 479c995ba3..86e3bbd239 100644 --- a/plugin/evm/database.go +++ b/plugin/evm/database/wrapped_database.go @@ -1,35 +1,39 @@ // (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package evm +package database import ( "errors" "github.com/ava-labs/avalanchego/database" - "github.com/ethereum/go-ethereum/ethdb" + "github.com/ava-labs/libevm/ethdb" ) var ( - _ ethdb.KeyValueStore = &Database{} + _ ethdb.KeyValueStore = ðDbWrapper{} ErrSnapshotNotSupported = errors.New("snapshot is not supported") ) -// Database implements ethdb.Database -type Database struct{ database.Database } +// ethDbWrapper implements ethdb.Database +type ethDbWrapper struct{ database.Database } + +func WrapDatabase(db database.Database) ethdb.KeyValueStore { return ethDbWrapper{db} } // Stat implements ethdb.Database -func (db Database) Stat(string) (string, error) { return "", database.ErrNotFound } +func (db ethDbWrapper) Stat(string) (string, error) { return "", database.ErrNotFound } // NewBatch implements ethdb.Database -func (db Database) NewBatch() ethdb.Batch { return Batch{db.Database.NewBatch()} } +func (db ethDbWrapper) NewBatch() ethdb.Batch { return wrappedBatch{db.Database.NewBatch()} } // NewBatchWithSize implements ethdb.Database // TODO: propagate size through avalanchego Database interface -func (db Database) NewBatchWithSize(size int) ethdb.Batch { return Batch{db.Database.NewBatch()} } +func (db ethDbWrapper) NewBatchWithSize(size int) ethdb.Batch { + return wrappedBatch{db.Database.NewBatch()} +} -func (db Database) NewSnapshot() (ethdb.Snapshot, error) { +func (db ethDbWrapper) NewSnapshot() (ethdb.Snapshot, error) { return nil, ErrSnapshotNotSupported } @@ -37,7 +41,7 @@ func (db Database) NewSnapshot() (ethdb.Snapshot, error) { // // Note: This method assumes that the prefix is NOT part of the start, so there's // no need for the caller to prepend the prefix to the start. -func (db Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator { +func (db ethDbWrapper) NewIterator(prefix []byte, start []byte) ethdb.Iterator { // avalanchego's database implementation assumes that the prefix is part of the // start, so it is added here (if it is provided). if len(prefix) > 0 { @@ -50,15 +54,15 @@ func (db Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator { } // NewIteratorWithStart implements ethdb.Database -func (db Database) NewIteratorWithStart(start []byte) ethdb.Iterator { +func (db ethDbWrapper) NewIteratorWithStart(start []byte) ethdb.Iterator { return db.Database.NewIteratorWithStart(start) } -// Batch implements ethdb.Batch -type Batch struct{ database.Batch } +// wrappedBatch implements ethdb.wrappedBatch +type wrappedBatch struct{ database.Batch } // ValueSize implements ethdb.Batch -func (batch Batch) ValueSize() int { return batch.Batch.Size() } +func (batch wrappedBatch) ValueSize() int { return batch.Batch.Size() } // Replay implements ethdb.Batch -func (batch Batch) Replay(w ethdb.KeyValueWriter) error { return batch.Batch.Replay(w) } +func (batch wrappedBatch) Replay(w ethdb.KeyValueWriter) error { return batch.Batch.Replay(w) } diff --git a/plugin/evm/gossip.go b/plugin/evm/gossip.go index f10c63bb43..b6624f328a 100644 --- a/plugin/evm/gossip.go +++ b/plugin/evm/gossip.go @@ -10,8 +10,8 @@ import ( "sync/atomic" "time" - ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" + ethcommon "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/prometheus/client_golang/prometheus" "github.com/ava-labs/avalanchego/ids" diff --git a/plugin/evm/gossip_test.go b/plugin/evm/gossip_test.go index 620dd62bf1..bc80813f0b 100644 --- a/plugin/evm/gossip_test.go +++ b/plugin/evm/gossip_test.go @@ -10,6 +10,9 @@ import ( "time" "github.com/ava-labs/avalanchego/network/p2p/gossip" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/rawdb" @@ -17,9 +20,6 @@ import ( "github.com/ava-labs/subnet-evm/core/txpool/legacypool" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/plugin/evm/gossiper_eth_gossiping_test.go b/plugin/evm/gossiper_eth_gossiping_test.go index cb8145113d..e3ab49b323 100644 --- a/plugin/evm/gossiper_eth_gossiping_test.go +++ b/plugin/evm/gossiper_eth_gossiping_test.go @@ -18,8 +18,8 @@ import ( commonEng "github.com/ava-labs/avalanchego/snow/engine/common" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/stretchr/testify/assert" diff --git a/plugin/evm/handler.go b/plugin/evm/handler.go index f01db79b04..2cd32b8ba3 100644 --- a/plugin/evm/handler.go +++ b/plugin/evm/handler.go @@ -6,8 +6,8 @@ package evm import ( "github.com/ava-labs/avalanchego/ids" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/txpool" "github.com/ava-labs/subnet-evm/core/types" diff --git a/plugin/evm/log.go b/plugin/evm/log.go index 048367818d..6650b01d5f 100644 --- a/plugin/evm/log.go +++ b/plugin/evm/log.go @@ -10,13 +10,13 @@ import ( "runtime" "strings" + ethlog "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/log" - gethlog "github.com/ethereum/go-ethereum/log" "golang.org/x/exp/slog" ) type SubnetEVMLogger struct { - gethlog.Logger + ethlog.Logger logLevel *slog.LevelVar } @@ -47,14 +47,14 @@ func InitLogger(alias string, level string, jsonFormat bool, writer io.Writer) ( // Create handler c := SubnetEVMLogger{ - Logger: gethlog.NewLogger(handler), + Logger: ethlog.NewLogger(handler), logLevel: logLevel, } if err := c.SetLogLevel(level); err != nil { return SubnetEVMLogger{}, err } - gethlog.SetDefault(c.Logger) + ethlog.SetDefault(c.Logger) return c, nil } diff --git a/plugin/evm/log_test.go b/plugin/evm/log_test.go index eb37e7a9e9..c16a0e99f1 100644 --- a/plugin/evm/log_test.go +++ b/plugin/evm/log_test.go @@ -7,7 +7,7 @@ import ( "os" "testing" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" "github.com/stretchr/testify/require" ) diff --git a/plugin/evm/message/block_request.go b/plugin/evm/message/block_request.go index f1f353f2f7..009e6b0155 100644 --- a/plugin/evm/message/block_request.go +++ b/plugin/evm/message/block_request.go @@ -9,7 +9,7 @@ import ( "github.com/ava-labs/avalanchego/ids" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) var ( diff --git a/plugin/evm/message/block_request_test.go b/plugin/evm/message/block_request_test.go index cd9070117d..7d5b286551 100644 --- a/plugin/evm/message/block_request_test.go +++ b/plugin/evm/message/block_request_test.go @@ -8,7 +8,7 @@ import ( "math/rand" "testing" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/assert" ) diff --git a/plugin/evm/message/code_request.go b/plugin/evm/message/code_request.go index cd1ffef844..d1aeb7f2f6 100644 --- a/plugin/evm/message/code_request.go +++ b/plugin/evm/message/code_request.go @@ -9,7 +9,7 @@ import ( "strings" "github.com/ava-labs/avalanchego/ids" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) var _ Request = CodeRequest{} diff --git a/plugin/evm/message/code_request_test.go b/plugin/evm/message/code_request_test.go index 88cedb54d4..3faf12949d 100644 --- a/plugin/evm/message/code_request_test.go +++ b/plugin/evm/message/code_request_test.go @@ -8,7 +8,7 @@ import ( "math/rand" "testing" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/assert" ) diff --git a/plugin/evm/message/handler.go b/plugin/evm/message/handler.go index d1e83d7883..d8c0c4f7ce 100644 --- a/plugin/evm/message/handler.go +++ b/plugin/evm/message/handler.go @@ -6,7 +6,7 @@ package message import ( "context" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/avalanchego/ids" ) diff --git a/plugin/evm/message/leafs_request.go b/plugin/evm/message/leafs_request.go index 872dea2824..bca3b16275 100644 --- a/plugin/evm/message/leafs_request.go +++ b/plugin/evm/message/leafs_request.go @@ -8,7 +8,7 @@ import ( "fmt" "github.com/ava-labs/avalanchego/ids" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) const MaxCodeHashesPerRequest = 5 diff --git a/plugin/evm/message/leafs_request_test.go b/plugin/evm/message/leafs_request_test.go index 6a698c890c..dccf60a918 100644 --- a/plugin/evm/message/leafs_request_test.go +++ b/plugin/evm/message/leafs_request_test.go @@ -11,7 +11,8 @@ import ( "testing" "github.com/ava-labs/avalanchego/ids" - "github.com/ethereum/go-ethereum/common" + + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/assert" ) diff --git a/plugin/evm/message/syncable.go b/plugin/evm/message/syncable.go index f79a9f2dfa..f05eea3d20 100644 --- a/plugin/evm/message/syncable.go +++ b/plugin/evm/message/syncable.go @@ -8,8 +8,8 @@ import ( "fmt" "github.com/ava-labs/avalanchego/ids" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" ) diff --git a/plugin/evm/network_handler.go b/plugin/evm/network_handler.go index e54d40e676..d0ad2626d5 100644 --- a/plugin/evm/network_handler.go +++ b/plugin/evm/network_handler.go @@ -8,14 +8,14 @@ import ( "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/metrics" "github.com/ava-labs/subnet-evm/plugin/evm/message" syncHandlers "github.com/ava-labs/subnet-evm/sync/handlers" syncStats "github.com/ava-labs/subnet-evm/sync/handlers/stats" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/warp" warpHandlers "github.com/ava-labs/subnet-evm/warp/handlers" - "github.com/ethereum/go-ethereum/ethdb" ) var _ message.RequestHandler = &networkHandler{} diff --git a/plugin/evm/service.go b/plugin/evm/service.go index a8fe61cbc0..0ad10a63b6 100644 --- a/plugin/evm/service.go +++ b/plugin/evm/service.go @@ -4,35 +4,94 @@ package evm import ( - "context" - "math/big" + "fmt" + "net/http" + "time" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/set" ) -// SnowmanAPI introduces snowman specific functionality to the evm -type SnowmanAPI struct{ vm *VM } +type ValidatorsAPI struct { + vm *VM +} + +type GetCurrentValidatorsRequest struct { + NodeIDs []ids.NodeID `json:"nodeIDs"` +} -// GetAcceptedFrontReply defines the reply that will be sent from the -// GetAcceptedFront API call -type GetAcceptedFrontReply struct { - Hash common.Hash `json:"hash"` - Number *big.Int `json:"number"` +type GetCurrentValidatorsResponse struct { + Validators []CurrentValidator `json:"validators"` } -// GetAcceptedFront returns the last accepted block's hash and height -func (api *SnowmanAPI) GetAcceptedFront(ctx context.Context) (*GetAcceptedFrontReply, error) { - blk := api.vm.blockChain.LastConsensusAcceptedBlock() - return &GetAcceptedFrontReply{ - Hash: blk.Hash(), - Number: blk.Number(), - }, nil +type CurrentValidator struct { + ValidationID ids.ID `json:"validationID"` + NodeID ids.NodeID `json:"nodeID"` + Weight uint64 `json:"weight"` + StartTimestamp uint64 `json:"startTimestamp"` + IsActive bool `json:"isActive"` + IsL1Validator bool `json:"isL1Validator"` + IsConnected bool `json:"isConnected"` + UptimePercentage float32 `json:"uptimePercentage"` + UptimeSeconds uint64 `json:"uptimeSeconds"` } -// IssueBlock to the chain -func (api *SnowmanAPI) IssueBlock(ctx context.Context) error { - log.Info("Issuing a new block") - api.vm.builder.signalTxsReady() +func (api *ValidatorsAPI) GetCurrentValidators(_ *http.Request, req *GetCurrentValidatorsRequest, reply *GetCurrentValidatorsResponse) error { + api.vm.ctx.Lock.RLock() + defer api.vm.ctx.Lock.RUnlock() + + var vIDs set.Set[ids.ID] + if len(req.NodeIDs) > 0 { + vIDs = set.NewSet[ids.ID](len(req.NodeIDs)) + for _, nodeID := range req.NodeIDs { + vID, err := api.vm.validatorsManager.GetValidationID(nodeID) + if err != nil { + return fmt.Errorf("couldn't find validator with node ID %s", nodeID) + } + vIDs.Add(vID) + } + } else { + vIDs = api.vm.validatorsManager.GetValidationIDs() + } + + reply.Validators = make([]CurrentValidator, 0, vIDs.Len()) + + for _, vID := range vIDs.List() { + validator, err := api.vm.validatorsManager.GetValidator(vID) + if err != nil { + return fmt.Errorf("couldn't find validator with validation ID %s", vID) + } + + isConnected := api.vm.validatorsManager.IsConnected(validator.NodeID) + + upDuration, lastUpdated, err := api.vm.validatorsManager.CalculateUptime(validator.NodeID) + if err != nil { + return err + } + var uptimeFloat float64 + startTime := time.Unix(int64(validator.StartTimestamp), 0) + bestPossibleUpDuration := lastUpdated.Sub(startTime) + if bestPossibleUpDuration == 0 { + uptimeFloat = 1 + } else { + uptimeFloat = float64(upDuration) / float64(bestPossibleUpDuration) + } + + // Transform this to a percentage (0-100) to make it consistent + // with currentValidators in PlatformVM API + uptimePercentage := float32(uptimeFloat * 100) + + reply.Validators = append(reply.Validators, CurrentValidator{ + ValidationID: validator.ValidationID, + NodeID: validator.NodeID, + StartTimestamp: validator.StartTimestamp, + Weight: validator.Weight, + IsActive: validator.IsActive, + IsL1Validator: validator.IsL1Validator, + IsConnected: isConnected, + UptimePercentage: uptimePercentage, + UptimeSeconds: uint64(upDuration.Seconds()), + }) + } return nil } diff --git a/plugin/evm/shared_memory_writer.go b/plugin/evm/shared_memory_writer.go deleted file mode 100644 index 88589720ee..0000000000 --- a/plugin/evm/shared_memory_writer.go +++ /dev/null @@ -1,37 +0,0 @@ -// (c) 2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package evm - -import ( - "github.com/ava-labs/avalanchego/chains/atomic" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/subnet-evm/precompile/precompileconfig" -) - -var _ precompileconfig.SharedMemoryWriter = &sharedMemoryWriter{} - -type sharedMemoryWriter struct { - requests map[ids.ID]*atomic.Requests -} - -func NewSharedMemoryWriter() *sharedMemoryWriter { - return &sharedMemoryWriter{ - requests: make(map[ids.ID]*atomic.Requests), - } -} - -func (s *sharedMemoryWriter) AddSharedMemoryRequests(chainID ids.ID, requests *atomic.Requests) { - mergeAtomicOpsToMap(s.requests, chainID, requests) -} - -// mergeAtomicOps merges atomic ops for [chainID] represented by [requests] -// to the [output] map provided. -func mergeAtomicOpsToMap(output map[ids.ID]*atomic.Requests, chainID ids.ID, requests *atomic.Requests) { - if request, exists := output[chainID]; exists { - request.PutRequests = append(request.PutRequests, requests.PutRequests...) - request.RemoveRequests = append(request.RemoveRequests, requests.RemoveRequests...) - } else { - output[chainID] = requests - } -} diff --git a/plugin/evm/static_service.go b/plugin/evm/static_service.go index 66b39d4acb..a4ac382019 100644 --- a/plugin/evm/static_service.go +++ b/plugin/evm/static_service.go @@ -8,8 +8,8 @@ import ( "net/http" "github.com/ava-labs/avalanchego/utils/formatting" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core" - "github.com/ethereum/go-ethereum/common" ) var ( diff --git a/plugin/evm/syncervm_client.go b/plugin/evm/syncervm_client.go index f18372995e..2b52fc697b 100644 --- a/plugin/evm/syncervm_client.go +++ b/plugin/evm/syncervm_client.go @@ -14,6 +14,9 @@ import ( commonEng "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" "github.com/ava-labs/avalanchego/vms/components/chain" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/eth" @@ -21,9 +24,6 @@ import ( "github.com/ava-labs/subnet-evm/plugin/evm/message" syncclient "github.com/ava-labs/subnet-evm/sync/client" "github.com/ava-labs/subnet-evm/sync/statesync" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" ) const ( @@ -299,7 +299,7 @@ func (client *stateSyncerClient) Shutdown() error { } // finishSync is responsible for updating disk and memory pointers so the VM is prepared -// for bootstrapping. Executes any shared memory operations from the atomic trie to shared memory. +// for bootstrapping. func (client *stateSyncerClient) finishSync() error { stateBlock, err := client.state.GetBlock(context.TODO(), ids.ID(client.syncSummary.BlockHash)) if err != nil { @@ -349,8 +349,6 @@ func (client *stateSyncerClient) finishSync() error { // updateVMMarkers updates the following markers in the VM's database // and commits them atomically: -// - updates atomic trie so it will have necessary metadata for the last committed root -// - updates atomic trie so it will resume applying operations to shared memory on initialize // - updates lastAcceptedKey // - removes state sync progress markers func (client *stateSyncerClient) updateVMMarkers() error { diff --git a/plugin/evm/syncervm_server.go b/plugin/evm/syncervm_server.go index 0f3643f6c4..6ec37ff3fa 100644 --- a/plugin/evm/syncervm_server.go +++ b/plugin/evm/syncervm_server.go @@ -10,9 +10,9 @@ import ( "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/plugin/evm/message" - "github.com/ethereum/go-ethereum/log" ) type stateSyncServerConfig struct { diff --git a/plugin/evm/syncervm_test.go b/plugin/evm/syncervm_test.go index 4f0a5ffc02..2caada0a04 100644 --- a/plugin/evm/syncervm_test.go +++ b/plugin/evm/syncervm_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/ava-labs/avalanchego/database" + avalanchedatabase "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" @@ -24,6 +24,12 @@ import ( "github.com/ava-labs/avalanchego/snow/engine/snowman/block" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/constants" "github.com/ava-labs/subnet-evm/core" @@ -31,16 +37,11 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/metrics" "github.com/ava-labs/subnet-evm/params" + "github.com/ava-labs/subnet-evm/plugin/evm/database" "github.com/ava-labs/subnet-evm/predicate" statesyncclient "github.com/ava-labs/subnet-evm/sync/client" "github.com/ava-labs/subnet-evm/sync/statesync" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) func TestSkipStateSync(t *testing.T) { @@ -372,7 +373,7 @@ type syncVMSetup struct { fundedAccounts map[*utils.Key]*types.StateAccount syncerVM *VM - syncerDB database.Database + syncerDB avalanchedatabase.Database syncerEngineChan <-chan commonEng.Message shutdownOnceSyncerVM *shutdownOnceVM } @@ -430,7 +431,7 @@ func testSyncerVM(t *testing.T, vmSetup *syncVMSetup, test syncTest) { if test.expectedErr != nil { require.ErrorIs(err, test.expectedErr) // Note we re-open the database here to avoid a closed error when the test is for a shutdown VM. - chaindb := Database{prefixdb.NewNested(ethDBPrefix, syncerVM.db)} + chaindb := database.WrapDatabase(prefixdb.NewNested(ethDBPrefix, syncerVM.versiondb)) assertSyncPerformedHeights(t, chaindb, map[uint64]struct{}{}) return } @@ -494,7 +495,7 @@ func testSyncerVM(t *testing.T, vmSetup *syncVMSetup, test syncTest) { // check we can transition to [NormalOp] state and continue to process blocks. require.NoError(syncerVM.SetState(context.Background(), snow.NormalOp)) - require.True(syncerVM.bootstrapped) + require.True(syncerVM.bootstrapped.Get()) // Generate blocks after we have entered normal consensus as well generateAndAcceptBlocks(t, syncerVM, blocksToBuild, func(_ int, gen *core.BlockGen) { diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go index 36c47ffde5..0eaaa63e6d 100644 --- a/plugin/evm/tx_gossip_test.go +++ b/plugin/evm/tx_gossip_test.go @@ -20,7 +20,6 @@ import ( "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/snow/engine/enginetest" "github.com/ava-labs/avalanchego/snow/validators" - "github.com/ava-labs/avalanchego/snow/validators/validatorstest" agoUtils "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/set" @@ -37,7 +36,7 @@ func TestEthTxGossip(t *testing.T) { require := require.New(t) ctx := context.Background() snowCtx := utils.TestSnowContext() - validatorState := &validatorstest.State{} + validatorState := utils.NewTestValidatorState() snowCtx.ValidatorState = validatorState responseSender := &enginetest.SenderStub{ @@ -155,14 +154,6 @@ func TestEthTxPushGossipOutbound(t *testing.T) { require := require.New(t) ctx := context.Background() snowCtx := utils.TestSnowContext() - snowCtx.ValidatorState = &validatorstest.State{ - GetCurrentHeightF: func(context.Context) (uint64, error) { - return 0, nil - }, - GetValidatorSetF: func(context.Context, uint64, ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) { - return nil, nil - }, - } sender := &enginetest.SenderStub{ SentAppGossip: make(chan []byte, 1), } diff --git a/plugin/evm/validators/README.md b/plugin/evm/validators/README.md new file mode 100644 index 0000000000..84055b04ab --- /dev/null +++ b/plugin/evm/validators/README.md @@ -0,0 +1,61 @@ +# Validators + +The Validators package is a collection of structs and functions to manage the state and uptime of validators in the Subnet-EVM. It consists of the following components: + +- State package : The state package stores the validator state and uptime information. +- Uptime package: The uptime package manages the uptime tracking of the validators. +- Manager struct: The manager struct is responsible for managing the state and uptime of the validators. + +## State Package + +The state package stores the validator state and uptime information. The state package implements a CRUD interface for validators. The implementation tracks validators by their validationIDs and assumes they're unique per node and their validation period. The state implementation also assumes NodeIDs are unique in the tracked set. The state implementation only allows existing validator's `weight` and `IsActive` fields to be updated; all other fields should be constant and if any other field changes, the state manager errors and does not update the validator. + +For L1 validators, an `active` status implies the validator balance on the P-Chain is sufficient to cover the continuous validation fee. When an L1 validator balance is depleted, it is marked as `inactive` on the P-Chain and this information is passed to the Subnet-EVM's state. + +The state interface allows a listener to register state changes including validator addition, removal, and active status change. The listener always receives the full state when it first subscribes. + +The package defines how to serialize the data according to the codec. It can read and write the validator state and uptime information within the database. + +## Uptime Package + +The uptime package manages the uptime tracking of the L1 validators. It wraps [AvalancheGo's uptime tracking manager](https://pkg.go.dev/github.com/ava-labs/avalanchego/snow/uptime) under the hood and additionally introduces pausable uptime manager interface. The pausable uptime manager interface allows the manager to pause the uptime tracking for a specific validator when it becomes `inactive` and resume it when it becomes `active` again. + +The uptime package must be run on at least one L1 node, referred to in this document as the "tracker node". + +Uptime tracking works as follows: + +### StartTracking + +Nodes can start uptime tracking with the `StartTracking` method once they're bootstrapped. This method updates the uptime of up-to-date validators by adding the duration between their last updated time and tracker node's initializing time to their uptime. This effectively adds the tracker node's offline duration to the validator's uptime and optimistically assumes that the validators are online during this period. Subnet-EVM's pausable manager does not directly modify this behavior and it also updates validators that were paused/inactive before the node initialized. The pausable uptime manager assumes peers are online and `active` when the tracker nodes are offline. + +### Connected + +The AvalancheGo uptime manager records the time when a peer is connected to the tracker node. When a paused/ `inactive` validator is connected, the pausable uptime manager does not directly invoke the `Connected` method on the AvalancheGo uptime manager, thus the connection time is not directly recorded. Instead, the pausable uptime manager waits for the validator to increase its continuous validation fee balance and resume operation. When the validator resumes, the tracker node records the resumed time and starts tracking the uptime of the validator. + +Note: The uptime manager does not check if the connected peer is a validator or not. It records the connection time assuming that a non-validator peer can become a validator whilst they're connected to the uptime manager. + +### Disconnected + +When a peer validator is disconnected, the AvalancheGo uptime manager updates the uptime of the validator by adding the duration between the connection time and the disconnection time to the uptime of the validator. When a validator is paused/`inactive`, the pausable uptime manager handles the `inactive` peers as if they were disconnected. Thus the uptime manager assumes that no paused peers can be disconnected again from the pausable uptime manager. + +### Pause + +The pausable uptime manager can listen for validator status changes by subscribing to the state. When the state invokes the `OnValidatorStatusChange` method, the pausable uptime manager pauses the uptime tracking of the validator if the validator is currently `inactive`. When a validator is paused, it is treated as if it is disconnected from the tracker node; thus, its uptime is updated from the connection time to the pause time, and uptime manager stops tracking the uptime of the validator. + +### Resume + +When a paused validator peer resumes, meaning its status becomes `active`, the pausable uptime manager resumes the uptime tracking of the validator. It treats the peer as if it is connected to the tracker node. + +Note: The pausable uptime manager holds the set of connected peers that tracks the connected peers in the p2p layer. This set is used to start tracking the uptime of the paused/`inactive` validators when they resume; this is because the AvalancheGo uptime manager thinks that the peer is completely disconnected when it is paused. The pausable uptime manager is able to reconnect them to the inner manager by using this additional connected set. + +### CalculateUptime + +The `CalculateUptime` method calculates a node's uptime based on its connection status, connected time, and the current time. It first retrieves the node's current uptime and last update time from the state, returning an error if retrieval fails. If tracking hasn’t started, it assumes the node has been online since the last update, adding this duration to its uptime. If the node is not connected and tracking is `active`, uptime remains unchanged and returned. For connected nodes, the method ensures the connection time does not predate the last update to avoid double counting. Finally, it adds the duration since the last connection time to the node's uptime and returns the updated values. + +## Manager Struct + +`Manager` struct in `validators` package is responsible for managing the state of the validators by fetching the information from P-Chain state (via `GetCurrentValidatorSet` in chain context) and updating the state accordingly. It dispatches a `goroutine` to sync the validator state every 60 seconds. The manager fetches the up-to-date validator set from P-Chain and performs the sync operation. The sync operation first performs removing the validators from the state that are not in the P-Chain validator set. Then it adds new validators and updates the existing validators in the state. This order of operations ensures that the uptimes of validators being removed and re-added under same nodeIDs are updated in the same sync operation despite having different validationIDs. + +P-Chain's `GetCurrentValidatorSet` can report both L1 and Subnet validators. Subnet-EVM's uptime manager also tracks both of these validator types. So even if a the Subnet has not yet been converted to an L1, the uptime and validator state tracking is still performed by Subnet-EVM. + +Validator Manager persists the state to disk at the end of every sync operation. The VM also persists the validator database when the node is shutting down. \ No newline at end of file diff --git a/plugin/evm/validators/interfaces/interfaces.go b/plugin/evm/validators/interfaces/interfaces.go new file mode 100644 index 0000000000..d8b88b3626 --- /dev/null +++ b/plugin/evm/validators/interfaces/interfaces.go @@ -0,0 +1,30 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package interfaces + +import ( + "context" + "time" + + "github.com/ava-labs/avalanchego/ids" + avalancheuptime "github.com/ava-labs/avalanchego/snow/uptime" + stateinterfaces "github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces" +) + +type ValidatorReader interface { + // GetValidatorAndUptime returns the uptime of the validator specified by validationID + GetValidatorAndUptime(validationID ids.ID) (stateinterfaces.Validator, time.Duration, time.Time, error) +} + +type Manager interface { + stateinterfaces.State + avalancheuptime.Manager + ValidatorReader + + // Sync updates the validator set managed + // by the manager + Sync(ctx context.Context) error + // DispatchSync starts the sync process + DispatchSync(ctx context.Context) +} diff --git a/plugin/evm/validators/manager.go b/plugin/evm/validators/manager.go new file mode 100644 index 0000000000..afdb8f40d9 --- /dev/null +++ b/plugin/evm/validators/manager.go @@ -0,0 +1,161 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package validators + +import ( + "context" + "fmt" + "time" + + "github.com/ava-labs/avalanchego/database" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" + avalancheuptime "github.com/ava-labs/avalanchego/snow/uptime" + avalanchevalidators "github.com/ava-labs/avalanchego/snow/validators" + "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/interfaces" + validators "github.com/ava-labs/subnet-evm/plugin/evm/validators/state" + stateinterfaces "github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/uptime" + uptimeinterfaces "github.com/ava-labs/subnet-evm/plugin/evm/validators/uptime/interfaces" + + "github.com/ava-labs/libevm/log" +) + +const ( + SyncFrequency = 1 * time.Minute +) + +type manager struct { + chainCtx *snow.Context + stateinterfaces.State + uptimeinterfaces.PausableManager +} + +// NewManager returns a new validator manager +// that manages the validator state and the uptime manager. +func NewManager( + ctx *snow.Context, + db database.Database, + clock *mockable.Clock, +) (interfaces.Manager, error) { + validatorState, err := validators.NewState(db) + if err != nil { + return nil, fmt.Errorf("failed to initialize validator state: %w", err) + } + + // Initialize uptime manager + uptimeManager := uptime.NewPausableManager(avalancheuptime.NewManager(validatorState, clock)) + validatorState.RegisterListener(uptimeManager) + + return &manager{ + chainCtx: ctx, + State: validatorState, + PausableManager: uptimeManager, + }, nil +} + +// GetValidatorAndUptime returns the calculated uptime of the validator specified by validationID +// and the last updated time. +// GetValidatorAndUptime holds the chain context lock while performing the operation and can be called concurrently. +func (m *manager) GetValidatorAndUptime(validationID ids.ID) (stateinterfaces.Validator, time.Duration, time.Time, error) { + // lock the state + m.chainCtx.Lock.RLock() + defer m.chainCtx.Lock.RUnlock() + + // Get validator first + vdr, err := m.GetValidator(validationID) + if err != nil { + return stateinterfaces.Validator{}, 0, time.Time{}, fmt.Errorf("failed to get validator: %w", err) + } + + uptime, lastUpdated, err := m.CalculateUptime(vdr.NodeID) + if err != nil { + return stateinterfaces.Validator{}, 0, time.Time{}, fmt.Errorf("failed to get uptime: %w", err) + } + + return vdr, uptime, lastUpdated, nil +} + +// DispatchSync starts the sync process +// DispatchSync holds the chain context lock while performing the sync. +func (m *manager) DispatchSync(ctx context.Context) { + ticker := time.NewTicker(SyncFrequency) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + m.chainCtx.Lock.Lock() + if err := m.Sync(ctx); err != nil { + log.Error("failed to sync validators", "error", err) + } + m.chainCtx.Lock.Unlock() + case <-ctx.Done(): + return + } + } +} + +// Sync synchronizes the validator state with the current validator set +// and writes the state to the database. +// Sync is not safe to call concurrently and should be called with the chain context locked. +func (m *manager) Sync(ctx context.Context) error { + now := time.Now() + log.Debug("performing validator sync") + // get current validator set + currentValidatorSet, _, err := m.chainCtx.ValidatorState.GetCurrentValidatorSet(ctx, m.chainCtx.SubnetID) + if err != nil { + return fmt.Errorf("failed to get current validator set: %w", err) + } + + // load the current validator set into the validator state + if err := loadValidators(m.State, currentValidatorSet); err != nil { + return fmt.Errorf("failed to load current validators: %w", err) + } + + // write validators to the database + if err := m.State.WriteState(); err != nil { + return fmt.Errorf("failed to write validator state: %w", err) + } + + // TODO: add metrics + log.Debug("validator sync complete", "duration", time.Since(now)) + return nil +} + +// loadValidators loads the [validators] into the validator state [validatorState] +func loadValidators(validatorState stateinterfaces.State, newValidators map[ids.ID]*avalanchevalidators.GetCurrentValidatorOutput) error { + currentValidationIDs := validatorState.GetValidationIDs() + // first check if we need to delete any existing validators + for vID := range currentValidationIDs { + // if the validator is not in the new set of validators + // delete the validator + if _, exists := newValidators[vID]; !exists { + validatorState.DeleteValidator(vID) + } + } + + // then load the new validators + for newVID, newVdr := range newValidators { + currentVdr := stateinterfaces.Validator{ + ValidationID: newVID, + NodeID: newVdr.NodeID, + Weight: newVdr.Weight, + StartTimestamp: newVdr.StartTime, + IsActive: newVdr.IsActive, + IsL1Validator: newVdr.IsL1Validator, + } + if currentValidationIDs.Contains(newVID) { + if err := validatorState.UpdateValidator(currentVdr); err != nil { + return err + } + } else { + if err := validatorState.AddValidator(currentVdr); err != nil { + return err + } + } + } + return nil +} diff --git a/plugin/evm/validators/manager_test.go b/plugin/evm/validators/manager_test.go new file mode 100644 index 0000000000..e73fcca26c --- /dev/null +++ b/plugin/evm/validators/manager_test.go @@ -0,0 +1,221 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package validators + +import ( + "testing" + + "github.com/ava-labs/avalanchego/database/memdb" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/state" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + avagovalidators "github.com/ava-labs/avalanchego/snow/validators" +) + +func TestLoadNewValidators(t *testing.T) { + testNodeIDs := []ids.NodeID{ + ids.GenerateTestNodeID(), + ids.GenerateTestNodeID(), + ids.GenerateTestNodeID(), + } + testValidationIDs := []ids.ID{ + ids.GenerateTestID(), + ids.GenerateTestID(), + ids.GenerateTestID(), + } + tests := []struct { + name string + initialValidators map[ids.ID]*avagovalidators.GetCurrentValidatorOutput + newValidators map[ids.ID]*avagovalidators.GetCurrentValidatorOutput + registerMockListenerCalls func(*interfaces.MockStateCallbackListener) + expectedLoadErr error + }{ + { + name: "before empty/after empty", + initialValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{}, + newValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{}, + registerMockListenerCalls: func(*interfaces.MockStateCallbackListener) {}, + }, + { + name: "before empty/after one", + initialValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{}, + newValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[0], + IsActive: true, + StartTime: 0, + }, + }, + registerMockListenerCalls: func(mock *interfaces.MockStateCallbackListener) { + mock.EXPECT().OnValidatorAdded(testValidationIDs[0], testNodeIDs[0], uint64(0), true).Times(1) + }, + }, + { + name: "before one/after empty", + initialValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[0], + IsActive: true, + StartTime: 0, + }, + }, + newValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{}, + registerMockListenerCalls: func(mock *interfaces.MockStateCallbackListener) { + // initial validator will trigger first + mock.EXPECT().OnValidatorAdded(testValidationIDs[0], testNodeIDs[0], uint64(0), true).Times(1) + // then it will be removed + mock.EXPECT().OnValidatorRemoved(testValidationIDs[0], testNodeIDs[0]).Times(1) + }, + }, + { + name: "no change", + initialValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[0], + IsActive: true, + StartTime: 0, + }, + }, + newValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[0], + IsActive: true, + StartTime: 0, + }, + }, + registerMockListenerCalls: func(mock *interfaces.MockStateCallbackListener) { + mock.EXPECT().OnValidatorAdded(testValidationIDs[0], testNodeIDs[0], uint64(0), true).Times(1) + }, + }, + { + name: "status and weight change and new one", + initialValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[0], + IsActive: true, + StartTime: 0, + Weight: 1, + }, + }, + newValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[0], + IsActive: false, + StartTime: 0, + Weight: 2, + }, + testValidationIDs[1]: { + NodeID: testNodeIDs[1], + IsActive: true, + StartTime: 0, + }, + }, + registerMockListenerCalls: func(mock *interfaces.MockStateCallbackListener) { + // initial validator will trigger first + mock.EXPECT().OnValidatorAdded(testValidationIDs[0], testNodeIDs[0], uint64(0), true).Times(1) + // then it will be updated + mock.EXPECT().OnValidatorStatusUpdated(testValidationIDs[0], testNodeIDs[0], false).Times(1) + // new validator will be added + mock.EXPECT().OnValidatorAdded(testValidationIDs[1], testNodeIDs[1], uint64(0), true).Times(1) + }, + }, + { + name: "renew validation ID", + initialValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[0], + IsActive: true, + StartTime: 0, + }, + }, + newValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[1]: { + NodeID: testNodeIDs[0], + IsActive: true, + StartTime: 0, + }, + }, + registerMockListenerCalls: func(mock *interfaces.MockStateCallbackListener) { + // initial validator will trigger first + mock.EXPECT().OnValidatorAdded(testValidationIDs[0], testNodeIDs[0], uint64(0), true).Times(1) + // then it will be removed + mock.EXPECT().OnValidatorRemoved(testValidationIDs[0], testNodeIDs[0]).Times(1) + // new validator will be added + mock.EXPECT().OnValidatorAdded(testValidationIDs[1], testNodeIDs[0], uint64(0), true).Times(1) + }, + }, + { + name: "renew node ID", + initialValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[0], + IsActive: true, + StartTime: 0, + }, + }, + newValidators: map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[1], + IsActive: true, + StartTime: 0, + }, + }, + expectedLoadErr: state.ErrImmutableField, + registerMockListenerCalls: func(mock *interfaces.MockStateCallbackListener) { + // initial validator will trigger first + mock.EXPECT().OnValidatorAdded(testValidationIDs[0], testNodeIDs[0], uint64(0), true).Times(1) + // then it won't be called since we don't track the node ID changes + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + require := require.New(tt) + db := memdb.New() + validatorState, err := state.NewState(db) + require.NoError(err) + + // set initial validators + for vID, validator := range test.initialValidators { + err := validatorState.AddValidator(interfaces.Validator{ + ValidationID: vID, + NodeID: validator.NodeID, + Weight: validator.Weight, + StartTimestamp: validator.StartTime, + IsActive: validator.IsActive, + IsL1Validator: validator.IsL1Validator, + }) + require.NoError(err) + } + // enable mock listener + ctrl := gomock.NewController(tt) + mockListener := interfaces.NewMockStateCallbackListener(ctrl) + test.registerMockListenerCalls(mockListener) + + validatorState.RegisterListener(mockListener) + // load new validators + err = loadValidators(validatorState, test.newValidators) + if test.expectedLoadErr != nil { + require.Error(err) + return + } + require.NoError(err) + // check if the state is as expected + require.Equal(len(test.newValidators), validatorState.GetValidationIDs().Len()) + for vID, validator := range test.newValidators { + v, err := validatorState.GetValidator(vID) + require.NoError(err) + require.Equal(validator.NodeID, v.NodeID) + require.Equal(validator.Weight, v.Weight) + require.Equal(validator.StartTime, v.StartTimestamp) + require.Equal(validator.IsActive, v.IsActive) + require.Equal(validator.IsL1Validator, v.IsL1Validator) + } + }) + } +} diff --git a/plugin/evm/validators/codec.go b/plugin/evm/validators/state/codec.go similarity index 96% rename from plugin/evm/validators/codec.go rename to plugin/evm/validators/state/codec.go index dadba8b273..aeb1a683b2 100644 --- a/plugin/evm/validators/codec.go +++ b/plugin/evm/validators/state/codec.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package validators +package state import ( "math" diff --git a/plugin/evm/validators/interfaces/mock_listener.go b/plugin/evm/validators/state/interfaces/mock_listener.go similarity index 70% rename from plugin/evm/validators/interfaces/mock_listener.go rename to plugin/evm/validators/state/interfaces/mock_listener.go index 8cf1903729..6ea8e5facf 100644 --- a/plugin/evm/validators/interfaces/mock_listener.go +++ b/plugin/evm/validators/state/interfaces/mock_listener.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ava-labs/subnet-evm/plugin/evm/validators/interfaces (interfaces: StateCallbackListener) +// Source: github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces (interfaces: StateCallbackListener) // // Generated by this command: // -// mockgen -package=interfaces -destination=plugin/evm/validators/interfaces/mock_listener.go github.com/ava-labs/subnet-evm/plugin/evm/validators/interfaces StateCallbackListener +// mockgen -package=interfaces -destination=mock_listener.go . StateCallbackListener // // Package interfaces is a generated GoMock package. @@ -20,6 +20,7 @@ import ( type MockStateCallbackListener struct { ctrl *gomock.Controller recorder *MockStateCallbackListenerMockRecorder + isgomock struct{} } // MockStateCallbackListenerMockRecorder is the mock recorder for MockStateCallbackListener. @@ -40,37 +41,37 @@ func (m *MockStateCallbackListener) EXPECT() *MockStateCallbackListenerMockRecor } // OnValidatorAdded mocks base method. -func (m *MockStateCallbackListener) OnValidatorAdded(arg0 ids.ID, arg1 ids.NodeID, arg2 uint64, arg3 bool) { +func (m *MockStateCallbackListener) OnValidatorAdded(vID ids.ID, nodeID ids.NodeID, startTime uint64, isActive bool) { m.ctrl.T.Helper() - m.ctrl.Call(m, "OnValidatorAdded", arg0, arg1, arg2, arg3) + m.ctrl.Call(m, "OnValidatorAdded", vID, nodeID, startTime, isActive) } // OnValidatorAdded indicates an expected call of OnValidatorAdded. -func (mr *MockStateCallbackListenerMockRecorder) OnValidatorAdded(arg0, arg1, arg2, arg3 any) *gomock.Call { +func (mr *MockStateCallbackListenerMockRecorder) OnValidatorAdded(vID, nodeID, startTime, isActive any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnValidatorAdded", reflect.TypeOf((*MockStateCallbackListener)(nil).OnValidatorAdded), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnValidatorAdded", reflect.TypeOf((*MockStateCallbackListener)(nil).OnValidatorAdded), vID, nodeID, startTime, isActive) } // OnValidatorRemoved mocks base method. -func (m *MockStateCallbackListener) OnValidatorRemoved(arg0 ids.ID, arg1 ids.NodeID) { +func (m *MockStateCallbackListener) OnValidatorRemoved(vID ids.ID, nodeID ids.NodeID) { m.ctrl.T.Helper() - m.ctrl.Call(m, "OnValidatorRemoved", arg0, arg1) + m.ctrl.Call(m, "OnValidatorRemoved", vID, nodeID) } // OnValidatorRemoved indicates an expected call of OnValidatorRemoved. -func (mr *MockStateCallbackListenerMockRecorder) OnValidatorRemoved(arg0, arg1 any) *gomock.Call { +func (mr *MockStateCallbackListenerMockRecorder) OnValidatorRemoved(vID, nodeID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnValidatorRemoved", reflect.TypeOf((*MockStateCallbackListener)(nil).OnValidatorRemoved), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnValidatorRemoved", reflect.TypeOf((*MockStateCallbackListener)(nil).OnValidatorRemoved), vID, nodeID) } // OnValidatorStatusUpdated mocks base method. -func (m *MockStateCallbackListener) OnValidatorStatusUpdated(arg0 ids.ID, arg1 ids.NodeID, arg2 bool) { +func (m *MockStateCallbackListener) OnValidatorStatusUpdated(vID ids.ID, nodeID ids.NodeID, isActive bool) { m.ctrl.T.Helper() - m.ctrl.Call(m, "OnValidatorStatusUpdated", arg0, arg1, arg2) + m.ctrl.Call(m, "OnValidatorStatusUpdated", vID, nodeID, isActive) } // OnValidatorStatusUpdated indicates an expected call of OnValidatorStatusUpdated. -func (mr *MockStateCallbackListenerMockRecorder) OnValidatorStatusUpdated(arg0, arg1, arg2 any) *gomock.Call { +func (mr *MockStateCallbackListenerMockRecorder) OnValidatorStatusUpdated(vID, nodeID, isActive any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnValidatorStatusUpdated", reflect.TypeOf((*MockStateCallbackListener)(nil).OnValidatorStatusUpdated), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnValidatorStatusUpdated", reflect.TypeOf((*MockStateCallbackListener)(nil).OnValidatorStatusUpdated), vID, nodeID, isActive) } diff --git a/plugin/evm/validators/state/interfaces/mocks_generate_test.go b/plugin/evm/validators/state/interfaces/mocks_generate_test.go new file mode 100644 index 0000000000..fb08084d17 --- /dev/null +++ b/plugin/evm/validators/state/interfaces/mocks_generate_test.go @@ -0,0 +1,3 @@ +package interfaces + +//go:generate go run go.uber.org/mock/mockgen -package=$GOPACKAGE -destination=mock_listener.go . StateCallbackListener diff --git a/plugin/evm/validators/interfaces/interface.go b/plugin/evm/validators/state/interfaces/state.go similarity index 60% rename from plugin/evm/validators/interfaces/interface.go rename to plugin/evm/validators/state/interfaces/state.go index 197ab553a1..6ed743d09c 100644 --- a/plugin/evm/validators/interfaces/interface.go +++ b/plugin/evm/validators/state/interfaces/state.go @@ -9,25 +9,28 @@ import ( "github.com/ava-labs/avalanchego/utils/set" ) +type StateReader interface { + // GetValidator returns the validator data for the given validation ID + GetValidator(vID ids.ID) (Validator, error) + // GetValidationIDs returns the validation IDs in the state + GetValidationIDs() set.Set[ids.ID] + // GetNodeIDs returns the validator node IDs in the state + GetNodeIDs() set.Set[ids.NodeID] + // GetValidationID returns the validation ID for the given node ID + GetValidationID(nodeID ids.NodeID) (ids.ID, error) +} + type State interface { uptime.State + StateReader // AddValidator adds a new validator to the state - AddValidator(vID ids.ID, nodeID ids.NodeID, startTimestamp uint64, isActive bool) error + AddValidator(vdr Validator) error + // UpdateValidator updates the validator in the state + UpdateValidator(vdr Validator) error // DeleteValidator deletes the validator from the state DeleteValidator(vID ids.ID) error // WriteState writes the validator state to the disk WriteState() error - - // SetStatus sets the active status of the validator with the given vID - SetStatus(vID ids.ID, isActive bool) error - // GetStatus returns the active status of the validator with the given vID - GetStatus(vID ids.ID) (bool, error) - - // GetValidationIDs returns the validation IDs in the state - GetValidationIDs() set.Set[ids.ID] - // GetValidatorIDs returns the validator node IDs in the state - GetValidatorIDs() set.Set[ids.NodeID] - // RegisterListener registers a listener to the state RegisterListener(StateCallbackListener) } @@ -41,3 +44,12 @@ type StateCallbackListener interface { // OnValidatorStatusUpdated is called when a validator status is updated OnValidatorStatusUpdated(vID ids.ID, nodeID ids.NodeID, isActive bool) } + +type Validator struct { + ValidationID ids.ID `json:"validationID"` + NodeID ids.NodeID `json:"nodeID"` + Weight uint64 `json:"weight"` + StartTimestamp uint64 `json:"startTimestamp"` + IsActive bool `json:"isActive"` + IsL1Validator bool `json:"isL1Validator"` +} diff --git a/plugin/evm/validators/state.go b/plugin/evm/validators/state/state.go similarity index 66% rename from plugin/evm/validators/state.go rename to plugin/evm/validators/state/state.go index 0be101f6bf..c3150c10ac 100644 --- a/plugin/evm/validators/state.go +++ b/plugin/evm/validators/state/state.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package validators +package state import ( "fmt" @@ -11,26 +11,31 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/uptime" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/subnet-evm/plugin/evm/validators/interfaces" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces" ) var _ uptime.State = &state{} type dbUpdateStatus bool -var ErrAlreadyExists = fmt.Errorf("validator already exists") +var ( + ErrAlreadyExists = fmt.Errorf("validator already exists") + ErrImmutableField = fmt.Errorf("immutable field cannot be updated") +) const ( - updated dbUpdateStatus = true - deleted dbUpdateStatus = false + updatedStatus dbUpdateStatus = true + deletedStatus dbUpdateStatus = false ) type validatorData struct { - UpDuration time.Duration `serialize:"true"` - LastUpdated uint64 `serialize:"true"` - NodeID ids.NodeID `serialize:"true"` - StartTime uint64 `serialize:"true"` - IsActive bool `serialize:"true"` + UpDuration time.Duration `serialize:"true"` + LastUpdated uint64 `serialize:"true"` + NodeID ids.NodeID `serialize:"true"` + Weight uint64 `serialize:"true"` + StartTime uint64 `serialize:"true"` + IsActive bool `serialize:"true"` + IsL1Validator bool `serialize:"true"` validationID ids.ID // database key } @@ -83,7 +88,7 @@ func (s *state) SetUptime( data.UpDuration = upDuration data.setLastUpdated(lastUpdated) - s.updatedData[data.validationID] = updated + s.updatedData[data.validationID] = updatedStatus return nil } @@ -98,23 +103,57 @@ func (s *state) GetStartTime(nodeID ids.NodeID) (time.Time, error) { // AddValidator adds a new validator to the state // the new validator is marked as updated and will be written to the disk when WriteState is called -func (s *state) AddValidator(vID ids.ID, nodeID ids.NodeID, startTimestamp uint64, isActive bool) error { +func (s *state) AddValidator(vdr interfaces.Validator) error { data := &validatorData{ - NodeID: nodeID, - validationID: vID, - IsActive: isActive, - StartTime: startTimestamp, - UpDuration: 0, - LastUpdated: startTimestamp, + NodeID: vdr.NodeID, + validationID: vdr.ValidationID, + IsActive: vdr.IsActive, + StartTime: vdr.StartTimestamp, + UpDuration: 0, + LastUpdated: vdr.StartTimestamp, + IsL1Validator: vdr.IsL1Validator, + Weight: vdr.Weight, } - if err := s.addData(vID, data); err != nil { + if err := s.addData(vdr.ValidationID, data); err != nil { return err } - s.updatedData[vID] = updated + s.updatedData[vdr.ValidationID] = updatedStatus for _, listener := range s.listeners { - listener.OnValidatorAdded(vID, nodeID, startTimestamp, isActive) + listener.OnValidatorAdded(vdr.ValidationID, vdr.NodeID, vdr.StartTimestamp, vdr.IsActive) + } + return nil +} + +// UpdateValidator updates the validator in the state +// returns an error if the validator does not exist or if the immutable fields are modified +func (s *state) UpdateValidator(vdr interfaces.Validator) error { + data, exists := s.data[vdr.ValidationID] + if !exists { + return database.ErrNotFound + } + // check immutable fields + if !data.constantsAreUnmodified(vdr) { + return ErrImmutableField + } + // check if mutable fields have changed + updated := false + if data.IsActive != vdr.IsActive { + data.IsActive = vdr.IsActive + updated = true + for _, listener := range s.listeners { + listener.OnValidatorStatusUpdated(data.validationID, data.NodeID, data.IsActive) + } + } + + if data.Weight != vdr.Weight { + data.Weight = vdr.Weight + updated = true + } + + if updated { + s.updatedData[vdr.ValidationID] = updatedStatus } return nil } @@ -130,7 +169,7 @@ func (s *state) DeleteValidator(vID ids.ID) error { delete(s.index, data.NodeID) // mark as deleted for WriteValidator - s.updatedData[data.validationID] = deleted + s.updatedData[data.validationID] = deletedStatus for _, listener := range s.listeners { listener.OnValidatorRemoved(vID, data.NodeID) @@ -144,7 +183,7 @@ func (s *state) WriteState() error { batch := s.db.NewBatch() for vID, updateStatus := range s.updatedData { switch updateStatus { - case updated: + case updatedStatus: data := s.data[vID] dataBytes, err := vdrCodec.Marshal(codecVersion, data) @@ -154,7 +193,7 @@ func (s *state) WriteState() error { if err := batch.Put(vID[:], dataBytes); err != nil { return err } - case deleted: + case deletedStatus: if err := batch.Delete(vID[:]); err != nil { return err } @@ -174,7 +213,7 @@ func (s *state) SetStatus(vID ids.ID, isActive bool) error { return database.ErrNotFound } data.IsActive = isActive - s.updatedData[vID] = updated + s.updatedData[vID] = updatedStatus for _, listener := range s.listeners { listener.OnValidatorStatusUpdated(vID, data.NodeID, isActive) @@ -182,15 +221,6 @@ func (s *state) SetStatus(vID ids.ID, isActive bool) error { return nil } -// GetStatus returns the active status of the validator with the given vID -func (s *state) GetStatus(vID ids.ID) (bool, error) { - data, exists := s.data[vID] - if !exists { - return false, database.ErrNotFound - } - return data.IsActive, nil -} - // GetValidationIDs returns the validation IDs in the state func (s *state) GetValidationIDs() set.Set[ids.ID] { ids := set.NewSet[ids.ID](len(s.data)) @@ -200,8 +230,8 @@ func (s *state) GetValidationIDs() set.Set[ids.ID] { return ids } -// GetValidatorIDs returns the validator IDs in the state -func (s *state) GetValidatorIDs() set.Set[ids.NodeID] { +// GetNodeIDs returns the node IDs of validators in the state +func (s *state) GetNodeIDs() set.Set[ids.NodeID] { ids := set.NewSet[ids.NodeID](len(s.index)) for nodeID := range s.index { ids.Add(nodeID) @@ -209,6 +239,31 @@ func (s *state) GetValidatorIDs() set.Set[ids.NodeID] { return ids } +// GetValidationID returns the validation ID for the given nodeID +func (s *state) GetValidationID(nodeID ids.NodeID) (ids.ID, error) { + vID, exists := s.index[nodeID] + if !exists { + return ids.ID{}, database.ErrNotFound + } + return vID, nil +} + +// GetValidator returns the validator data for the given validationID +func (s *state) GetValidator(vID ids.ID) (interfaces.Validator, error) { + data, ok := s.data[vID] + if !ok { + return interfaces.Validator{}, database.ErrNotFound + } + return interfaces.Validator{ + ValidationID: data.validationID, + NodeID: data.NodeID, + StartTimestamp: data.StartTime, + IsActive: data.IsActive, + Weight: data.Weight, + IsL1Validator: data.IsL1Validator, + }, nil +} + // RegisterListener registers a listener to the state // OnValidatorAdded is called for all current validators on the provided listener before this function returns func (s *state) RegisterListener(listener interfaces.StateCallbackListener) { @@ -293,3 +348,12 @@ func (v *validatorData) getLastUpdated() time.Time { func (v *validatorData) getStartTime() time.Time { return time.Unix(int64(v.StartTime), 0) } + +// constantsAreUnmodified returns true if the constants of this validator have +// not been modified compared to the updated validator. +func (v *validatorData) constantsAreUnmodified(u interfaces.Validator) bool { + return v.validationID == u.ValidationID && + v.NodeID == u.NodeID && + v.IsL1Validator == u.IsL1Validator && + v.StartTime == u.StartTimestamp +} diff --git a/plugin/evm/validators/state_test.go b/plugin/evm/validators/state/state_test.go similarity index 66% rename from plugin/evm/validators/state_test.go rename to plugin/evm/validators/state/state_test.go index e5e8244027..852a654109 100644 --- a/plugin/evm/validators/state_test.go +++ b/plugin/evm/validators/state/state_test.go @@ -1,7 +1,7 @@ // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package validators +package state import ( "testing" @@ -15,7 +15,7 @@ import ( "github.com/ava-labs/avalanchego/database/memdb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/wrappers" - "github.com/ava-labs/subnet-evm/plugin/evm/validators/interfaces" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces" ) func TestState(t *testing.T) { @@ -36,13 +36,23 @@ func TestState(t *testing.T) { require.ErrorIs(err, database.ErrNotFound) // add new validator - state.AddValidator(vID, nodeID, uint64(startTime.Unix()), true) + vdr := interfaces.Validator{ + ValidationID: vID, + NodeID: nodeID, + Weight: 1, + StartTimestamp: uint64(startTime.Unix()), + IsActive: true, + IsL1Validator: true, + } + state.AddValidator(vdr) // adding the same validator should fail - err = state.AddValidator(vID, ids.GenerateTestNodeID(), uint64(startTime.Unix()), true) + err = state.AddValidator(vdr) require.ErrorIs(err, ErrAlreadyExists) // adding the same nodeID should fail - err = state.AddValidator(ids.GenerateTestID(), nodeID, uint64(startTime.Unix()), true) + newVdr := vdr + newVdr.ValidationID = ids.GenerateTestID() + err = state.AddValidator(newVdr) require.ErrorIs(err, ErrAlreadyExists) // get uptime @@ -62,11 +72,38 @@ func TestState(t *testing.T) { require.Equal(newLastUpdated, lastUpdated) // set status - require.NoError(state.SetStatus(vID, false)) + vdr.IsActive = false + require.NoError(state.UpdateValidator(vdr)) // get status - status, err := state.GetStatus(vID) + data, err := state.GetValidator(vID) + require.NoError(err) + require.False(data.IsActive) + + // set weight + newWeight := uint64(2) + vdr.Weight = newWeight + require.NoError(state.UpdateValidator(vdr)) + // get weight + data, err = state.GetValidator(vID) require.NoError(err) - require.False(status) + require.Equal(newWeight, data.Weight) + + // set a different node ID should fail + newNodeID := ids.GenerateTestNodeID() + vdr.NodeID = newNodeID + require.ErrorIs(state.UpdateValidator(vdr), ErrImmutableField) + + // set a different start time should fail + vdr.StartTimestamp = vdr.StartTimestamp + 100 + require.ErrorIs(state.UpdateValidator(vdr), ErrImmutableField) + + // set IsL1Validator should fail + vdr.IsL1Validator = false + require.ErrorIs(state.UpdateValidator(vdr), ErrImmutableField) + + // set validation ID should result in not found + vdr.ValidationID = ids.GenerateTestID() + require.ErrorIs(state.UpdateValidator(vdr), database.ErrNotFound) // delete uptime require.NoError(state.DeleteValidator(vID)) @@ -88,7 +125,14 @@ func TestWriteValidator(t *testing.T) { nodeID := ids.GenerateTestNodeID() vID := ids.GenerateTestID() startTime := time.Now() - require.NoError(state.AddValidator(vID, nodeID, uint64(startTime.Unix()), true)) + require.NoError(state.AddValidator(interfaces.Validator{ + ValidationID: vID, + NodeID: nodeID, + Weight: 1, + StartTimestamp: uint64(startTime.Unix()), + IsActive: true, + IsL1Validator: true, + })) // write state, should reflect to DB require.NoError(state.WriteState()) @@ -132,8 +176,14 @@ func TestParseValidator(t *testing.T) { name: "nil", bytes: nil, expected: &validatorData{ - LastUpdated: 0, - StartTime: 0, + LastUpdated: 0, + StartTime: 0, + validationID: ids.Empty, + NodeID: ids.EmptyNodeID, + UpDuration: 0, + Weight: 0, + IsActive: false, + IsL1Validator: false, }, expectedErr: nil, }, @@ -141,8 +191,14 @@ func TestParseValidator(t *testing.T) { name: "empty", bytes: []byte{}, expected: &validatorData{ - LastUpdated: 0, - StartTime: 0, + LastUpdated: 0, + StartTime: 0, + validationID: ids.Empty, + NodeID: ids.EmptyNodeID, + UpDuration: 0, + Weight: 0, + IsActive: false, + IsL1Validator: false, }, expectedErr: nil, }, @@ -159,17 +215,23 @@ func TestParseValidator(t *testing.T) { 0x7e, 0xef, 0xe8, 0x8a, 0x45, 0xfb, 0x7a, 0xc4, 0xb0, 0x59, 0xc9, 0x33, 0x71, 0x0a, 0x57, 0x33, 0xff, 0x9f, 0x4b, 0xab, + // weight + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // start time 0x00, 0x00, 0x00, 0x00, 0x00, 0x5B, 0x8D, 0x80, // status 0x01, + // IsL1Validator + 0x01, }, expected: &validatorData{ - UpDuration: time.Duration(6000000), - LastUpdated: 900000, - NodeID: testNodeID, - StartTime: 6000000, - IsActive: true, + UpDuration: time.Duration(6000000), + LastUpdated: 900000, + NodeID: testNodeID, + StartTime: 6000000, + IsActive: true, + Weight: 1, + IsL1Validator: true, }, }, { @@ -231,7 +293,14 @@ func TestStateListener(t *testing.T) { initialStartTime := time.Now() // add initial validator - require.NoError(state.AddValidator(initialvID, initialNodeID, uint64(initialStartTime.Unix()), true)) + require.NoError(state.AddValidator(interfaces.Validator{ + ValidationID: initialvID, + NodeID: initialNodeID, + Weight: 1, + StartTimestamp: uint64(initialStartTime.Unix()), + IsActive: true, + IsL1Validator: true, + })) // register listener mockListener.EXPECT().OnValidatorAdded(initialvID, initialNodeID, uint64(initialStartTime.Unix()), true) @@ -239,11 +308,23 @@ func TestStateListener(t *testing.T) { // add new validator mockListener.EXPECT().OnValidatorAdded(expectedvID, expectedNodeID, uint64(expectedStartTime.Unix()), true) - require.NoError(state.AddValidator(expectedvID, expectedNodeID, uint64(expectedStartTime.Unix()), true)) + vdr := interfaces.Validator{ + ValidationID: expectedvID, + NodeID: expectedNodeID, + Weight: 1, + StartTimestamp: uint64(expectedStartTime.Unix()), + IsActive: true, + IsL1Validator: true, + } + require.NoError(state.AddValidator(vdr)) // set status mockListener.EXPECT().OnValidatorStatusUpdated(expectedvID, expectedNodeID, false) - require.NoError(state.SetStatus(expectedvID, false)) + vdr.IsActive = false + require.NoError(state.UpdateValidator(vdr)) + + // set status twice should not trigger listener + require.NoError(state.UpdateValidator(vdr)) // remove validator mockListener.EXPECT().OnValidatorRemoved(expectedvID, expectedNodeID) diff --git a/plugin/evm/uptime/interfaces/interface.go b/plugin/evm/validators/uptime/interfaces/interface.go similarity index 67% rename from plugin/evm/uptime/interfaces/interface.go rename to plugin/evm/validators/uptime/interfaces/interface.go index 13e6b7abba..296daae314 100644 --- a/plugin/evm/uptime/interfaces/interface.go +++ b/plugin/evm/validators/uptime/interfaces/interface.go @@ -6,11 +6,11 @@ package interfaces import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/uptime" - validatorsinterfaces "github.com/ava-labs/subnet-evm/plugin/evm/validators/interfaces" + validatorsstateinterfaces "github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces" ) type PausableManager interface { uptime.Manager - validatorsinterfaces.StateCallbackListener + validatorsstateinterfaces.StateCallbackListener IsPaused(nodeID ids.NodeID) bool } diff --git a/plugin/evm/uptime/pausable_manager.go b/plugin/evm/validators/uptime/pausable_manager.go similarity index 88% rename from plugin/evm/uptime/pausable_manager.go rename to plugin/evm/validators/uptime/pausable_manager.go index 3976fcae6c..a3cc608960 100644 --- a/plugin/evm/uptime/pausable_manager.go +++ b/plugin/evm/validators/uptime/pausable_manager.go @@ -6,8 +6,8 @@ package uptime import ( "errors" - "github.com/ava-labs/subnet-evm/plugin/evm/uptime/interfaces" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/uptime/interfaces" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/uptime" @@ -58,16 +58,10 @@ func (p *pausableManager) Disconnect(nodeID ids.NodeID) error { return nil } -// StartTracking starts tracking uptime for the nodes with the given IDs -// If a node is paused, it will not be tracked -func (p *pausableManager) StartTracking(nodeIDs []ids.NodeID) error { - activeNodeIDs := make([]ids.NodeID, 0, len(nodeIDs)) - for _, nodeID := range nodeIDs { - if !p.IsPaused(nodeID) { - activeNodeIDs = append(activeNodeIDs, nodeID) - } - } - return p.Manager.StartTracking(activeNodeIDs) +// IsConnected returns true if the node with the given ID is connected to this manager +// Note: Inner manager may have a different view of the connection status due to pausing +func (p *pausableManager) IsConnected(nodeID ids.NodeID) bool { + return p.connectedVdrs.Contains(nodeID) } // OnValidatorAdded is called when a validator is added. diff --git a/plugin/evm/uptime/pausable_manager_test.go b/plugin/evm/validators/uptime/pausable_manager_test.go similarity index 69% rename from plugin/evm/uptime/pausable_manager_test.go rename to plugin/evm/validators/uptime/pausable_manager_test.go index e1f4f4a6f8..8cdadba0fd 100644 --- a/plugin/evm/uptime/pausable_manager_test.go +++ b/plugin/evm/validators/uptime/pausable_manager_test.go @@ -10,7 +10,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/uptime" "github.com/ava-labs/avalanchego/utils/timer/mockable" - "github.com/ava-labs/subnet-evm/plugin/evm/uptime/interfaces" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/uptime/interfaces" "github.com/stretchr/testify/require" ) @@ -31,6 +31,7 @@ func TestPausableManager(t *testing.T) { // Connect before tracking require.NoError(up.Connect(nodeID0)) addTime(clk, time.Second) + expectedUptime := 1 * time.Second // Pause before tracking up.OnValidatorStatusUpdated(vID, nodeID0, false) @@ -38,12 +39,15 @@ func TestPausableManager(t *testing.T) { // Elapse Time addTime(clk, time.Second) + // Since we have not started tracking this node yet, its observed uptime should + // be incremented even though it is actually paused. + expectedUptime += 1 * time.Second // Start tracking require.NoError(up.StartTracking([]ids.NodeID{nodeID0})) + // Uptime here should not increase after start tracking + // since the node is still paused after we started tracking currentTime := addTime(clk, time.Second) - // Uptime should not have increased since the node was paused - expectedUptime := 0 * time.Second checkUptime(t, up, nodeID0, expectedUptime, currentTime) // Disconnect @@ -114,15 +118,17 @@ func TestPausableManager(t *testing.T) { // Start tracking addTime(clk, time.Second) + // Uptime should be 1 since the node was paused before we started tracking + expectedUptime := 1 * time.Second require.NoError(up.StartTracking([]ids.NodeID{nodeID0})) // Connect and check uptime addTime(clk, 1*time.Second) + checkUptime(t, up, nodeID0, expectedUptime, clk.Time()) require.NoError(up.Connect(nodeID0)) currentTime := addTime(clk, 2*time.Second) - // Uptime should not have increased since the node was paused - expectedUptime := 0 * time.Second + // Uptime should not have increased since the node was paused after we started tracking checkUptime(t, up, nodeID0, expectedUptime, currentTime) // Disconnect and check uptime @@ -209,6 +215,81 @@ func TestPausableManager(t *testing.T) { checkUptime(t, up, nodeID0, expectedUptime, currentTime) }, }, + { + name: "Case 5: Node paused after we stop tracking", + testFunc: func(t *testing.T, up interfaces.PausableManager, clk *mockable.Clock, s uptime.State) { + require := require.New(t) + + // Start tracking and connect + require.NoError(up.StartTracking([]ids.NodeID{nodeID0})) + addTime(clk, time.Second) + require.NoError(up.Connect(nodeID0)) + + // Stop tracking + currentTime := addTime(clk, 2*time.Second) + expectedUptime := 2 * time.Second + checkUptime(t, up, nodeID0, expectedUptime, currentTime) + require.NoError(up.StopTracking([]ids.NodeID{nodeID0})) + + // Pause after a while + addTime(clk, 3*time.Second) + // expectedUptime should increase since we stopped tracking + expectedUptime += 3 * time.Second + up.OnValidatorStatusUpdated(vID, nodeID0, false) + require.True(up.IsPaused(nodeID0)) + // expectedUptime should increase since we stopped tracking (even if the node was paused) + currentTime = addTime(clk, 4*time.Second) + expectedUptime += 4 * time.Second + + // Start tracking and check elapsed time + require.NoError(up.StartTracking([]ids.NodeID{nodeID0})) + // Uptime have increased since the node was paused before we started tracking + // We should be optimistic and assume the node was online and active until we start tracking + require.True(up.IsPaused(nodeID0)) + checkUptime(t, up, nodeID0, expectedUptime, currentTime) + }, + }, + { + name: "Case 6: Paused node got resumed after we stop tracking", + testFunc: func(t *testing.T, up interfaces.PausableManager, clk *mockable.Clock, s uptime.State) { + require := require.New(t) + + // Start tracking and connect + require.NoError(up.StartTracking([]ids.NodeID{nodeID0})) + addTime(clk, time.Second) + require.NoError(up.Connect(nodeID0)) + + // Pause after a while + currentTime := addTime(clk, 2*time.Second) + // expectedUptime should increase + expectedUptime := 2 * time.Second + up.OnValidatorStatusUpdated(vID, nodeID0, false) + require.True(up.IsPaused(nodeID0)) + checkUptime(t, up, nodeID0, expectedUptime, currentTime) + + // Stop tracking + currentTime = addTime(clk, 3*time.Second) + // expectedUptime should not increase since the node was paused + checkUptime(t, up, nodeID0, expectedUptime, currentTime) + require.NoError(up.StopTracking([]ids.NodeID{nodeID0})) + + // Resume after a while + addTime(clk, 4*time.Second) + // expectedUptime should increase since we stopped tracking + expectedUptime += 4 * time.Second + up.OnValidatorStatusUpdated(vID, nodeID0, true) + require.False(up.IsPaused(nodeID0)) + // expectedUptime should increase since we stopped tracking + currentTime = addTime(clk, 5*time.Second) + expectedUptime += 5 * time.Second + + // Start tracking and check elapsed time + require.NoError(up.StartTracking([]ids.NodeID{nodeID0})) + // Uptime should have increased by 4 seconds since the node was resumed + // We should be optimistic and assume the node was online and active until we start tracking + checkUptime(t, up, nodeID0, expectedUptime, currentTime) + }, + }, } for _, test := range tests { diff --git a/plugin/evm/version.go b/plugin/evm/version.go index 4ab2b39409..158c6e1510 100644 --- a/plugin/evm/version.go +++ b/plugin/evm/version.go @@ -11,7 +11,7 @@ var ( // GitCommit is set by the build script GitCommit string // Version is the version of Subnet EVM - Version string = "v0.6.11" + Version string = "v0.7.1" ) func init() { diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 5303e2dca6..abc81c8f13 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -5,7 +5,6 @@ package evm import ( "context" - "encoding/base64" "encoding/json" "errors" "fmt" @@ -24,6 +23,7 @@ import ( "github.com/ava-labs/avalanchego/network/p2p/gossip" "github.com/prometheus/client_golang/prometheus" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/constants" @@ -40,7 +40,8 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/peer" "github.com/ava-labs/subnet-evm/plugin/evm/message" - "github.com/ava-labs/subnet-evm/triedb" + "github.com/ava-labs/subnet-evm/plugin/evm/validators" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/interfaces" "github.com/ava-labs/subnet-evm/triedb/hashdb" warpcontract "github.com/ava-labs/subnet-evm/precompile/contracts/warp" @@ -54,26 +55,21 @@ import ( // We must import this package (not referenced elsewhere) so that the native "callTracer" // is added to a map of client-accessible tracers. In geth, this is done // inside of cmd/geth. - _ "github.com/ethereum/go-ethereum/eth/tracers/js" - _ "github.com/ethereum/go-ethereum/eth/tracers/native" + _ "github.com/ava-labs/libevm/eth/tracers/js" + _ "github.com/ava-labs/libevm/eth/tracers/native" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" // Force-load precompiles to trigger registration _ "github.com/ava-labs/subnet-evm/precompile/registry" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" avalancheRPC "github.com/gorilla/rpc/v2" "github.com/ava-labs/avalanchego/codec" - "github.com/ava-labs/avalanchego/database/leveldb" - "github.com/ava-labs/avalanchego/database/memdb" - "github.com/ava-labs/avalanchego/database/meterdb" - "github.com/ava-labs/avalanchego/database/pebbledb" - "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/database/versiondb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" @@ -83,14 +79,13 @@ import ( "github.com/ava-labs/avalanchego/utils/profiler" "github.com/ava-labs/avalanchego/utils/timer/mockable" "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/version" "github.com/ava-labs/avalanchego/vms/components/chain" commonEng "github.com/ava-labs/avalanchego/snow/engine/common" - avalanchemetrics "github.com/ava-labs/avalanchego/api/metrics" "github.com/ava-labs/avalanchego/database" avalancheUtils "github.com/ava-labs/avalanchego/utils" - avalancheconstants "github.com/ava-labs/avalanchego/utils/constants" avalancheJSON "github.com/ava-labs/avalanchego/utils/json" ) @@ -115,7 +110,6 @@ const ( ethMetricsPrefix = "eth" sdkMetricsPrefix = "sdk" chainStateMetricsPrefix = "chain_state" - dbMetricsPrefix = "db" // gossip constants pushGossipDiscardedElements = 16_384 @@ -135,16 +129,18 @@ const ( adminEndpoint = "/admin" ethRPCEndpoint = "/rpc" ethWSEndpoint = "/ws" + validatorsEndpoint = "/validators" ethTxGossipNamespace = "eth_tx_gossip" ) var ( // Set last accepted key to be longer than the keys used to store accepted block IDs. - lastAcceptedKey = []byte("last_accepted_key") - acceptedPrefix = []byte("snowman_accepted") - metadataPrefix = []byte("metadata") - warpPrefix = []byte("warp") - ethDBPrefix = []byte("ethdb") + lastAcceptedKey = []byte("last_accepted_key") + acceptedPrefix = []byte("snowman_accepted") + metadataPrefix = []byte("metadata") + warpPrefix = []byte("warp") + ethDBPrefix = []byte("ethdb") + validatorsDBPrefix = []byte("validators") ) var ( @@ -199,8 +195,11 @@ type VM struct { blockChain *core.BlockChain miner *miner.Miner - // [db] is the VM's current database managed by ChainState - db *versiondb.Database + // [versiondb] is the VM's current versioned database + versiondb *versiondb.Database + + // [db] is the VM's current database + db database.Database // metadataDB is used to store one off keys. metadataDB database.Database @@ -208,6 +207,8 @@ type VM struct { // [chaindb] is the database supplied to the Ethereum backend chaindb ethdb.Database + usingStandaloneDB bool + // [acceptedBlockDB] is the database to store the last accepted // block. acceptedBlockDB database.Database @@ -215,6 +216,8 @@ type VM struct { // set to a prefixDB with the prefix [warpPrefix] warpDB database.Database + validatorsDB database.Database + toEngine chan<- commonEng.Message syntacticBlockValidator BlockValidator @@ -233,12 +236,12 @@ type VM struct { client peer.NetworkClient networkCodec codec.Manager - validators *p2p.Validators + p2pValidators *p2p.Validators // Metrics sdkMetrics *prometheus.Registry - bootstrapped bool + bootstrapped avalancheUtils.Atomic[bool] logger SubnetEVMLogger // State sync server and client @@ -255,6 +258,8 @@ type VM struct { ethTxPushGossiper avalancheUtils.Atomic[*gossip.PushGossiper[*GossipEthTx]] ethTxPullGossiper gossip.Gossiper + validatorsManager interfaces.Manager + chainAlias string // RPC handlers (should be stopped before closing chaindb) rpcHandlers []interface{ Stop() } @@ -328,12 +333,9 @@ func (vm *VM) Initialize( } if vm.config.InspectDatabase { - start := time.Now() - log.Info("Starting database inspection") - if err := rawdb.InspectDatabase(vm.chaindb, nil, nil); err != nil { + if err := vm.inspectDatabases(); err != nil { return err } - log.Info("Completed database inspection", "elapsed", time.Since(start)) } g := new(core.Genesis) @@ -486,11 +488,16 @@ func (vm *VM) Initialize( if err != nil { return fmt.Errorf("failed to initialize p2p network: %w", err) } - vm.validators = p2p.NewValidators(p2pNetwork.Peers, vm.ctx.Log, vm.ctx.SubnetID, vm.ctx.ValidatorState, maxValidatorSetStaleness) + vm.p2pValidators = p2p.NewValidators(p2pNetwork.Peers, vm.ctx.Log, vm.ctx.SubnetID, vm.ctx.ValidatorState, maxValidatorSetStaleness) vm.networkCodec = message.Codec vm.Network = peer.NewNetwork(p2pNetwork, appSender, vm.networkCodec, chainCtx.NodeID, vm.config.MaxOutboundActiveRequests) vm.client = peer.NewNetworkClient(vm.Network) + vm.validatorsManager, err = validators.NewManager(vm.ctx, vm.validatorsDB, &vm.clock) + if err != nil { + return fmt.Errorf("failed to initialize validators manager: %w", err) + } + // Initialize warp backend offchainWarpMessages := make([][]byte, len(vm.config.WarpOffChainMessages)) for i, hexMsg := range vm.config.WarpOffChainMessages { @@ -514,6 +521,7 @@ func (vm *VM) Initialize( vm.ctx.ChainID, vm.ctx.WarpSigner, vm, + vm.validatorsManager, vm.warpDB, meteredCache, offchainWarpMessages, @@ -628,7 +636,7 @@ func (vm *VM) initializeStateSyncClient(lastAcceptedHeight uint64) error { chaindb: vm.chaindb, metadataDB: vm.metadataDB, acceptedBlockDB: vm.acceptedBlockDB, - db: vm.db, + db: vm.versiondb, toEngine: vm.toEngine, }) @@ -674,47 +682,73 @@ func (vm *VM) initChainState(lastAcceptedBlock *types.Block) error { func (vm *VM) SetState(_ context.Context, state snow.State) error { switch state { case snow.StateSyncing: - vm.bootstrapped = false + vm.bootstrapped.Set(false) return nil case snow.Bootstrapping: - vm.bootstrapped = false - if err := vm.StateSyncClient.Error(); err != nil { - return err - } - // After starting bootstrapping, do not attempt to resume a previous state sync. - if err := vm.StateSyncClient.ClearOngoingSummary(); err != nil { - return err - } - // Ensure snapshots are initialized before bootstrapping (i.e., if state sync is skipped). - // Note calling this function has no effect if snapshots are already initialized. - vm.blockChain.InitializeSnapshots() - return nil + return vm.onBootstrapStarted() case snow.NormalOp: - // Initialize goroutines related to block building once we enter normal operation as there is no need to handle mempool gossip before this point. - if err := vm.initBlockBuilding(); err != nil { - return fmt.Errorf("failed to initialize block building: %w", err) - } - vm.bootstrapped = true - return nil + return vm.onNormalOperationsStarted() default: return snow.ErrUnknownState } } -// initBlockBuilding starts goroutines to manage block building -func (vm *VM) initBlockBuilding() error { +// onBootstrapStarted marks this VM as bootstrapping +func (vm *VM) onBootstrapStarted() error { + vm.bootstrapped.Set(false) + if err := vm.StateSyncClient.Error(); err != nil { + return err + } + // After starting bootstrapping, do not attempt to resume a previous state sync. + if err := vm.StateSyncClient.ClearOngoingSummary(); err != nil { + return err + } + // Ensure snapshots are initialized before bootstrapping (i.e., if state sync is skipped). + // Note calling this function has no effect if snapshots are already initialized. + vm.blockChain.InitializeSnapshots() + + return nil +} + +// onNormalOperationsStarted marks this VM as bootstrapped +func (vm *VM) onNormalOperationsStarted() error { + if vm.bootstrapped.Get() { + return nil + } + vm.bootstrapped.Set(true) + ctx, cancel := context.WithCancel(context.TODO()) vm.cancel = cancel + // sync validators first + if err := vm.validatorsManager.Sync(ctx); err != nil { + return fmt.Errorf("failed to update validators: %w", err) + } + vdrIDs := vm.validatorsManager.GetNodeIDs().List() + // Then start tracking with updated validators + // StartTracking initializes the uptime tracking with the known validators + // and update their uptime to account for the time we were being offline. + if err := vm.validatorsManager.StartTracking(vdrIDs); err != nil { + return fmt.Errorf("failed to start tracking uptime: %w", err) + } + // dispatch validator set update + vm.shutdownWg.Add(1) + go func() { + vm.validatorsManager.DispatchSync(ctx) + vm.shutdownWg.Done() + }() + + // Initialize goroutines related to block building + // once we enter normal operation as there is no need to handle mempool gossip before this point. ethTxGossipMarshaller := GossipEthTxMarshaller{} - ethTxGossipClient := vm.Network.NewClient(p2p.TxGossipHandlerID, p2p.WithValidatorSampling(vm.validators)) + ethTxGossipClient := vm.Network.NewClient(p2p.TxGossipHandlerID, p2p.WithValidatorSampling(vm.p2pValidators)) ethTxGossipMetrics, err := gossip.NewMetrics(vm.sdkMetrics, ethTxGossipNamespace) if err != nil { return fmt.Errorf("failed to initialize eth tx gossip metrics: %w", err) } ethTxPool, err := NewGossipEthTxPool(vm.txPool, vm.sdkMetrics) if err != nil { - return err + return fmt.Errorf("failed to initialize gossip eth tx pool: %w", err) } vm.shutdownWg.Add(1) go func() { @@ -737,7 +771,7 @@ func (vm *VM) initBlockBuilding() error { ethTxPushGossiper, err = gossip.NewPushGossiper[*GossipEthTx]( ethTxGossipMarshaller, ethTxPool, - vm.validators, + vm.p2pValidators, ethTxGossipClient, ethTxGossipMetrics, pushGossipParams, @@ -767,12 +801,12 @@ func (vm *VM) initBlockBuilding() error { txGossipTargetMessageSize, txGossipThrottlingPeriod, txGossipThrottlingLimit, - vm.validators, + vm.p2pValidators, ) } if err := vm.Network.AddHandler(p2p.TxGossipHandlerID, vm.ethTxGossipHandler); err != nil { - return err + return fmt.Errorf("failed to add eth tx gossip handler: %w", err) } if vm.ethTxPullGossiper == nil { @@ -788,7 +822,7 @@ func (vm *VM) initBlockBuilding() error { vm.ethTxPullGossiper = gossip.ValidatorGossiper{ Gossiper: ethTxPullGossiper, NodeID: vm.ctx.NodeID, - Validators: vm.validators, + Validators: vm.p2pValidators, } } @@ -814,9 +848,9 @@ func (vm *VM) setAppRequestHandlers() { evmTrieDB := triedb.NewDatabase( vm.chaindb, &triedb.Config{ - HashDB: &hashdb.Config{ + DBOverride: hashdb.Config{ CleanCacheSize: vm.config.StateSyncServerTrieCache * units.MiB, - }, + }.BackendConstructor, }, ) @@ -832,6 +866,15 @@ func (vm *VM) Shutdown(context.Context) error { if vm.cancel != nil { vm.cancel() } + if vm.bootstrapped.Get() { + vdrIDs := vm.validatorsManager.GetNodeIDs().List() + if err := vm.validatorsManager.StopTracking(vdrIDs); err != nil { + return fmt.Errorf("failed to stop tracking uptime: %w", err) + } + if err := vm.validatorsManager.WriteState(); err != nil { + return fmt.Errorf("failed to write validator: %w", err) + } + } vm.Network.Shutdown() if err := vm.StateSyncClient.Shutdown(); err != nil { log.Error("error stopping state syncer", "err", err) @@ -843,6 +886,13 @@ func (vm *VM) Shutdown(context.Context) error { } vm.eth.Stop() log.Info("Ethereum backend stop completed") + if vm.usingStandaloneDB { + if err := vm.db.Close(); err != nil { + log.Error("failed to close database: %w", err) + } else { + log.Info("Database closed") + } + } vm.shutdownWg.Wait() log.Info("Subnet-EVM Shutdown completed") return nil @@ -1028,6 +1078,16 @@ func (vm *VM) CreateHandlers(context.Context) (map[string]http.Handler, error) { enabledAPIs = append(enabledAPIs, "subnet-evm-admin") } + if vm.config.ValidatorsAPIEnabled { + validatorsAPI, err := newHandler("validators", &ValidatorsAPI{vm}) + if err != nil { + return nil, fmt.Errorf("failed to register service for validators API due to %w", err) + } + apis[validatorsEndpoint] = validatorsAPI + enabledAPIs = append(enabledAPIs, "validators") + } + + // RPC APIs if vm.config.SnowmanAPIEnabled { if err := handler.RegisterName("snowman", &SnowmanAPI{vm}); err != nil { return nil, err @@ -1200,167 +1260,17 @@ func attachEthService(handler *rpc.Server, apis []rpc.API, names []string) error return nil } -// useStandaloneDatabase returns true if the chain can and should use a standalone database -// other than given by [db] in Initialize() -func (vm *VM) useStandaloneDatabase(acceptedDB database.Database) (bool, error) { - // no config provided, use default - standaloneDBFlag := vm.config.UseStandaloneDatabase - if standaloneDBFlag != nil { - return standaloneDBFlag.Bool(), nil - } - - // check if the chain can use a standalone database - _, err := acceptedDB.Get(lastAcceptedKey) - if err == database.ErrNotFound { - // If there is nothing in the database, we can use the standalone database - return true, nil - } - return false, err -} - -type DatabaseConfig struct { - // If true, all writes are to memory and are discarded at node shutdown. - ReadOnly bool `json:"readOnly"` - - // Path to database - Path string `json:"path"` - - // Name of the database type to use - Name string `json:"name"` - - // Path to config file - Config []byte `json:"-"` -} - -// getDatabaseConfig returns the database configuration for the chain -// to be used by separate, standalone database. -func getDatabaseConfig(config Config, chainDataDir string) (DatabaseConfig, error) { - var ( - configBytes []byte - err error - ) - if len(config.DatabaseConfigContent) != 0 { - dbConfigContent := config.DatabaseConfigContent - configBytes, err = base64.StdEncoding.DecodeString(dbConfigContent) - if err != nil { - return DatabaseConfig{}, fmt.Errorf("unable to decode base64 content: %w", err) - } - } else if len(config.DatabaseConfigFile) != 0 { - configPath := config.DatabaseConfigFile - configBytes, err = os.ReadFile(configPath) - if err != nil { - return DatabaseConfig{}, err - } - } - - dbPath := filepath.Join(chainDataDir, "db") - if len(config.DatabasePath) != 0 { - dbPath = config.DatabasePath +func (vm *VM) Connected(ctx context.Context, nodeID ids.NodeID, version *version.Application) error { + if err := vm.validatorsManager.Connect(nodeID); err != nil { + return fmt.Errorf("uptime manager failed to connect node %s: %w", nodeID, err) } - - return DatabaseConfig{ - Name: config.DatabaseType, - ReadOnly: config.DatabaseReadOnly, - Path: dbPath, - Config: configBytes, - }, nil + return vm.Network.Connected(ctx, nodeID, version) } -// initializeDBs initializes the databases used by the VM. -// If [useStandaloneDB] is true, the chain will use a standalone database for its state. -// Otherwise, the chain will use the provided [avaDB] for its state. -func (vm *VM) initializeDBs(avaDB database.Database) error { - db := avaDB - // skip standalone database initialization if we are running in unit tests - if vm.ctx.NetworkID != avalancheconstants.UnitTestID { - // first initialize the accepted block database to check if we need to use a standalone database - verDB := versiondb.New(avaDB) - acceptedDB := prefixdb.New(acceptedPrefix, verDB) - useStandAloneDB, err := vm.useStandaloneDatabase(acceptedDB) - if err != nil { - return err - } - if useStandAloneDB { - // If we are using a standalone database, we need to create a new database - // for the chain state. - dbConfig, err := getDatabaseConfig(vm.config, vm.ctx.ChainDataDir) - if err != nil { - return err - } - log.Info("Using standalone database for the chain state", "DatabaseConfig", dbConfig) - db, err = vm.createDatabase(dbConfig) - if err != nil { - return err - } - } - } - // Use NewNested rather than New so that the structure of the database - // remains the same regardless of the provided baseDB type. - vm.chaindb = rawdb.NewDatabase(Database{prefixdb.NewNested(ethDBPrefix, db)}) - vm.db = versiondb.New(db) - vm.acceptedBlockDB = prefixdb.New(acceptedPrefix, vm.db) - vm.metadataDB = prefixdb.New(metadataPrefix, vm.db) - // Note warpDB is not part of versiondb because it is not necessary - // that warp signatures are committed to the database atomically with - // the last accepted block. - // [warpDB] is used to store warp message signatures - // set to a prefixDB with the prefix [warpPrefix] - vm.warpDB = prefixdb.New(warpPrefix, db) - return nil -} - -// createDatabase returns a new database instance with the provided configuration -func (vm *VM) createDatabase(dbConfig DatabaseConfig) (database.Database, error) { - dbRegisterer, err := avalanchemetrics.MakeAndRegister( - vm.ctx.Metrics, - dbMetricsPrefix, - ) - if err != nil { - return nil, err - } - var db database.Database - // start the db - switch dbConfig.Name { - case leveldb.Name: - dbPath := filepath.Join(dbConfig.Path, leveldb.Name) - db, err = leveldb.New(dbPath, dbConfig.Config, vm.ctx.Log, dbRegisterer) - if err != nil { - return nil, fmt.Errorf("couldn't create %s at %s: %w", leveldb.Name, dbPath, err) - } - case memdb.Name: - db = memdb.New() - case pebbledb.Name: - dbPath := filepath.Join(dbConfig.Path, pebbledb.Name) - db, err = pebbledb.New(dbPath, dbConfig.Config, vm.ctx.Log, dbRegisterer) - if err != nil { - return nil, fmt.Errorf("couldn't create %s at %s: %w", pebbledb.Name, dbPath, err) - } - default: - return nil, fmt.Errorf( - "db-type was %q but should have been one of {%s, %s, %s}", - dbConfig.Name, - leveldb.Name, - memdb.Name, - pebbledb.Name, - ) - } - - if dbConfig.ReadOnly && dbConfig.Name != memdb.Name { - db = versiondb.New(db) - } - - meterDBReg, err := avalanchemetrics.MakeAndRegister( - vm.ctx.Metrics, - "meterdb", - ) - if err != nil { - return nil, err - } - - db, err = meterdb.New(meterDBReg, db) - if err != nil { - return nil, fmt.Errorf("failed to create meterdb: %w", err) +func (vm *VM) Disconnected(ctx context.Context, nodeID ids.NodeID) error { + if err := vm.validatorsManager.Disconnect(nodeID); err != nil { + return fmt.Errorf("uptime manager failed to disconnect node %s: %w", nodeID, err) } - return db, nil + return vm.Network.Disconnected(ctx, nodeID) } diff --git a/plugin/evm/vm_database.go b/plugin/evm/vm_database.go new file mode 100644 index 0000000000..16e9fae84c --- /dev/null +++ b/plugin/evm/vm_database.go @@ -0,0 +1,173 @@ +// (c) 2019-2021, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "encoding/base64" + "fmt" + "os" + "path/filepath" + "time" + + "github.com/ava-labs/avalanchego/config/node" + avalanchedatabase "github.com/ava-labs/avalanchego/database" + "github.com/ava-labs/avalanchego/database/prefixdb" + "github.com/ava-labs/avalanchego/database/versiondb" + avalancheconstants "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/subnet-evm/core/rawdb" + "github.com/ava-labs/subnet-evm/plugin/evm/database" +) + +// initializeDBs initializes the databases used by the VM. +// If [useStandaloneDB] is true, the chain will use a standalone database for its state. +// Otherwise, the chain will use the provided [avaDB] for its state. +func (vm *VM) initializeDBs(avaDB avalanchedatabase.Database) error { + db := avaDB + // skip standalone database initialization if we are running in unit tests + if vm.ctx.NetworkID != avalancheconstants.UnitTestID { + // first initialize the accepted block database to check if we need to use a standalone database + acceptedDB := prefixdb.New(acceptedPrefix, avaDB) + useStandAloneDB, err := vm.useStandaloneDatabase(acceptedDB) + if err != nil { + return err + } + if useStandAloneDB { + // If we are using a standalone database, we need to create a new database + // for the chain state. + dbConfig, err := getDatabaseConfig(vm.config, vm.ctx.ChainDataDir) + if err != nil { + return err + } + log.Info("Using standalone database for the chain state", "DatabaseConfig", dbConfig) + db, err = database.NewStandaloneDatabase(dbConfig, vm.ctx.Metrics, vm.ctx.Log) + if err != nil { + return err + } + vm.usingStandaloneDB = true + } + } + // Use NewNested rather than New so that the structure of the database + // remains the same regardless of the provided baseDB type. + vm.chaindb = rawdb.NewDatabase(database.WrapDatabase(prefixdb.NewNested(ethDBPrefix, db))) + vm.versiondb = versiondb.New(db) + vm.acceptedBlockDB = prefixdb.New(acceptedPrefix, vm.versiondb) + vm.metadataDB = prefixdb.New(metadataPrefix, vm.versiondb) + vm.db = db + // Note warpDB and validatorsDB are not part of versiondb because it is not necessary + // that they are committed to the database atomically with + // the last accepted block. + // [warpDB] is used to store warp message signatures + // set to a prefixDB with the prefix [warpPrefix] + vm.warpDB = prefixdb.New(warpPrefix, db) + // [validatorsDB] is used to store the current validator set and uptimes + // set to a prefixDB with the prefix [validatorsDBPrefix] + vm.validatorsDB = prefixdb.New(validatorsDBPrefix, db) + return nil +} + +func (vm *VM) inspectDatabases() error { + start := time.Now() + log.Info("Starting database inspection") + if err := rawdb.InspectDatabase(vm.chaindb, nil, nil); err != nil { + return err + } + if err := inspectDB(vm.acceptedBlockDB, "acceptedBlockDB"); err != nil { + return err + } + if err := inspectDB(vm.metadataDB, "metadataDB"); err != nil { + return err + } + if err := inspectDB(vm.warpDB, "warpDB"); err != nil { + return err + } + if err := inspectDB(vm.validatorsDB, "validatorsDB"); err != nil { + return err + } + log.Info("Completed database inspection", "elapsed", time.Since(start)) + return nil +} + +// useStandaloneDatabase returns true if the chain can and should use a standalone database +// other than given by [db] in Initialize() +func (vm *VM) useStandaloneDatabase(acceptedDB avalanchedatabase.Database) (bool, error) { + // no config provided, use default + standaloneDBFlag := vm.config.UseStandaloneDatabase + if standaloneDBFlag != nil { + return standaloneDBFlag.Bool(), nil + } + + // check if the chain can use a standalone database + _, err := acceptedDB.Get(lastAcceptedKey) + if err == avalanchedatabase.ErrNotFound { + // If there is nothing in the database, we can use the standalone database + return true, nil + } + return false, err +} + +// getDatabaseConfig returns the database configuration for the chain +// to be used by separate, standalone database. +func getDatabaseConfig(config Config, chainDataDir string) (node.DatabaseConfig, error) { + var ( + configBytes []byte + err error + ) + if len(config.DatabaseConfigContent) != 0 { + dbConfigContent := config.DatabaseConfigContent + configBytes, err = base64.StdEncoding.DecodeString(dbConfigContent) + if err != nil { + return node.DatabaseConfig{}, fmt.Errorf("unable to decode base64 content: %w", err) + } + } else if len(config.DatabaseConfigFile) != 0 { + configPath := config.DatabaseConfigFile + configBytes, err = os.ReadFile(configPath) + if err != nil { + return node.DatabaseConfig{}, err + } + } + + dbPath := filepath.Join(chainDataDir, "db") + if len(config.DatabasePath) != 0 { + dbPath = config.DatabasePath + } + + return node.DatabaseConfig{ + Name: config.DatabaseType, + ReadOnly: config.DatabaseReadOnly, + Path: dbPath, + Config: configBytes, + }, nil +} + +func inspectDB(db avalanchedatabase.Database, label string) error { + it := db.NewIterator() + defer it.Release() + + var ( + count int64 + start = time.Now() + logged = time.Now() + + // Totals + total common.StorageSize + ) + // Inspect key-value database first. + for it.Next() { + var ( + key = it.Key() + size = common.StorageSize(len(key) + len(it.Value())) + ) + total += size + count++ + if count%1000 == 0 && time.Since(logged) > 8*time.Second { + log.Info("Inspecting database", "label", label, "count", count, "elapsed", common.PrettyDuration(time.Since(start))) + logged = time.Now() + } + } + // Display the database statistic. + log.Info("Database statistics", "label", label, "total", total.String(), "count", count) + return nil +} diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 05fff2002e..e841108d6b 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -17,10 +17,11 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/api/keystore" @@ -33,14 +34,12 @@ import ( "github.com/ava-labs/avalanchego/snow/consensus/snowman" commonEng "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/snow/engine/enginetest" - "github.com/ava-labs/avalanchego/snow/validators/validatorstest" "github.com/ava-labs/avalanchego/upgrade" - avalancheConstants "github.com/ava-labs/avalanchego/utils/constants" - "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/formatting" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/vms/components/chain" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/constants" @@ -56,22 +55,18 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contracts/rewardmanager" "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ava-labs/subnet-evm/trie" "github.com/ava-labs/subnet-evm/utils" "github.com/ava-labs/subnet-evm/vmerrs" avagoconstants "github.com/ava-labs/avalanchego/utils/constants" - avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" ) var ( - testNetworkID uint32 = avagoconstants.UnitTestID - testCChainID = ids.ID{'c', 'c', 'h', 'a', 'i', 'n', 't', 'e', 's', 't'} - testXChainID = ids.ID{'t', 'e', 's', 't', 'x'} - testMinGasPrice int64 = 225_000_000_000 + testNetworkID uint32 = avagoconstants.UnitTestID + + testMinGasPrice int64 = 225_000_000_000 testKeys []*ecdsa.PrivateKey testEthAddrs []common.Address // testEthAddrs[i] corresponds to testKeys[i] - testAvaxAssetID = ids.ID{1, 2, 3} username = "Johns" password = "CjasdjhiPeirbSenfeI13" // #nosec G101 @@ -137,40 +132,6 @@ func buildGenesisTest(t *testing.T, genesisJSON string) []byte { return genesisBytes } -func NewContext() *snow.Context { - ctx := utils.TestSnowContext() - ctx.NodeID = ids.GenerateTestNodeID() - ctx.NetworkID = testNetworkID - ctx.ChainID = testCChainID - ctx.AVAXAssetID = testAvaxAssetID - ctx.XChainID = testXChainID - aliaser := ctx.BCLookup.(ids.Aliaser) - _ = aliaser.Alias(testCChainID, "C") - _ = aliaser.Alias(testCChainID, testCChainID.String()) - _ = aliaser.Alias(testXChainID, "X") - _ = aliaser.Alias(testXChainID, testXChainID.String()) - ctx.ValidatorState = &validatorstest.State{ - GetSubnetIDF: func(_ context.Context, chainID ids.ID) (ids.ID, error) { - subnetID, ok := map[ids.ID]ids.ID{ - avalancheConstants.PlatformChainID: avalancheConstants.PrimaryNetworkID, - testXChainID: avalancheConstants.PrimaryNetworkID, - testCChainID: avalancheConstants.PrimaryNetworkID, - }[chainID] - if !ok { - return ids.Empty, errors.New("unknown chain") - } - return subnetID, nil - }, - } - blsSecretKey, err := bls.NewSecretKey() - if err != nil { - panic(err) - } - ctx.WarpSigner = avalancheWarp.NewSigner(blsSecretKey, ctx.NetworkID, ctx.ChainID) - ctx.PublicKey = bls.PublicFromSecretKey(blsSecretKey) - return ctx -} - // setupGenesis sets up the genesis // If [genesisJSON] is empty, defaults to using [genesisJSONLatest] func setupGenesis( @@ -186,7 +147,7 @@ func setupGenesis( genesisJSON = genesisJSONLatest } genesisBytes := buildGenesisTest(t, genesisJSON) - ctx := NewContext() + ctx := utils.TestSnowContext() baseDB := memdb.New() @@ -492,7 +453,7 @@ func TestBuildEthTxBlock(t *testing.T) { if err := restartedVM.Initialize( context.Background(), - NewContext(), + utils.TestSnowContext(), dbManager, genesisBytes, []byte(""), @@ -1957,7 +1918,7 @@ func TestConfigureLogLevel(t *testing.T) { } } - // If the VM was not initialized, do not attept to shut it down + // If the VM was not initialized, do not attempt to shut it down if err == nil { shutdownChan := make(chan error, 1) shutdownFunc := func() { @@ -3151,3 +3112,64 @@ func TestParentBeaconRootBlock(t *testing.T) { }) } } + +func TestStandaloneDB(t *testing.T) { + vm := &VM{} + ctx := utils.TestSnowContext() + baseDB := memdb.New() + atomicMemory := atomic.NewMemory(prefixdb.New([]byte{0}, baseDB)) + ctx.SharedMemory = atomicMemory.NewSharedMemory(ctx.ChainID) + issuer := make(chan commonEng.Message, 1) + sharedDB := prefixdb.New([]byte{1}, baseDB) + genesisBytes := buildGenesisTest(t, genesisJSONLatest) + // alter network ID to use standalone database + ctx.NetworkID = 123456 + appSender := &enginetest.Sender{T: t} + appSender.CantSendAppGossip = true + appSender.SendAppGossipF = func(context.Context, commonEng.SendConfig, []byte) error { return nil } + configJSON := `{"database-type": "memdb"}` + + isDBEmpty := func(db database.Database) bool { + it := db.NewIterator() + defer it.Release() + return !it.Next() + } + // Ensure that the database is empty + require.True(t, isDBEmpty(baseDB)) + + err := vm.Initialize( + context.Background(), + ctx, + sharedDB, + genesisBytes, + nil, + []byte(configJSON), + issuer, + []*commonEng.Fx{}, + appSender, + ) + defer vm.Shutdown(context.Background()) + require.NoError(t, err, "error initializing VM") + require.NoError(t, vm.SetState(context.Background(), snow.Bootstrapping)) + require.NoError(t, vm.SetState(context.Background(), snow.NormalOp)) + + // Issue a block + acceptedBlockEvent := make(chan core.ChainEvent, 1) + vm.blockChain.SubscribeChainAcceptedEvent(acceptedBlockEvent) + tx0 := types.NewTransaction(uint64(0), testEthAddrs[0], big.NewInt(1), 21000, big.NewInt(testMinGasPrice), nil) + signedTx0, err := types.SignTx(tx0, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0]) + require.NoError(t, err) + errs := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx0}) + require.NoError(t, errs[0]) + + // accept block + blk := issueAndAccept(t, issuer, vm) + newBlock := <-acceptedBlockEvent + require.Equal(t, newBlock.Block.Hash(), common.Hash(blk.ID())) + + // Ensure that the shared database is empty + assert.True(t, isDBEmpty(baseDB)) + // Ensure that the standalone database is not empty + assert.False(t, isDBEmpty(vm.db)) + assert.False(t, isDBEmpty(vm.acceptedBlockDB)) +} diff --git a/plugin/evm/vm_upgrade_bytes_test.go b/plugin/evm/vm_upgrade_bytes_test.go index 8553b7d7e0..5be09998ba 100644 --- a/plugin/evm/vm_upgrade_bytes_test.go +++ b/plugin/evm/vm_upgrade_bytes_test.go @@ -17,6 +17,10 @@ import ( "github.com/ava-labs/avalanchego/snow/engine/enginetest" "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/avalanchego/vms/components/chain" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/metrics" @@ -24,10 +28,6 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" "github.com/ava-labs/subnet-evm/utils" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" "github.com/holiman/uint256" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -111,6 +111,9 @@ func TestVMUpgradeBytesPrecompile(t *testing.T) { } }() // Set the VM's state to NormalOp to initialize the tx pool. + if err := vm.SetState(context.Background(), snow.Bootstrapping); err != nil { + t.Fatal(err) + } if err := vm.SetState(context.Background(), snow.NormalOp); err != nil { t.Fatal(err) } diff --git a/plugin/evm/vm_validators_test.go b/plugin/evm/vm_validators_test.go new file mode 100644 index 0000000000..d8d0719fde --- /dev/null +++ b/plugin/evm/vm_validators_test.go @@ -0,0 +1,161 @@ +// See the file LICENSE for licensing terms. + +package evm + +import ( + "context" + "testing" + "time" + + "github.com/ava-labs/avalanchego/database" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" + commonEng "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/avalanchego/snow/engine/enginetest" + avagovalidators "github.com/ava-labs/avalanchego/snow/validators" + "github.com/ava-labs/avalanchego/snow/validators/validatorstest" + "github.com/ava-labs/subnet-evm/core" + "github.com/ava-labs/subnet-evm/plugin/evm/validators" + "github.com/ava-labs/subnet-evm/utils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidatorState(t *testing.T) { + require := require.New(t) + genesis := &core.Genesis{} + require.NoError(genesis.UnmarshalJSON([]byte(genesisJSONLatest))) + genesisJSON, err := genesis.MarshalJSON() + require.NoError(err) + + vm := &VM{} + ctx, dbManager, genesisBytes, issuer, _ := setupGenesis(t, string(genesisJSON)) + appSender := &enginetest.Sender{T: t} + appSender.CantSendAppGossip = true + testNodeIDs := []ids.NodeID{ + ids.GenerateTestNodeID(), + ids.GenerateTestNodeID(), + ids.GenerateTestNodeID(), + } + testValidationIDs := []ids.ID{ + ids.GenerateTestID(), + ids.GenerateTestID(), + ids.GenerateTestID(), + } + ctx.ValidatorState = &validatorstest.State{ + GetCurrentValidatorSetF: func(ctx context.Context, subnetID ids.ID) (map[ids.ID]*avagovalidators.GetCurrentValidatorOutput, uint64, error) { + return map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[0], + PublicKey: nil, + Weight: 1, + }, + testValidationIDs[1]: { + NodeID: testNodeIDs[1], + PublicKey: nil, + Weight: 1, + }, + testValidationIDs[2]: { + NodeID: testNodeIDs[2], + PublicKey: nil, + Weight: 1, + }, + }, 0, nil + }, + } + appSender.SendAppGossipF = func(context.Context, commonEng.SendConfig, []byte) error { return nil } + err = vm.Initialize( + context.Background(), + ctx, + dbManager, + genesisBytes, + []byte(""), + []byte(""), + issuer, + []*commonEng.Fx{}, + appSender, + ) + require.NoError(err, "error initializing GenesisVM") + + // Test case 1: state should not be populated until bootstrapped + require.NoError(vm.SetState(context.Background(), snow.Bootstrapping)) + require.Equal(0, vm.validatorsManager.GetValidationIDs().Len()) + _, _, err = vm.validatorsManager.CalculateUptime(testNodeIDs[0]) + require.ErrorIs(database.ErrNotFound, err) + require.False(vm.validatorsManager.StartedTracking()) + + // Test case 2: state should be populated after bootstrapped + require.NoError(vm.SetState(context.Background(), snow.NormalOp)) + require.Len(vm.validatorsManager.GetValidationIDs(), 3) + _, _, err = vm.validatorsManager.CalculateUptime(testNodeIDs[0]) + require.NoError(err) + require.True(vm.validatorsManager.StartedTracking()) + + // Test case 3: restarting VM should not lose state + vm.Shutdown(context.Background()) + // Shutdown should stop tracking + require.False(vm.validatorsManager.StartedTracking()) + + vm = &VM{} + err = vm.Initialize( + context.Background(), + utils.TestSnowContext(), // this context does not have validators state, making VM to source it from the database + dbManager, + genesisBytes, + []byte(""), + []byte(""), + issuer, + []*commonEng.Fx{}, + appSender, + ) + require.NoError(err, "error initializing GenesisVM") + require.Len(vm.validatorsManager.GetValidationIDs(), 3) + _, _, err = vm.validatorsManager.CalculateUptime(testNodeIDs[0]) + require.NoError(err) + require.False(vm.validatorsManager.StartedTracking()) + + // Test case 4: new validators should be added to the state + newValidationID := ids.GenerateTestID() + newNodeID := ids.GenerateTestNodeID() + testState := &validatorstest.State{ + GetCurrentValidatorSetF: func(ctx context.Context, subnetID ids.ID) (map[ids.ID]*avagovalidators.GetCurrentValidatorOutput, uint64, error) { + return map[ids.ID]*avagovalidators.GetCurrentValidatorOutput{ + testValidationIDs[0]: { + NodeID: testNodeIDs[0], + PublicKey: nil, + Weight: 1, + }, + testValidationIDs[1]: { + NodeID: testNodeIDs[1], + PublicKey: nil, + Weight: 1, + }, + testValidationIDs[2]: { + NodeID: testNodeIDs[2], + PublicKey: nil, + Weight: 1, + }, + newValidationID: { + NodeID: newNodeID, + PublicKey: nil, + Weight: 1, + }, + }, 0, nil + }, + } + // set VM as bootstrapped + require.NoError(vm.SetState(context.Background(), snow.Bootstrapping)) + require.NoError(vm.SetState(context.Background(), snow.NormalOp)) + + vm.ctx.ValidatorState = testState + + // new validator should be added to the state eventually after SyncFrequency + require.EventuallyWithT(func(c *assert.CollectT) { + vm.ctx.Lock.Lock() + defer vm.ctx.Lock.Unlock() + assert.Len(c, vm.validatorsManager.GetNodeIDs(), 4) + newValidator, err := vm.validatorsManager.GetValidator(newValidationID) + assert.NoError(c, err) + assert.Equal(c, newNodeID, newValidator.NodeID) + }, validators.SyncFrequency*2, 5*time.Second) +} diff --git a/plugin/evm/vm_warp_test.go b/plugin/evm/vm_warp_test.go index 71ff262423..777d52ce6c 100644 --- a/plugin/evm/vm_warp_test.go +++ b/plugin/evm/vm_warp_test.go @@ -26,6 +26,8 @@ import ( "github.com/ava-labs/avalanchego/vms/components/chain" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" @@ -37,8 +39,6 @@ import ( "github.com/ava-labs/subnet-evm/predicate" "github.com/ava-labs/subnet-evm/utils" "github.com/ava-labs/subnet-evm/warp" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) @@ -280,16 +280,16 @@ func testWarpVMTransaction(t *testing.T, unsignedMessage *avalancheWarp.Unsigned defer logsSub.Unsubscribe() nodeID1 := ids.GenerateTestNodeID() - blsSecretKey1, err := bls.NewSecretKey() + blsSecretKey1, err := bls.NewSigner() require.NoError(err) - blsPublicKey1 := bls.PublicFromSecretKey(blsSecretKey1) - blsSignature1 := bls.Sign(blsSecretKey1, unsignedMessage.Bytes()) + blsPublicKey1 := blsSecretKey1.PublicKey() + blsSignature1 := blsSecretKey1.Sign(unsignedMessage.Bytes()) nodeID2 := ids.GenerateTestNodeID() - blsSecretKey2, err := bls.NewSecretKey() + blsSecretKey2, err := bls.NewSigner() require.NoError(err) - blsPublicKey2 := bls.PublicFromSecretKey(blsSecretKey2) - blsSignature2 := bls.Sign(blsSecretKey2, unsignedMessage.Bytes()) + blsPublicKey2 := blsSecretKey2.PublicKey() + blsSignature2 := blsSecretKey2.Sign(unsignedMessage.Bytes()) blsAggregatedSignature, err := bls.AggregateSignatures([]*bls.Signature{blsSignature1, blsSignature2}) require.NoError(err) @@ -481,7 +481,7 @@ func TestReceiveWarpMessage(t *testing.T) { }, { name: "C-Chain message should be signed by subnet without RequirePrimaryNetworkSigners", - sourceChainID: testCChainID, + sourceChainID: vm.ctx.CChainID, msgFrom: fromPrimary, useSigners: signersSubnet, blockTime: upgrade.InitiallyActiveTime.Add(2 * blockGap), @@ -504,7 +504,7 @@ func TestReceiveWarpMessage(t *testing.T) { }, { name: "C-Chain message should be signed by primary with RequirePrimaryNetworkSigners (impacted)", - sourceChainID: testCChainID, + sourceChainID: vm.ctx.CChainID, msgFrom: fromPrimary, useSigners: signersPrimary, blockTime: reEnableTime.Add(2 * blockGap), @@ -545,18 +545,18 @@ func testReceiveWarpMessage( type signer struct { networkID ids.ID nodeID ids.NodeID - secret *bls.SecretKey + secret bls.Signer signature *bls.Signature weight uint64 } newSigner := func(networkID ids.ID, weight uint64) signer { - secret, err := bls.NewSecretKey() + secret, err := bls.NewSigner() require.NoError(err) return signer{ networkID: networkID, nodeID: ids.GenerateTestNodeID(), secret: secret, - signature: bls.Sign(secret, unsignedMessage.Bytes()), + signature: secret.Sign(unsignedMessage.Bytes()), weight: weight, } } @@ -604,7 +604,7 @@ func testReceiveWarpMessage( for _, s := range signers { vdrOutput[s.nodeID] = &validators.GetValidatorOutput{ NodeID: s.nodeID, - PublicKey: bls.PublicFromSecretKey(s.secret), + PublicKey: s.secret.PublicKey(), Weight: s.weight, } } diff --git a/precompile/allowlist/allowlist.go b/precompile/allowlist/allowlist.go index 96abdb7208..81fc965ff0 100644 --- a/precompile/allowlist/allowlist.go +++ b/precompile/allowlist/allowlist.go @@ -9,9 +9,9 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" ) // AllowList is an abstraction that allows other precompiles to manage diff --git a/precompile/allowlist/allowlist_test.go b/precompile/allowlist/allowlist_test.go index b7b4ca480a..a35c6f0477 100644 --- a/precompile/allowlist/allowlist_test.go +++ b/precompile/allowlist/allowlist_test.go @@ -6,12 +6,12 @@ package allowlist_test import ( "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/extstate" . "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" ) var ( diff --git a/precompile/allowlist/config.go b/precompile/allowlist/config.go index 520021f511..3b147019ee 100644 --- a/precompile/allowlist/config.go +++ b/precompile/allowlist/config.go @@ -6,9 +6,9 @@ package allowlist import ( "fmt" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" ) var ErrCannotAddManagersBeforeDurango = fmt.Errorf("cannot add managers before Durango") diff --git a/precompile/allowlist/event.go b/precompile/allowlist/event.go index 8c0f3e44f3..f51cb274bb 100644 --- a/precompile/allowlist/event.go +++ b/precompile/allowlist/event.go @@ -7,8 +7,8 @@ package allowlist import ( "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" ) const ( diff --git a/precompile/allowlist/role.go b/precompile/allowlist/role.go index 4cd55dcd3d..1d785c7647 100644 --- a/precompile/allowlist/role.go +++ b/precompile/allowlist/role.go @@ -7,7 +7,7 @@ import ( "errors" "math/big" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) // 1. NoRole - this is equivalent to common.Hash{} and deletes the key from the DB when set diff --git a/precompile/allowlist/test_allowlist.go b/precompile/allowlist/test_allowlist.go index 48e81f18fd..21d3951165 100644 --- a/precompile/allowlist/test_allowlist.go +++ b/precompile/allowlist/test_allowlist.go @@ -6,12 +6,12 @@ package allowlist import ( "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" ) diff --git a/precompile/allowlist/test_allowlist_config.go b/precompile/allowlist/test_allowlist_config.go index 27c649f520..244e6f3fca 100644 --- a/precompile/allowlist/test_allowlist_config.go +++ b/precompile/allowlist/test_allowlist_config.go @@ -7,11 +7,11 @@ import ( "encoding/json" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" "go.uber.org/mock/gomock" ) diff --git a/precompile/allowlist/unpack_pack_test.go b/precompile/allowlist/unpack_pack_test.go index 5d39c35d86..10498da47c 100644 --- a/precompile/allowlist/unpack_pack_test.go +++ b/precompile/allowlist/unpack_pack_test.go @@ -7,9 +7,9 @@ import ( "fmt" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) diff --git a/precompile/contract/contract.go b/precompile/contract/contract.go index 0be76a8955..b64c8058dc 100644 --- a/precompile/contract/contract.go +++ b/precompile/contract/contract.go @@ -6,7 +6,7 @@ package contract import ( "fmt" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) const ( diff --git a/precompile/contract/interfaces.go b/precompile/contract/interfaces.go index 54dbd3fb28..a4174fb5a4 100644 --- a/precompile/contract/interfaces.go +++ b/precompile/contract/interfaces.go @@ -8,13 +8,13 @@ import ( "math/big" "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/libevm/common" + ethtypes "github.com/ava-labs/libevm/core/types" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" - gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/holiman/uint256" ) -type Log = gethtypes.Log +type Log = ethtypes.Log // StatefulPrecompiledContract is the interface for executing a precompiled contract type StatefulPrecompiledContract interface { @@ -67,7 +67,7 @@ type ConfigurationBlockContext interface { type BlockContext interface { ConfigurationBlockContext - // GetPredicateResults returns a the result of verifying the predicates of the + // GetPredicateResults returns the result of verifying the predicates of the // given transaction, precompile address pair as a byte array. GetPredicateResults(txHash common.Hash, precompileAddress common.Address) []byte } diff --git a/precompile/contract/mocks.go b/precompile/contract/mocks.go index 707dec44bc..eb8d371e75 100644 --- a/precompile/contract/mocks.go +++ b/precompile/contract/mocks.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -package=contract -destination=precompile/contract/mocks.go github.com/ava-labs/subnet-evm/precompile/contract BlockContext,AccessibleState,StateDB +// mockgen -package=contract -destination=mocks.go . BlockContext,AccessibleState,StateDB // // Package contract is a generated GoMock package. @@ -14,9 +14,9 @@ import ( reflect "reflect" snow "github.com/ava-labs/avalanchego/snow" + common "github.com/ava-labs/libevm/common" + types "github.com/ava-labs/libevm/core/types" precompileconfig "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - common "github.com/ethereum/go-ethereum/common" - types "github.com/ethereum/go-ethereum/core/types" uint256 "github.com/holiman/uint256" gomock "go.uber.org/mock/gomock" ) @@ -25,6 +25,7 @@ import ( type MockBlockContext struct { ctrl *gomock.Controller recorder *MockBlockContextMockRecorder + isgomock struct{} } // MockBlockContextMockRecorder is the mock recorder for MockBlockContext. @@ -45,17 +46,17 @@ func (m *MockBlockContext) EXPECT() *MockBlockContextMockRecorder { } // GetPredicateResults mocks base method. -func (m *MockBlockContext) GetPredicateResults(arg0 common.Hash, arg1 common.Address) []byte { +func (m *MockBlockContext) GetPredicateResults(txHash common.Hash, precompileAddress common.Address) []byte { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPredicateResults", arg0, arg1) + ret := m.ctrl.Call(m, "GetPredicateResults", txHash, precompileAddress) ret0, _ := ret[0].([]byte) return ret0 } // GetPredicateResults indicates an expected call of GetPredicateResults. -func (mr *MockBlockContextMockRecorder) GetPredicateResults(arg0, arg1 any) *gomock.Call { +func (mr *MockBlockContextMockRecorder) GetPredicateResults(txHash, precompileAddress any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPredicateResults", reflect.TypeOf((*MockBlockContext)(nil).GetPredicateResults), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPredicateResults", reflect.TypeOf((*MockBlockContext)(nil).GetPredicateResults), txHash, precompileAddress) } // Number mocks base method. @@ -90,6 +91,7 @@ func (mr *MockBlockContextMockRecorder) Timestamp() *gomock.Call { type MockAccessibleState struct { ctrl *gomock.Controller recorder *MockAccessibleStateMockRecorder + isgomock struct{} } // MockAccessibleStateMockRecorder is the mock recorder for MockAccessibleState. @@ -169,6 +171,7 @@ func (mr *MockAccessibleStateMockRecorder) GetStateDB() *gomock.Call { type MockStateDB struct { ctrl *gomock.Controller recorder *MockStateDBMockRecorder + isgomock struct{} } // MockStateDBMockRecorder is the mock recorder for MockStateDB. @@ -282,18 +285,18 @@ func (mr *MockStateDBMockRecorder) GetNonce(arg0 any) *gomock.Call { } // GetPredicateStorageSlots mocks base method. -func (m *MockStateDB) GetPredicateStorageSlots(arg0 common.Address, arg1 int) ([]byte, bool) { +func (m *MockStateDB) GetPredicateStorageSlots(address common.Address, index int) ([]byte, bool) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPredicateStorageSlots", arg0, arg1) + ret := m.ctrl.Call(m, "GetPredicateStorageSlots", address, index) ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(bool) return ret0, ret1 } // GetPredicateStorageSlots indicates an expected call of GetPredicateStorageSlots. -func (mr *MockStateDBMockRecorder) GetPredicateStorageSlots(arg0, arg1 any) *gomock.Call { +func (mr *MockStateDBMockRecorder) GetPredicateStorageSlots(address, index any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPredicateStorageSlots", reflect.TypeOf((*MockStateDB)(nil).GetPredicateStorageSlots), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPredicateStorageSlots", reflect.TypeOf((*MockStateDB)(nil).GetPredicateStorageSlots), address, index) } // GetState mocks base method. @@ -349,15 +352,15 @@ func (mr *MockStateDBMockRecorder) SetNonce(arg0, arg1 any) *gomock.Call { } // SetPredicateStorageSlots mocks base method. -func (m *MockStateDB) SetPredicateStorageSlots(arg0 common.Address, arg1 [][]byte) { +func (m *MockStateDB) SetPredicateStorageSlots(address common.Address, predicates [][]byte) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetPredicateStorageSlots", arg0, arg1) + m.ctrl.Call(m, "SetPredicateStorageSlots", address, predicates) } // SetPredicateStorageSlots indicates an expected call of SetPredicateStorageSlots. -func (mr *MockStateDBMockRecorder) SetPredicateStorageSlots(arg0, arg1 any) *gomock.Call { +func (mr *MockStateDBMockRecorder) SetPredicateStorageSlots(address, predicates any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPredicateStorageSlots", reflect.TypeOf((*MockStateDB)(nil).SetPredicateStorageSlots), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPredicateStorageSlots", reflect.TypeOf((*MockStateDB)(nil).SetPredicateStorageSlots), address, predicates) } // SetState mocks base method. diff --git a/precompile/contract/mocks_generate_test.go b/precompile/contract/mocks_generate_test.go new file mode 100644 index 0000000000..4903b47c7c --- /dev/null +++ b/precompile/contract/mocks_generate_test.go @@ -0,0 +1,3 @@ +package contract + +//go:generate go run go.uber.org/mock/mockgen -package=$GOPACKAGE -destination=mocks.go . BlockContext,AccessibleState,StateDB diff --git a/precompile/contract/test_utils.go b/precompile/contract/test_utils.go index cf38b5db77..bc4b25e5ba 100644 --- a/precompile/contract/test_utils.go +++ b/precompile/contract/test_utils.go @@ -6,7 +6,7 @@ package contract import ( "fmt" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) // PackOrderedHashesWithSelector packs the function selector and ordered list of hashes into [dst] diff --git a/precompile/contract/utils.go b/precompile/contract/utils.go index 4b7eff94bb..5a8fb39c40 100644 --- a/precompile/contract/utils.go +++ b/precompile/contract/utils.go @@ -8,9 +8,9 @@ import ( "regexp" "strings" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/crypto" ) // Gas costs for stateful precompiles diff --git a/precompile/contracts/deployerallowlist/config.go b/precompile/contracts/deployerallowlist/config.go index a588101dc3..79527d3dd5 100644 --- a/precompile/contracts/deployerallowlist/config.go +++ b/precompile/contracts/deployerallowlist/config.go @@ -4,9 +4,9 @@ package deployerallowlist import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" ) var _ precompileconfig.Config = &Config{} diff --git a/precompile/contracts/deployerallowlist/config_test.go b/precompile/contracts/deployerallowlist/config_test.go index f0ad2bddf7..09ed5a9b9d 100644 --- a/precompile/contracts/deployerallowlist/config_test.go +++ b/precompile/contracts/deployerallowlist/config_test.go @@ -6,11 +6,11 @@ package deployerallowlist import ( "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" "go.uber.org/mock/gomock" ) diff --git a/precompile/contracts/deployerallowlist/contract.go b/precompile/contracts/deployerallowlist/contract.go index 6ec66c1a0d..7770db78c9 100644 --- a/precompile/contracts/deployerallowlist/contract.go +++ b/precompile/contracts/deployerallowlist/contract.go @@ -4,9 +4,9 @@ package deployerallowlist import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" ) // Singleton StatefulPrecompiledContract for W/R access to the contract deployer allow list. diff --git a/precompile/contracts/deployerallowlist/module.go b/precompile/contracts/deployerallowlist/module.go index 17f7431ab0..055f65c0f6 100644 --- a/precompile/contracts/deployerallowlist/module.go +++ b/precompile/contracts/deployerallowlist/module.go @@ -6,10 +6,10 @@ package deployerallowlist import ( "fmt" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" ) var _ contract.Configurator = &configurator{} diff --git a/precompile/contracts/feemanager/config.go b/precompile/contracts/feemanager/config.go index 9dcfc307d2..258512fe25 100644 --- a/precompile/contracts/feemanager/config.go +++ b/precompile/contracts/feemanager/config.go @@ -4,10 +4,10 @@ package feemanager import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" ) var _ precompileconfig.Config = &Config{} diff --git a/precompile/contracts/feemanager/config_test.go b/precompile/contracts/feemanager/config_test.go index 4182ec4716..9e1262d608 100644 --- a/precompile/contracts/feemanager/config_test.go +++ b/precompile/contracts/feemanager/config_test.go @@ -7,12 +7,12 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" "go.uber.org/mock/gomock" ) diff --git a/precompile/contracts/feemanager/contract.go b/precompile/contracts/feemanager/contract.go index 10cd6d2d17..ac46e568ef 100644 --- a/precompile/contracts/feemanager/contract.go +++ b/precompile/contracts/feemanager/contract.go @@ -9,12 +9,12 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" ) const ( diff --git a/precompile/contracts/feemanager/contract_test.go b/precompile/contracts/feemanager/contract_test.go index 62011186b3..01382383be 100644 --- a/precompile/contracts/feemanager/contract_test.go +++ b/precompile/contracts/feemanager/contract_test.go @@ -7,6 +7,7 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/core/extstate" "github.com/ava-labs/subnet-evm/precompile/allowlist" @@ -14,7 +15,6 @@ import ( "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" ) diff --git a/precompile/contracts/feemanager/event.go b/precompile/contracts/feemanager/event.go index f9ba375b51..d7628f4b67 100644 --- a/precompile/contracts/feemanager/event.go +++ b/precompile/contracts/feemanager/event.go @@ -7,9 +7,9 @@ package feemanager import ( "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" ) // FeeConfigChangedEventGasCost is the gas cost of a FeeConfigChanged event. diff --git a/precompile/contracts/feemanager/module.go b/precompile/contracts/feemanager/module.go index e67e5e1115..5348b36852 100644 --- a/precompile/contracts/feemanager/module.go +++ b/precompile/contracts/feemanager/module.go @@ -6,10 +6,10 @@ package feemanager import ( "fmt" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" ) var _ contract.Configurator = &configurator{} diff --git a/precompile/contracts/feemanager/unpack_pack_test.go b/precompile/contracts/feemanager/unpack_pack_test.go index e2afc6b3d5..be2efc852a 100644 --- a/precompile/contracts/feemanager/unpack_pack_test.go +++ b/precompile/contracts/feemanager/unpack_pack_test.go @@ -8,11 +8,11 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/stretchr/testify/require" ) diff --git a/precompile/contracts/nativeminter/config.go b/precompile/contracts/nativeminter/config.go index 38a65ee6c8..34ffe2c484 100644 --- a/precompile/contracts/nativeminter/config.go +++ b/precompile/contracts/nativeminter/config.go @@ -7,11 +7,11 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" ) var _ precompileconfig.Config = &Config{} diff --git a/precompile/contracts/nativeminter/config_test.go b/precompile/contracts/nativeminter/config_test.go index ca0a63ce4a..05f009d4a2 100644 --- a/precompile/contracts/nativeminter/config_test.go +++ b/precompile/contracts/nativeminter/config_test.go @@ -6,12 +6,12 @@ package nativeminter import ( "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "go.uber.org/mock/gomock" ) diff --git a/precompile/contracts/nativeminter/contract.go b/precompile/contracts/nativeminter/contract.go index 6ce211fbd8..b11c384f82 100644 --- a/precompile/contracts/nativeminter/contract.go +++ b/precompile/contracts/nativeminter/contract.go @@ -9,10 +9,10 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" ) diff --git a/precompile/contracts/nativeminter/contract_test.go b/precompile/contracts/nativeminter/contract_test.go index 8115e84b3c..d06cce76ec 100644 --- a/precompile/contracts/nativeminter/contract_test.go +++ b/precompile/contracts/nativeminter/contract_test.go @@ -7,14 +7,14 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" "github.com/ava-labs/subnet-evm/core/extstate" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/holiman/uint256" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" diff --git a/precompile/contracts/nativeminter/event.go b/precompile/contracts/nativeminter/event.go index b253728118..65d568a9ec 100644 --- a/precompile/contracts/nativeminter/event.go +++ b/precompile/contracts/nativeminter/event.go @@ -7,8 +7,8 @@ package nativeminter import ( "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" ) const ( diff --git a/precompile/contracts/nativeminter/module.go b/precompile/contracts/nativeminter/module.go index 02529e2432..4dbc4c8ddb 100644 --- a/precompile/contracts/nativeminter/module.go +++ b/precompile/contracts/nativeminter/module.go @@ -7,10 +7,10 @@ import ( "fmt" "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" ) diff --git a/precompile/contracts/nativeminter/unpack_pack_test.go b/precompile/contracts/nativeminter/unpack_pack_test.go index 10b2cb8a5d..8d41482554 100644 --- a/precompile/contracts/nativeminter/unpack_pack_test.go +++ b/precompile/contracts/nativeminter/unpack_pack_test.go @@ -8,11 +8,11 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/constants" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) diff --git a/precompile/contracts/rewardmanager/config.go b/precompile/contracts/rewardmanager/config.go index 49949cac1a..93e33e5685 100644 --- a/precompile/contracts/rewardmanager/config.go +++ b/precompile/contracts/rewardmanager/config.go @@ -11,7 +11,7 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) var _ precompileconfig.Config = &Config{} diff --git a/precompile/contracts/rewardmanager/config_test.go b/precompile/contracts/rewardmanager/config_test.go index 958eb000d9..f848d80dbb 100644 --- a/precompile/contracts/rewardmanager/config_test.go +++ b/precompile/contracts/rewardmanager/config_test.go @@ -6,11 +6,11 @@ package rewardmanager import ( "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" "go.uber.org/mock/gomock" ) diff --git a/precompile/contracts/rewardmanager/contract.go b/precompile/contracts/rewardmanager/contract.go index 053a5648d1..f179b8c924 100644 --- a/precompile/contracts/rewardmanager/contract.go +++ b/precompile/contracts/rewardmanager/contract.go @@ -17,7 +17,7 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) const ( diff --git a/precompile/contracts/rewardmanager/contract_test.go b/precompile/contracts/rewardmanager/contract_test.go index 0a8e74dedb..a6dceb8ec1 100644 --- a/precompile/contracts/rewardmanager/contract_test.go +++ b/precompile/contracts/rewardmanager/contract_test.go @@ -6,7 +6,7 @@ package rewardmanager import ( "testing" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" diff --git a/precompile/contracts/rewardmanager/event.go b/precompile/contracts/rewardmanager/event.go index 1bfa891682..05c25f6468 100644 --- a/precompile/contracts/rewardmanager/event.go +++ b/precompile/contracts/rewardmanager/event.go @@ -5,8 +5,8 @@ package rewardmanager import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" ) const ( diff --git a/precompile/contracts/rewardmanager/module.go b/precompile/contracts/rewardmanager/module.go index 272547c212..bd445fcc27 100644 --- a/precompile/contracts/rewardmanager/module.go +++ b/precompile/contracts/rewardmanager/module.go @@ -10,7 +10,7 @@ import ( "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) var _ contract.Configurator = &configurator{} diff --git a/precompile/contracts/txallowlist/config.go b/precompile/contracts/txallowlist/config.go index f5656d9c78..26360b168d 100644 --- a/precompile/contracts/txallowlist/config.go +++ b/precompile/contracts/txallowlist/config.go @@ -4,9 +4,9 @@ package txallowlist import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" ) var _ precompileconfig.Config = &Config{} diff --git a/precompile/contracts/txallowlist/config_test.go b/precompile/contracts/txallowlist/config_test.go index 29010ce8af..8d97eff584 100644 --- a/precompile/contracts/txallowlist/config_test.go +++ b/precompile/contracts/txallowlist/config_test.go @@ -6,11 +6,11 @@ package txallowlist import ( "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" "go.uber.org/mock/gomock" ) diff --git a/precompile/contracts/txallowlist/contract.go b/precompile/contracts/txallowlist/contract.go index 63926c4225..6a839e4b9e 100644 --- a/precompile/contracts/txallowlist/contract.go +++ b/precompile/contracts/txallowlist/contract.go @@ -4,9 +4,9 @@ package txallowlist import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" ) // Singleton StatefulPrecompiledContract for W/R access to the tx allow list. diff --git a/precompile/contracts/txallowlist/module.go b/precompile/contracts/txallowlist/module.go index f7333613c7..3b474a0f7c 100644 --- a/precompile/contracts/txallowlist/module.go +++ b/precompile/contracts/txallowlist/module.go @@ -6,10 +6,10 @@ package txallowlist import ( "fmt" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" ) var _ contract.Configurator = &configurator{} diff --git a/precompile/contracts/warp/README.md b/precompile/contracts/warp/README.md index 0e43769753..5886f623aa 100644 --- a/precompile/contracts/warp/README.md +++ b/precompile/contracts/warp/README.md @@ -57,7 +57,7 @@ To use this function, the transaction must include the signed Avalanche Warp Mes This leads to the following advantages: 1. The EVM execution does not need to verify the Warp Message at runtime (no signature verification or external calls to the P-Chain) -2. The EVM can deterministically re-execute and re-verify blocks assuming the predicate was verified by the network (eg., in bootstrapping) +2. The EVM can deterministically re-execute and re-verify blocks assuming the predicate was verified by the network (e.g., in bootstrapping) This pre-verification is performed using the ProposerVM Block header during [block verification](../../../plugin/evm/block.go#L220) and [block building](../../../miner/worker.go#L200). diff --git a/precompile/contracts/warp/config.go b/precompile/contracts/warp/config.go index bacfc9a2f1..67ee7ee97b 100644 --- a/precompile/contracts/warp/config.go +++ b/precompile/contracts/warp/config.go @@ -10,12 +10,12 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/predicate" warpValidators "github.com/ava-labs/subnet-evm/warp/validators" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/log" ) const ( diff --git a/precompile/contracts/warp/contract.go b/precompile/contracts/warp/contract.go index 4a4fffba09..bf1236b8a4 100644 --- a/precompile/contracts/warp/contract.go +++ b/precompile/contracts/warp/contract.go @@ -15,8 +15,8 @@ import ( _ "embed" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" ) const ( diff --git a/precompile/contracts/warp/contract_test.go b/precompile/contracts/warp/contract_test.go index c5d6920666..4738c2d1ed 100644 --- a/precompile/contracts/warp/contract_test.go +++ b/precompile/contracts/warp/contract_test.go @@ -13,13 +13,13 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/extstate" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/testutils" "github.com/ava-labs/subnet-evm/predicate" "github.com/ava-labs/subnet-evm/utils" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) diff --git a/precompile/contracts/warp/contract_warp_handler.go b/precompile/contracts/warp/contract_warp_handler.go index f40eea889a..8b03f03c7c 100644 --- a/precompile/contracts/warp/contract_warp_handler.go +++ b/precompile/contracts/warp/contract_warp_handler.go @@ -9,11 +9,11 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/predicate" "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" ) var ( diff --git a/precompile/contracts/warp/module.go b/precompile/contracts/warp/module.go index 37b7451184..018075b65f 100644 --- a/precompile/contracts/warp/module.go +++ b/precompile/contracts/warp/module.go @@ -10,7 +10,7 @@ import ( "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) var _ contract.Configurator = &configurator{} diff --git a/precompile/contracts/warp/predicate_test.go b/precompile/contracts/warp/predicate_test.go index 1c7b08a7c0..65d202de09 100644 --- a/precompile/contracts/warp/predicate_test.go +++ b/precompile/contracts/warp/predicate_test.go @@ -93,7 +93,7 @@ func init() { } for _, testVdr := range testVdrs { - blsSignature := bls.Sign(testVdr.sk, unsignedMsg.Bytes()) + blsSignature := testVdr.sk.Sign(unsignedMsg.Bytes()) blsSignatures = append(blsSignatures, blsSignature) } @@ -102,7 +102,7 @@ func init() { type testValidator struct { nodeID ids.NodeID - sk *bls.SecretKey + sk bls.Signer vdr *avalancheWarp.Validator } @@ -111,13 +111,13 @@ func (v *testValidator) Compare(o *testValidator) int { } func newTestValidator() *testValidator { - sk, err := bls.NewSecretKey() + sk, err := bls.NewSigner() if err != nil { panic(err) } nodeID := ids.GenerateTestNodeID() - pk := bls.PublicFromSecretKey(sk) + pk := sk.PublicKey() return &testValidator{ nodeID: nodeID, sk: sk, @@ -240,7 +240,7 @@ func testWarpMessageFromPrimaryNetwork(t *testing.T, requirePrimaryNetworkSigner PublicKey: testVdrs[i].vdr.PublicKey, } getValidatorsOutput[testVdrs[i].nodeID] = validatorOutput - blsSignatures = append(blsSignatures, bls.Sign(testVdrs[i].sk, unsignedMsg.Bytes())) + blsSignatures = append(blsSignatures, testVdrs[i].sk.Sign(unsignedMsg.Bytes())) } aggregateSignature, err := bls.AggregateSignatures(blsSignatures) require.NoError(err) diff --git a/precompile/contracts/warp/signature_verification_test.go b/precompile/contracts/warp/signature_verification_test.go index 5b54cd29b8..d52f0a0f89 100644 --- a/precompile/contracts/warp/signature_verification_test.go +++ b/precompile/contracts/warp/signature_verification_test.go @@ -212,8 +212,8 @@ func TestSignatureVerification(t *testing.T) { signers.Add(1) unsignedBytes := unsignedMsg.Bytes() - vdr0Sig := bls.Sign(testVdrs[0].sk, unsignedBytes) - vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) + vdr0Sig := testVdrs[0].sk.Sign(unsignedBytes) + vdr1Sig := testVdrs[1].sk.Sign(unsignedBytes) aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr0Sig, vdr1Sig}) require.NoError(err) aggSigBytes := [bls.SignatureLen]byte{} @@ -284,7 +284,7 @@ func TestSignatureVerification(t *testing.T) { require.NoError(err) unsignedBytes := unsignedMsg.Bytes() - vdr0Sig := bls.Sign(testVdrs[0].sk, unsignedBytes) + vdr0Sig := testVdrs[0].sk.Sign(unsignedBytes) aggSigBytes := [bls.SignatureLen]byte{} copy(aggSigBytes[:], bls.SignatureToBytes(vdr0Sig)) @@ -323,10 +323,10 @@ func TestSignatureVerification(t *testing.T) { signers.Add(1) unsignedBytes := unsignedMsg.Bytes() - vdr0Sig := bls.Sign(testVdrs[0].sk, unsignedBytes) + vdr0Sig := testVdrs[0].sk.Sign(unsignedBytes) // Give sig from vdr[2] even though the bit vector says it // should be from vdr[1] - vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) + vdr2Sig := testVdrs[2].sk.Sign(unsignedBytes) aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr0Sig, vdr2Sig}) require.NoError(err) aggSigBytes := [bls.SignatureLen]byte{} @@ -367,7 +367,7 @@ func TestSignatureVerification(t *testing.T) { signers.Add(1) unsignedBytes := unsignedMsg.Bytes() - vdr0Sig := bls.Sign(testVdrs[0].sk, unsignedBytes) + vdr0Sig := testVdrs[0].sk.Sign(unsignedBytes) // Don't give the sig from vdr[1] aggSigBytes := [bls.SignatureLen]byte{} copy(aggSigBytes[:], bls.SignatureToBytes(vdr0Sig)) @@ -407,11 +407,11 @@ func TestSignatureVerification(t *testing.T) { signers.Add(1) unsignedBytes := unsignedMsg.Bytes() - vdr0Sig := bls.Sign(testVdrs[0].sk, unsignedBytes) - vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) + vdr0Sig := testVdrs[0].sk.Sign(unsignedBytes) + vdr1Sig := testVdrs[1].sk.Sign(unsignedBytes) // Give sig from vdr[2] even though the bit vector doesn't have // it - vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) + vdr2Sig := testVdrs[2].sk.Sign(unsignedBytes) aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr0Sig, vdr1Sig, vdr2Sig}) require.NoError(err) aggSigBytes := [bls.SignatureLen]byte{} @@ -454,8 +454,8 @@ func TestSignatureVerification(t *testing.T) { signers.Add(2) unsignedBytes := unsignedMsg.Bytes() - vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) - vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) + vdr1Sig := testVdrs[1].sk.Sign(unsignedBytes) + vdr2Sig := testVdrs[2].sk.Sign(unsignedBytes) aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr1Sig, vdr2Sig}) require.NoError(err) aggSigBytes := [bls.SignatureLen]byte{} @@ -498,8 +498,8 @@ func TestSignatureVerification(t *testing.T) { signers.Add(2) unsignedBytes := unsignedMsg.Bytes() - vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) - vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) + vdr1Sig := testVdrs[1].sk.Sign(unsignedBytes) + vdr2Sig := testVdrs[2].sk.Sign(unsignedBytes) aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr1Sig, vdr2Sig}) require.NoError(err) aggSigBytes := [bls.SignatureLen]byte{} @@ -559,8 +559,8 @@ func TestSignatureVerification(t *testing.T) { signers.Add(1) // vdr[2] unsignedBytes := unsignedMsg.Bytes() - vdr1Sig := bls.Sign(testVdrs[1].sk, unsignedBytes) - vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) + vdr1Sig := testVdrs[1].sk.Sign(unsignedBytes) + vdr2Sig := testVdrs[2].sk.Sign(unsignedBytes) aggSig, err := bls.AggregateSignatures([]*bls.Signature{vdr1Sig, vdr2Sig}) require.NoError(err) aggSigBytes := [bls.SignatureLen]byte{} @@ -621,7 +621,7 @@ func TestSignatureVerification(t *testing.T) { unsignedBytes := unsignedMsg.Bytes() // Because vdr[1] and vdr[2] share a key, only one of them sign. - vdr2Sig := bls.Sign(testVdrs[2].sk, unsignedBytes) + vdr2Sig := testVdrs[2].sk.Sign(unsignedBytes) aggSigBytes := [bls.SignatureLen]byte{} copy(aggSigBytes[:], bls.SignatureToBytes(vdr2Sig)) diff --git a/precompile/modules/module.go b/precompile/modules/module.go index d0a047c94d..f090ae185c 100644 --- a/precompile/modules/module.go +++ b/precompile/modules/module.go @@ -6,8 +6,8 @@ package modules import ( "bytes" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/precompile/contract" - "github.com/ethereum/go-ethereum/common" ) type Module struct { diff --git a/precompile/modules/registerer.go b/precompile/modules/registerer.go index 3ab469ed06..54929a8716 100644 --- a/precompile/modules/registerer.go +++ b/precompile/modules/registerer.go @@ -7,9 +7,9 @@ import ( "fmt" "sort" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/constants" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" ) var ( diff --git a/precompile/modules/registerer_test.go b/precompile/modules/registerer_test.go index c0e4feb711..b6449ebbcb 100644 --- a/precompile/modules/registerer_test.go +++ b/precompile/modules/registerer_test.go @@ -7,8 +7,8 @@ import ( "math/big" "testing" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/constants" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) diff --git a/precompile/precompileconfig/config.go b/precompile/precompileconfig/config.go index 05d204de45..b7c55ef0c1 100644 --- a/precompile/precompileconfig/config.go +++ b/precompile/precompileconfig/config.go @@ -5,13 +5,11 @@ package precompileconfig import ( - "github.com/ava-labs/avalanchego/chains/atomic" - "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/snow/engine/snowman/block" "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/commontype" - "github.com/ethereum/go-ethereum/common" ) // StatefulPrecompileConfig defines the interface for a stateful precompile to @@ -54,21 +52,14 @@ type Predicater interface { VerifyPredicate(predicateContext *PredicateContext, predicateBytes []byte) error } -// SharedMemoryWriter defines an interface to allow a precompile's Accepter to write operations -// into shared memory to be committed atomically on block accept. -type SharedMemoryWriter interface { - AddSharedMemoryRequests(chainID ids.ID, requests *atomic.Requests) -} - type WarpMessageWriter interface { AddMessage(unsignedMessage *warp.UnsignedMessage) error } // AcceptContext defines the context passed in to a precompileconfig's Accepter type AcceptContext struct { - SnowCtx *snow.Context - SharedMemory SharedMemoryWriter - Warp WarpMessageWriter + SnowCtx *snow.Context + Warp WarpMessageWriter } // Accepter is an optional interface for StatefulPrecompiledContracts to implement. diff --git a/precompile/precompileconfig/mocks.go b/precompile/precompileconfig/mocks.go index 614ec5a522..e74316ae27 100644 --- a/precompile/precompileconfig/mocks.go +++ b/precompile/precompileconfig/mocks.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -package=precompileconfig -destination=precompile/precompileconfig/mocks.go github.com/ava-labs/subnet-evm/precompile/precompileconfig Predicater,Config,ChainConfig,Accepter +// mockgen -package=precompileconfig -destination=mocks.go . Predicater,Config,ChainConfig,Accepter // // Package precompileconfig is a generated GoMock package. @@ -12,8 +12,8 @@ package precompileconfig import ( reflect "reflect" + common "github.com/ava-labs/libevm/common" commontype "github.com/ava-labs/subnet-evm/commontype" - common "github.com/ethereum/go-ethereum/common" gomock "go.uber.org/mock/gomock" ) @@ -21,6 +21,7 @@ import ( type MockPredicater struct { ctrl *gomock.Controller recorder *MockPredicaterMockRecorder + isgomock struct{} } // MockPredicaterMockRecorder is the mock recorder for MockPredicater. @@ -41,38 +42,39 @@ func (m *MockPredicater) EXPECT() *MockPredicaterMockRecorder { } // PredicateGas mocks base method. -func (m *MockPredicater) PredicateGas(arg0 []byte) (uint64, error) { +func (m *MockPredicater) PredicateGas(predicateBytes []byte) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PredicateGas", arg0) + ret := m.ctrl.Call(m, "PredicateGas", predicateBytes) ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } // PredicateGas indicates an expected call of PredicateGas. -func (mr *MockPredicaterMockRecorder) PredicateGas(arg0 any) *gomock.Call { +func (mr *MockPredicaterMockRecorder) PredicateGas(predicateBytes any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PredicateGas", reflect.TypeOf((*MockPredicater)(nil).PredicateGas), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PredicateGas", reflect.TypeOf((*MockPredicater)(nil).PredicateGas), predicateBytes) } // VerifyPredicate mocks base method. -func (m *MockPredicater) VerifyPredicate(arg0 *PredicateContext, arg1 []byte) error { +func (m *MockPredicater) VerifyPredicate(predicateContext *PredicateContext, predicateBytes []byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VerifyPredicate", arg0, arg1) + ret := m.ctrl.Call(m, "VerifyPredicate", predicateContext, predicateBytes) ret0, _ := ret[0].(error) return ret0 } // VerifyPredicate indicates an expected call of VerifyPredicate. -func (mr *MockPredicaterMockRecorder) VerifyPredicate(arg0, arg1 any) *gomock.Call { +func (mr *MockPredicaterMockRecorder) VerifyPredicate(predicateContext, predicateBytes any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VerifyPredicate", reflect.TypeOf((*MockPredicater)(nil).VerifyPredicate), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VerifyPredicate", reflect.TypeOf((*MockPredicater)(nil).VerifyPredicate), predicateContext, predicateBytes) } // MockConfig is a mock of Config interface. type MockConfig struct { ctrl *gomock.Controller recorder *MockConfigMockRecorder + isgomock struct{} } // MockConfigMockRecorder is the mock recorder for MockConfig. @@ -166,6 +168,7 @@ func (mr *MockConfigMockRecorder) Verify(arg0 any) *gomock.Call { type MockChainConfig struct { ctrl *gomock.Controller recorder *MockChainConfigMockRecorder + isgomock struct{} } // MockChainConfigMockRecorder is the mock recorder for MockChainConfig. @@ -214,23 +217,24 @@ func (mr *MockChainConfigMockRecorder) GetFeeConfig() *gomock.Call { } // IsDurango mocks base method. -func (m *MockChainConfig) IsDurango(arg0 uint64) bool { +func (m *MockChainConfig) IsDurango(time uint64) bool { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsDurango", arg0) + ret := m.ctrl.Call(m, "IsDurango", time) ret0, _ := ret[0].(bool) return ret0 } // IsDurango indicates an expected call of IsDurango. -func (mr *MockChainConfigMockRecorder) IsDurango(arg0 any) *gomock.Call { +func (mr *MockChainConfigMockRecorder) IsDurango(time any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsDurango", reflect.TypeOf((*MockChainConfig)(nil).IsDurango), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsDurango", reflect.TypeOf((*MockChainConfig)(nil).IsDurango), time) } // MockAccepter is a mock of Accepter interface. type MockAccepter struct { ctrl *gomock.Controller recorder *MockAccepterMockRecorder + isgomock struct{} } // MockAccepterMockRecorder is the mock recorder for MockAccepter. @@ -251,15 +255,15 @@ func (m *MockAccepter) EXPECT() *MockAccepterMockRecorder { } // Accept mocks base method. -func (m *MockAccepter) Accept(arg0 *AcceptContext, arg1 common.Hash, arg2 uint64, arg3 common.Hash, arg4 int, arg5 []common.Hash, arg6 []byte) error { +func (m *MockAccepter) Accept(acceptCtx *AcceptContext, blockHash common.Hash, blockNumber uint64, txHash common.Hash, logIndex int, topics []common.Hash, logData []byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Accept", arg0, arg1, arg2, arg3, arg4, arg5, arg6) + ret := m.ctrl.Call(m, "Accept", acceptCtx, blockHash, blockNumber, txHash, logIndex, topics, logData) ret0, _ := ret[0].(error) return ret0 } // Accept indicates an expected call of Accept. -func (mr *MockAccepterMockRecorder) Accept(arg0, arg1, arg2, arg3, arg4, arg5, arg6 any) *gomock.Call { +func (mr *MockAccepterMockRecorder) Accept(acceptCtx, blockHash, blockNumber, txHash, logIndex, topics, logData any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Accept", reflect.TypeOf((*MockAccepter)(nil).Accept), arg0, arg1, arg2, arg3, arg4, arg5, arg6) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Accept", reflect.TypeOf((*MockAccepter)(nil).Accept), acceptCtx, blockHash, blockNumber, txHash, logIndex, topics, logData) } diff --git a/precompile/precompileconfig/mocks_generate_test.go b/precompile/precompileconfig/mocks_generate_test.go new file mode 100644 index 0000000000..7dcdbbdde0 --- /dev/null +++ b/precompile/precompileconfig/mocks_generate_test.go @@ -0,0 +1,3 @@ +package precompileconfig + +//go:generate go run go.uber.org/mock/mockgen -package=$GOPACKAGE -destination=mocks.go . Predicater,Config,ChainConfig,Accepter diff --git a/precompile/testutils/test_precompile.go b/precompile/testutils/test_precompile.go index c1a1eac813..d345f9ada8 100644 --- a/precompile/testutils/test_precompile.go +++ b/precompile/testutils/test_precompile.go @@ -8,12 +8,12 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile/contract" "github.com/ava-labs/subnet-evm/precompile/modules" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" ) diff --git a/predicate/predicate_bytes.go b/predicate/predicate_bytes.go index 5c93bb5e3b..1d487a99d9 100644 --- a/predicate/predicate_bytes.go +++ b/predicate/predicate_bytes.go @@ -6,7 +6,7 @@ package predicate import ( "fmt" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) // DynamicFeeExtraDataSize is defined in the predicate package to avoid a circular dependency. diff --git a/predicate/predicate_results.go b/predicate/predicate_results.go index f28b790821..a79417329c 100644 --- a/predicate/predicate_results.go +++ b/predicate/predicate_results.go @@ -11,7 +11,7 @@ import ( "github.com/ava-labs/avalanchego/codec/linearcodec" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/utils/wrappers" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) const ( diff --git a/predicate/predicate_results_test.go b/predicate/predicate_results_test.go index e3daefa706..45b8efc0d6 100644 --- a/predicate/predicate_results_test.go +++ b/predicate/predicate_results_test.go @@ -6,7 +6,7 @@ package predicate import ( "testing" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/require" ) diff --git a/predicate/predicate_slots.go b/predicate/predicate_slots.go index b7a7024a78..9444f7dc55 100644 --- a/predicate/predicate_slots.go +++ b/predicate/predicate_slots.go @@ -4,9 +4,9 @@ package predicate import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" ) type predicaters interface { diff --git a/predicate/predicate_tx.go b/predicate/predicate_tx.go index 5244483888..b5c00787df 100644 --- a/predicate/predicate_tx.go +++ b/predicate/predicate_tx.go @@ -6,9 +6,9 @@ package predicate import ( "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" ) // NewPredicateTx returns a transaction with the predicateAddress/predicateBytes tuple diff --git a/rpc/client.go b/rpc/client.go index 6c11365560..ff351485f0 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -37,7 +37,7 @@ import ( "sync/atomic" "time" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" ) var ( diff --git a/rpc/client_test.go b/rpc/client_test.go index eec18afb8f..6a13e487da 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -42,8 +42,8 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/log" "github.com/davecgh/go-spew/spew" - "github.com/ethereum/go-ethereum/log" ) func TestClientRequest(t *testing.T) { diff --git a/rpc/handler.go b/rpc/handler.go index b4f54e1a91..f2142034a4 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -38,8 +38,8 @@ import ( "sync" "time" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/metrics" - "github.com/ethereum/go-ethereum/log" "golang.org/x/time/rate" ) @@ -479,7 +479,7 @@ func (h *handler) startCallProc(fn func(*callProc)) { } } -// handleResponse processes method call responses. +// handleResponses processes method call responses. func (h *handler) handleResponses(batch []*jsonrpcMessage, handleCall func(*jsonrpcMessage)) { var resolvedops []*requestOp handleResp := func(msg *jsonrpcMessage) { diff --git a/rpc/server.go b/rpc/server.go index 054bd2de92..d41ce1cc32 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -33,7 +33,7 @@ import ( "sync/atomic" "time" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" ) const MetadataApi = "rpc" diff --git a/rpc/service.go b/rpc/service.go index eecd70e90e..d8fe238844 100644 --- a/rpc/service.go +++ b/rpc/service.go @@ -35,7 +35,7 @@ import ( "sync" "unicode" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" ) var ( diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index 416940392e..3a90a5a238 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -38,8 +38,8 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" ) func TestNewID(t *testing.T) { diff --git a/rpc/types.go b/rpc/types.go index b2f5b98528..38123bb430 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -34,8 +34,8 @@ import ( "math" "strings" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" ) // API describes the set of methods offered over the RPC interface @@ -62,7 +62,7 @@ type ServerCodec interface { type jsonWriter interface { // writeJSON writes a message to the connection. writeJSON(ctx context.Context, msg interface{}, isError bool) error - // writeJSON writes a message to the connection with the option of skipping the deadline. + // writeJSONSkipDeadline writes a message to the connection with the option of skipping the deadline. writeJSONSkipDeadline(ctx context.Context, msg interface{}, isError bool, skip bool) error // Closed returns a channel which is closed when the connection is closed. closed() <-chan interface{} diff --git a/rpc/types_test.go b/rpc/types_test.go index a255c1e9f7..824c1c8155 100644 --- a/rpc/types_test.go +++ b/rpc/types_test.go @@ -31,8 +31,8 @@ import ( "reflect" "testing" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" ) func TestBlockNumberJSONUnmarshal(t *testing.T) { diff --git a/rpc/websocket.go b/rpc/websocket.go index 1be8364955..6f545477ad 100644 --- a/rpc/websocket.go +++ b/rpc/websocket.go @@ -37,8 +37,8 @@ import ( "sync" "time" + "github.com/ava-labs/libevm/log" mapset "github.com/deckarep/golang-set/v2" - "github.com/ethereum/go-ethereum/log" "github.com/gorilla/websocket" ) diff --git a/scripts/build_antithesis_images.sh b/scripts/build_antithesis_images.sh index b0764d84b9..13bad83552 100755 --- a/scripts/build_antithesis_images.sh +++ b/scripts/build_antithesis_images.sh @@ -47,7 +47,7 @@ source "${AVALANCHEGO_CLONE_PATH}"/scripts/lib_build_antithesis_images.sh build_antithesis_builder_image "${GO_VERSION}" "antithesis-subnet-evm-builder:${IMAGE_TAG}" "${AVALANCHEGO_CLONE_PATH}" "${SUBNET_EVM_PATH}" # Ensure avalanchego and subnet-evm binaries are available to create an initial db state that includes subnets. -"${AVALANCHEGO_CLONE_PATH}"/scripts/build.sh +pushd "${AVALANCHEGO_CLONE_PATH}" && ./scripts/build.sh && popd "${SUBNET_EVM_PATH}"/scripts/build.sh echo "Generating compose configuration" diff --git a/scripts/build_docker_image.sh b/scripts/build_docker_image.sh index 9de30cd7e7..93474e4a36 100755 --- a/scripts/build_docker_image.sh +++ b/scripts/build_docker_image.sh @@ -2,8 +2,25 @@ set -euo pipefail +# If set to non-empty, prompts the building of a multi-arch image when the image +# name indicates use of a registry. +# +# A registry is required to build a multi-arch image since a multi-arch image is +# not really an image at all. A multi-arch image (also called a manifest) is +# basically a list of arch-specific images available from the same registry that +# hosts the manifest. Manifests are not supported for local images. +# +# Reference: https://docs.docker.com/build/building/multi-platform/ +PLATFORMS="${PLATFORMS:-}" + +# If set to non-empty, the image will be published to the registry. +PUBLISH="${PUBLISH:-}" + # Directory above this script -SUBNET_EVM_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd ) +SUBNET_EVM_PATH=$( + cd "$(dirname "${BASH_SOURCE[0]}")" + cd .. && pwd +) # Load the constants source "$SUBNET_EVM_PATH"/scripts/constants.sh @@ -14,8 +31,30 @@ source "$SUBNET_EVM_PATH"/scripts/versions.sh # WARNING: this will use the most recent commit even if there are un-committed changes present BUILD_IMAGE_ID=${BUILD_IMAGE_ID:-"${CURRENT_BRANCH}"} +# buildx (BuildKit) improves the speed and UI of builds over the legacy builder and +# simplifies creation of multi-arch images. +# +# Reference: https://docs.docker.com/build/buildkit/ +DOCKER_CMD="docker buildx build" + +if [[ -n "${PUBLISH}" ]]; then + DOCKER_CMD="${DOCKER_CMD} --push" + + echo "Pushing $DOCKERHUB_REPO:$BUILD_IMAGE_ID" + + # A populated DOCKER_USERNAME env var triggers login + if [[ -n "${DOCKER_USERNAME:-}" ]]; then + echo "$DOCKER_PASS" | docker login --username "$DOCKER_USERNAME" --password-stdin + fi +fi + +# Build a multi-arch image if requested +if [[ -n "${PLATFORMS}" ]]; then + DOCKER_CMD="${DOCKER_CMD} --platform=${PLATFORMS}" +fi + VM_ID=${VM_ID:-"${DEFAULT_VM_ID}"} -if [[ "${VM_ID}" != "${DEFAULT_VM_ID}" ]]; then +if [[ "${VM_ID}" != "${DEFAULT_VM_ID}" ]]; then DOCKERHUB_TAG="${VM_ID}-${DOCKERHUB_TAG}" fi @@ -23,9 +62,14 @@ fi AVALANCHEGO_NODE_IMAGE="${AVALANCHEGO_NODE_IMAGE:-${AVALANCHEGO_IMAGE_NAME}:${AVALANCHE_VERSION}}" echo "Building Docker Image: $DOCKERHUB_REPO:$BUILD_IMAGE_ID based of AvalancheGo@$AVALANCHE_VERSION" -docker build -t "$DOCKERHUB_REPO:$BUILD_IMAGE_ID" -t "$DOCKERHUB_REPO:${DOCKERHUB_TAG}" \ - "$SUBNET_EVM_PATH" -f "$SUBNET_EVM_PATH/Dockerfile" \ +${DOCKER_CMD} -t "$DOCKERHUB_REPO:$BUILD_IMAGE_ID" -t "$DOCKERHUB_REPO:${DOCKERHUB_TAG}" \ + "$SUBNET_EVM_PATH" -f "$SUBNET_EVM_PATH/Dockerfile" \ --build-arg AVALANCHEGO_NODE_IMAGE="$AVALANCHEGO_NODE_IMAGE" \ --build-arg SUBNET_EVM_COMMIT="$SUBNET_EVM_COMMIT" \ --build-arg CURRENT_BRANCH="$CURRENT_BRANCH" \ --build-arg VM_ID="$VM_ID" + +if [[ -n "${PUBLISH}" && $CURRENT_BRANCH == "master" ]]; then + echo "Tagging current image as $DOCKERHUB_REPO:latest" + docker buildx imagetools create -t "$DOCKERHUB_REPO:latest" "$DOCKERHUB_REPO:$BUILD_IMAGE_ID" +fi diff --git a/scripts/eth-allowed-packages.txt b/scripts/eth-allowed-packages.txt new file mode 100644 index 0000000000..6f69e52bcd --- /dev/null +++ b/scripts/eth-allowed-packages.txt @@ -0,0 +1,38 @@ +"github.com/ava-labs/libevm/accounts" +"github.com/ava-labs/libevm/accounts/external" +"github.com/ava-labs/libevm/accounts/keystore" +"github.com/ava-labs/libevm/accounts/scwallet" +"github.com/ava-labs/libevm/common" +"github.com/ava-labs/libevm/common/bitutil" +"github.com/ava-labs/libevm/common/compiler" +"github.com/ava-labs/libevm/common/hexutil" +"github.com/ava-labs/libevm/common/lru" +"github.com/ava-labs/libevm/common/math" +"github.com/ava-labs/libevm/common/prque" +"github.com/ava-labs/libevm/core/asm" +"github.com/ava-labs/libevm/core/vm" +"github.com/ava-labs/libevm/crypto" +"github.com/ava-labs/libevm/crypto/blake2b" +"github.com/ava-labs/libevm/crypto/bls12381" +"github.com/ava-labs/libevm/crypto/bn256" +"github.com/ava-labs/libevm/crypto/kzg4844" +"github.com/ava-labs/libevm/eth/tracers/js" +"github.com/ava-labs/libevm/eth/tracers/logger" +"github.com/ava-labs/libevm/eth/tracers/native" +"github.com/ava-labs/libevm/ethdb" +"github.com/ava-labs/libevm/ethdb/leveldb" +"github.com/ava-labs/libevm/ethdb/memorydb" +"github.com/ava-labs/libevm/ethdb/pebble" +"github.com/ava-labs/libevm/event" +"github.com/ava-labs/libevm/libevm" +"github.com/ava-labs/libevm/libevm/stateconf" +"github.com/ava-labs/libevm/log" +"github.com/ava-labs/libevm/params" +"github.com/ava-labs/libevm/rlp" +"github.com/ava-labs/libevm/trie" +"github.com/ava-labs/libevm/trie/testutil" +"github.com/ava-labs/libevm/trie/trienode" +"github.com/ava-labs/libevm/trie/triestate" +"github.com/ava-labs/libevm/trie/utils" +"github.com/ava-labs/libevm/triedb" +"github.com/ava-labs/libevm/triedb/database" \ No newline at end of file diff --git a/scripts/geth-allowed-packages.txt b/scripts/geth-allowed-packages.txt deleted file mode 100644 index 06383561cd..0000000000 --- a/scripts/geth-allowed-packages.txt +++ /dev/null @@ -1,30 +0,0 @@ -"github.com/ethereum/go-ethereum/accounts" -"github.com/ethereum/go-ethereum/accounts/external" -"github.com/ethereum/go-ethereum/accounts/keystore" -"github.com/ethereum/go-ethereum/accounts/scwallet" -"github.com/ethereum/go-ethereum/common" -"github.com/ethereum/go-ethereum/common/bitutil" -"github.com/ethereum/go-ethereum/common/compiler" -"github.com/ethereum/go-ethereum/common/hexutil" -"github.com/ethereum/go-ethereum/common/lru" -"github.com/ethereum/go-ethereum/common/math" -"github.com/ethereum/go-ethereum/common/prque" -"github.com/ethereum/go-ethereum/core/asm" -"github.com/ethereum/go-ethereum/core/vm" -"github.com/ethereum/go-ethereum/crypto" -"github.com/ethereum/go-ethereum/crypto/blake2b" -"github.com/ethereum/go-ethereum/crypto/bls12381" -"github.com/ethereum/go-ethereum/crypto/bn256" -"github.com/ethereum/go-ethereum/crypto/kzg4844" -"github.com/ethereum/go-ethereum/eth/tracers/js" -"github.com/ethereum/go-ethereum/eth/tracers/logger" -"github.com/ethereum/go-ethereum/eth/tracers/native" -"github.com/ethereum/go-ethereum/ethdb" -"github.com/ethereum/go-ethereum/ethdb/leveldb" -"github.com/ethereum/go-ethereum/ethdb/memorydb" -"github.com/ethereum/go-ethereum/ethdb/pebble" -"github.com/ethereum/go-ethereum/event" -"github.com/ethereum/go-ethereum/libevm" -"github.com/ethereum/go-ethereum/log" -"github.com/ethereum/go-ethereum/params" -"github.com/ethereum/go-ethereum/rlp" \ No newline at end of file diff --git a/scripts/known_flakes.txt b/scripts/known_flakes.txt index 6f39599d6c..063a16def2 100644 --- a/scripts/known_flakes.txt +++ b/scripts/known_flakes.txt @@ -6,6 +6,7 @@ TestGolangBindings TestMempoolEthTxsAppGossipHandling TestResumeSyncAccountsTrieInterrupted TestResyncNewRootAfterDeletes +TestTimedUnlock TestTransactionSkipIndexing TestVMShutdownWhileSyncing TestWaitDeployedCornerCases diff --git a/scripts/lint_allowed_geth_imports.sh b/scripts/lint_allowed_eth_imports.sh similarity index 81% rename from scripts/lint_allowed_geth_imports.sh rename to scripts/lint_allowed_eth_imports.sh index ebc3c65c5f..47a64a66c4 100755 --- a/scripts/lint_allowed_geth_imports.sh +++ b/scripts/lint_allowed_eth_imports.sh @@ -9,11 +9,11 @@ set -o pipefail # 2. Ignore lines that import go-ethereum with a named import starting with "geth" # 3. Sort the unique results # 4. Print out the difference between the search results and the list of specified allowed package imports from geth. -geth_regexp='"github.com/ethereum/go-ethereum/.*"' -allow_named_imports='geth\w\+ "' -extra_imports=$(grep -r --include='*.go' --exclude=mocks.go --exclude-dir='simulator' "${geth_regexp}" -h | grep -v "${allow_named_imports}" | grep -o "${geth_regexp}" | sort -u | comm -23 - ./scripts/geth-allowed-packages.txt) +geth_regexp='"github.com/ava-labs/libevm/.*"' +allow_named_imports='eth\w\+ "' +extra_imports=$(grep -r --include='*.go' --exclude=mocks.go --exclude-dir='simulator' "${geth_regexp}" -h | grep -v "${allow_named_imports}" | grep -o "${geth_regexp}" | sort -u | comm -23 - ./scripts/eth-allowed-packages.txt) if [ -n "${extra_imports}" ]; then - echo "new go-ethereum imports should be added to ./scripts/geth-allowed-packages.txt to prevent accidental imports:" + echo "new ethereum imports should be added to ./scripts/eth-allowed-packages.txt to prevent accidental imports:" echo "${extra_imports}" exit 1 fi diff --git a/scripts/mock.gen.sh b/scripts/mock.gen.sh deleted file mode 100755 index 3550cba16f..0000000000 --- a/scripts/mock.gen.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -# Root directory -SUBNET_EVM_PATH=$( - cd "$(dirname "${BASH_SOURCE[0]}")" - cd .. && pwd -) - -if ! [[ "$0" =~ scripts/mock.gen.sh ]]; then - echo "must be run from repository root" - exit 255 -fi - -# https://github.com/uber-go/mock -go install -v go.uber.org/mock/mockgen@v0.4.0 - -if ! command -v go-license &>/dev/null; then - echo "go-license not found, installing..." - # https://github.com/palantir/go-license - go install -v github.com/palantir/go-license@v1.25.0 -fi - -# Load the constants -source "$SUBNET_EVM_PATH"/scripts/constants.sh - -# tuples of (source interface import path, comma-separated interface names, output file path) -input="scripts/mocks.mockgen.txt" -while IFS= read -r line; do - IFS='=' read -r src_import_path interface_name output_path <<<"${line}" - package_name=$(basename "$(dirname "$output_path")") - echo "Generating ${output_path}..." - mockgen -package="${package_name}" -destination="${output_path}" "${src_import_path}" "${interface_name}" - - go-license \ - --config=./header.yml \ - "${output_path}" -done <"$input" - -echo "SUCCESS" diff --git a/scripts/mocks.mockgen.txt b/scripts/mocks.mockgen.txt deleted file mode 100644 index 43a9d60cad..0000000000 --- a/scripts/mocks.mockgen.txt +++ /dev/null @@ -1,3 +0,0 @@ -github.com/ava-labs/subnet-evm/precompile/precompileconfig=Predicater,Config,ChainConfig,Accepter=precompile/precompileconfig/mocks.go -github.com/ava-labs/subnet-evm/precompile/contract=BlockContext,AccessibleState,StateDB=precompile/contract/mocks.go -github.com/ava-labs/subnet-evm/plugin/evm/validators/interfaces=StateCallbackListener=plugin/evm/validators/interfaces/mock_listener.go diff --git a/scripts/versions.sh b/scripts/versions.sh index a3c3664462..096bc8aa19 100644 --- a/scripts/versions.sh +++ b/scripts/versions.sh @@ -4,8 +4,5 @@ # shellcheck disable=SC2034 # Don't export them as they're used in the context of other calls -AVALANCHE_VERSION=${AVALANCHE_VERSION:-'acb3d7d1'} +AVALANCHE_VERSION=${AVALANCHE_VERSION:-'2fb6d3f6'} GINKGO_VERSION=${GINKGO_VERSION:-'v2.2.0'} - -# This won't be used, but it's here to make code syncs easier -LATEST_CORETH_VERSION='v0.13.7' diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 89b621d329..c2215fc407 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -32,9 +32,9 @@ import ( "math/big" "strings" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" ) type ValidationInfo struct { diff --git a/stateupgrade/interfaces.go b/stateupgrade/interfaces.go index a12351ecc9..87b68e65a9 100644 --- a/stateupgrade/interfaces.go +++ b/stateupgrade/interfaces.go @@ -6,7 +6,7 @@ package stateupgrade import ( "math/big" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/holiman/uint256" ) diff --git a/stateupgrade/state_upgrade.go b/stateupgrade/state_upgrade.go index 65a1f2dc69..a7c5765b88 100644 --- a/stateupgrade/state_upgrade.go +++ b/stateupgrade/state_upgrade.go @@ -6,8 +6,8 @@ package stateupgrade import ( "math/big" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" ) diff --git a/sync/client/client.go b/sync/client/client.go index 1c2a3fcc2c..5e46430a5f 100644 --- a/sync/client/client.go +++ b/sync/client/client.go @@ -19,16 +19,16 @@ import ( "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/version" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/peer" "github.com/ava-labs/subnet-evm/plugin/evm/message" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ethereum/go-ethereum/ethdb" ) const ( diff --git a/sync/client/client_test.go b/sync/client/client_test.go index 1e65286085..ef04df144b 100644 --- a/sync/client/client_test.go +++ b/sync/client/client_test.go @@ -15,6 +15,9 @@ import ( "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/rawdb" @@ -25,9 +28,6 @@ import ( "github.com/ava-labs/subnet-evm/sync/handlers" handlerstats "github.com/ava-labs/subnet-evm/sync/handlers/stats" "github.com/ava-labs/subnet-evm/sync/syncutils" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" ) func TestGetCode(t *testing.T) { diff --git a/sync/client/leaf_syncer.go b/sync/client/leaf_syncer.go index 8ad9ef27c6..93cd0e1696 100644 --- a/sync/client/leaf_syncer.go +++ b/sync/client/leaf_syncer.go @@ -9,10 +9,10 @@ import ( "errors" "fmt" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" "golang.org/x/sync/errgroup" ) diff --git a/sync/client/mock_client.go b/sync/client/mock_client.go index 2851db9275..8c0026e3d1 100644 --- a/sync/client/mock_client.go +++ b/sync/client/mock_client.go @@ -10,11 +10,11 @@ import ( "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" ) var ( diff --git a/sync/handlers/block_request.go b/sync/handlers/block_request.go index a8fc070eb0..a511e33430 100644 --- a/sync/handlers/block_request.go +++ b/sync/handlers/block_request.go @@ -12,10 +12,10 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers/stats" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" ) const ( diff --git a/sync/handlers/block_request_test.go b/sync/handlers/block_request_test.go index dfc467c188..cb581b9321 100644 --- a/sync/handlers/block_request_test.go +++ b/sync/handlers/block_request_test.go @@ -10,6 +10,10 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/rawdb" @@ -17,10 +21,6 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers/stats" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/assert" ) diff --git a/sync/handlers/code_request.go b/sync/handlers/code_request.go index cbe29b3b94..23f3c3f584 100644 --- a/sync/handlers/code_request.go +++ b/sync/handlers/code_request.go @@ -10,12 +10,12 @@ import ( "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers/stats" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" ) // CodeRequestHandler is a peer.RequestHandler for message.CodeRequest diff --git a/sync/handlers/code_request_test.go b/sync/handlers/code_request_test.go index 31112f636b..ff94863be6 100644 --- a/sync/handlers/code_request_test.go +++ b/sync/handlers/code_request_test.go @@ -11,12 +11,12 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb/memorydb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers/stats" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/stretchr/testify/assert" ) diff --git a/sync/handlers/handler.go b/sync/handlers/handler.go index 867941aa83..bfaa7ac716 100644 --- a/sync/handlers/handler.go +++ b/sync/handlers/handler.go @@ -4,9 +4,9 @@ package handlers import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" ) type BlockProvider interface { diff --git a/sync/handlers/leafs_request.go b/sync/handlers/leafs_request.go index 5222091649..8c6f3aff60 100644 --- a/sync/handlers/leafs_request.go +++ b/sync/handlers/leafs_request.go @@ -11,18 +11,18 @@ import ( "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/ethdb/memorydb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers/stats" "github.com/ava-labs/subnet-evm/sync/syncutils" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/ethdb/memorydb" - "github.com/ethereum/go-ethereum/log" ) const ( diff --git a/sync/handlers/leafs_request_test.go b/sync/handlers/leafs_request_test.go index 7c97c8afa1..8e22cefd49 100644 --- a/sync/handlers/leafs_request_test.go +++ b/sync/handlers/leafs_request_test.go @@ -10,17 +10,17 @@ import ( "testing" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers/stats" "github.com/ava-labs/subnet-evm/sync/syncutils" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/stretchr/testify/assert" ) diff --git a/sync/handlers/test_providers.go b/sync/handlers/test_providers.go index 9fb8945a4b..4d78206ff6 100644 --- a/sync/handlers/test_providers.go +++ b/sync/handlers/test_providers.go @@ -4,9 +4,9 @@ package handlers import ( + "github.com/ava-labs/libevm/common" "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" ) var ( diff --git a/sync/statesync/code_syncer.go b/sync/statesync/code_syncer.go index 560c85f7b0..9f1dfc6cdf 100644 --- a/sync/statesync/code_syncer.go +++ b/sync/statesync/code_syncer.go @@ -11,11 +11,11 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/plugin/evm/message" statesyncclient "github.com/ava-labs/subnet-evm/sync/client" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" ) const ( diff --git a/sync/statesync/code_syncer_test.go b/sync/statesync/code_syncer_test.go index dbc9b7969a..be23eb2b27 100644 --- a/sync/statesync/code_syncer_test.go +++ b/sync/statesync/code_syncer_test.go @@ -9,14 +9,14 @@ import ( "testing" "github.com/ava-labs/avalanchego/utils" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb/memorydb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/plugin/evm/message" statesyncclient "github.com/ava-labs/subnet-evm/sync/client" "github.com/ava-labs/subnet-evm/sync/handlers" handlerstats "github.com/ava-labs/subnet-evm/sync/handlers/stats" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/stretchr/testify/assert" ) diff --git a/sync/statesync/state_syncer.go b/sync/statesync/state_syncer.go index 873d81e000..14d03e58d4 100644 --- a/sync/statesync/state_syncer.go +++ b/sync/statesync/state_syncer.go @@ -8,11 +8,11 @@ import ( "fmt" "sync" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/state/snapshot" syncclient "github.com/ava-labs/subnet-evm/sync/client" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" "golang.org/x/sync/errgroup" ) @@ -35,12 +35,12 @@ type StateSyncerConfig struct { // stateSync keeps the state of the entire state sync operation. type stateSync struct { - db ethdb.Database // database we are syncing - root common.Hash // root of the EVM state we are syncing to - trieDB *triedb.Database // trieDB on top of db we are syncing. used to restore any existing tries. - snapshot snapshot.Snapshot // used to access the database we are syncing as a snapshot. - batchSize int // write batches when they reach this size - client syncclient.Client // used to contact peers over the network + db ethdb.Database // database we are syncing + root common.Hash // root of the EVM state we are syncing to + trieDB *triedb.Database // trieDB on top of db we are syncing. used to restore any existing tries. + snapshot snapshot.SnapshotIterable // used to access the database we are syncing as a snapshot. + batchSize int // write batches when they reach this size + client syncclient.Client // used to contact peers over the network segments chan syncclient.LeafSyncTask // channel of tasks to sync syncer *syncclient.CallbackLeafSyncer // performs the sync, looping over each task's range and invoking specified callbacks diff --git a/sync/statesync/sync_helpers.go b/sync/statesync/sync_helpers.go index 45cfc02b90..d285d90232 100644 --- a/sync/statesync/sync_helpers.go +++ b/sync/statesync/sync_helpers.go @@ -4,11 +4,11 @@ package statesync import ( + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" ) // writeAccountSnapshot stores the account represented by [acc] to the snapshot at [accHash], using diff --git a/sync/statesync/sync_test.go b/sync/statesync/sync_test.go index 1fe066e142..33da3d82ea 100644 --- a/sync/statesync/sync_test.go +++ b/sync/statesync/sync_test.go @@ -13,6 +13,12 @@ import ( "testing" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/core/types" @@ -21,12 +27,6 @@ import ( "github.com/ava-labs/subnet-evm/sync/handlers" handlerstats "github.com/ava-labs/subnet-evm/sync/handlers/stats" "github.com/ava-labs/subnet-evm/sync/syncutils" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/triedb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/assert" ) diff --git a/sync/statesync/test_sync.go b/sync/statesync/test_sync.go index 27061243e8..5c218d95d5 100644 --- a/sync/statesync/test_sync.go +++ b/sync/statesync/test_sync.go @@ -8,15 +8,15 @@ import ( "math/rand" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/sync/syncutils" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/assert" ) diff --git a/sync/statesync/trie_queue.go b/sync/statesync/trie_queue.go index b8de049003..905cbb8844 100644 --- a/sync/statesync/trie_queue.go +++ b/sync/statesync/trie_queue.go @@ -4,9 +4,9 @@ package statesync import ( + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" ) // trieQueue persists storage trie roots with their associated diff --git a/sync/statesync/trie_segments.go b/sync/statesync/trie_segments.go index 4ba43a2bc4..4a524dc9fd 100644 --- a/sync/statesync/trie_segments.go +++ b/sync/statesync/trie_segments.go @@ -11,13 +11,13 @@ import ( "sync" "github.com/ava-labs/avalanchego/utils/wrappers" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/core/rawdb" syncclient "github.com/ava-labs/subnet-evm/sync/client" - "github.com/ava-labs/subnet-evm/trie" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" ) var ( diff --git a/sync/statesync/trie_sync_stats.go b/sync/statesync/trie_sync_stats.go index 217c649181..a64432d6fe 100644 --- a/sync/statesync/trie_sync_stats.go +++ b/sync/statesync/trie_sync_stats.go @@ -10,9 +10,9 @@ import ( utils_math "github.com/ava-labs/avalanchego/utils/math" "github.com/ava-labs/avalanchego/utils/timer" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/metrics" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" ) const ( @@ -79,7 +79,7 @@ func (t *trieSyncStats) incLeafs(segment *trieSegment, count uint64, remaining u } } -// estimateSegmentsInProgressTime retrns the ETA for all trie segments +// estimateSegmentsInProgressTime returns the ETA for all trie segments // in progress to finish (uses the one with most remaining leafs to estimate). func (t *trieSyncStats) estimateSegmentsInProgressTime() time.Duration { if len(t.remainingLeafs) == 0 { diff --git a/sync/statesync/trie_sync_tasks.go b/sync/statesync/trie_sync_tasks.go index a734550e1e..5d925f523d 100644 --- a/sync/statesync/trie_sync_tasks.go +++ b/sync/statesync/trie_sync_tasks.go @@ -6,14 +6,14 @@ package statesync import ( "fmt" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/sync/syncutils" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) var ( diff --git a/sync/syncutils/iterators.go b/sync/syncutils/iterators.go index 45752ca72f..a30564eed8 100644 --- a/sync/syncutils/iterators.go +++ b/sync/syncutils/iterators.go @@ -4,9 +4,9 @@ package syncutils import ( + "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/ethdb" ) var ( diff --git a/sync/syncutils/test_trie.go b/sync/syncutils/test_trie.go index 335baaf6fb..7662d4acf3 100644 --- a/sync/syncutils/test_trie.go +++ b/sync/syncutils/test_trie.go @@ -10,16 +10,16 @@ import ( "testing" "github.com/ava-labs/avalanchego/utils/wrappers" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/trie/trienode" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/utils" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" + + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/rlp" "github.com/stretchr/testify/assert" ) diff --git a/tests/antithesis/main.go b/tests/antithesis/main.go index a58893a1be..4a93a1c3db 100644 --- a/tests/antithesis/main.go +++ b/tests/antithesis/main.go @@ -8,20 +8,21 @@ import ( "crypto/ecdsa" "crypto/rand" "fmt" - "log" "math/big" "path/filepath" "time" "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/antithesishq/antithesis-sdk-go/lifecycle" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" "github.com/stretchr/testify/require" + "go.uber.org/zap" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/tests/antithesis" "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" + "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/core/types" @@ -37,7 +38,8 @@ import ( const NumKeys = 5 func main() { - tc := ago_tests.NewTestContext() + logger := ago_tests.NewDefaultLogger("") + tc := ago_tests.NewTestContext(logger) defer tc.Cleanup() require := require.New(tc) @@ -60,7 +62,9 @@ func main() { ctx := ago_tests.DefaultNotifyContext(c.Duration, tc.DeferCleanup) require.Len(c.ChainIDs, 1) - log.Printf("CHAIN IDS: %v", c.ChainIDs) + logger.Info("Starting testing", + zap.Strings("chainIDs", c.ChainIDs), + ) chainID, err := ids.FromString(c.ChainIDs[0]) require.NoError(err, "failed to parse chainID") @@ -69,6 +73,7 @@ func main() { genesisKey := tmpnet.HardhatKey.ToECDSA() genesisWorkload := &workload{ id: 0, + log: ago_tests.NewDefaultLogger(fmt.Sprintf("worker %d", 0)), client: genesisClient, key: genesisKey, uris: c.URIs, @@ -82,13 +87,14 @@ func main() { key, err := crypto.ToECDSA(crypto.Keccak256([]byte{uint8(i)})) require.NoError(err, "failed to generate key") - require.NoError(transferFunds(ctx, genesisClient, genesisKey, crypto.PubkeyToAddress(key.PublicKey), initialAmount)) + require.NoError(transferFunds(ctx, genesisClient, genesisKey, crypto.PubkeyToAddress(key.PublicKey), initialAmount, logger)) client, err := ethclient.Dial(getChainURI(c.URIs[i%len(c.URIs)], chainID.String())) require.NoError(err, "failed to dial chain") workloads[i] = &workload{ id: i, + log: ago_tests.NewDefaultLogger(fmt.Sprintf("worker %d", i)), client: client, key: key, uris: c.URIs, @@ -109,6 +115,7 @@ func main() { type workload struct { id int client ethclient.Client + log logging.Logger key *ecdsa.PrivateKey uris []string } @@ -116,7 +123,7 @@ type workload struct { func (w *workload) run(ctx context.Context) { timer := timerpkg.StoppedTimer() - tc := ago_tests.NewTestContext() + tc := ago_tests.NewTestContext(w.log) defer tc.Cleanup() require := require.New(tc) @@ -132,12 +139,14 @@ func (w *workload) run(ctx context.Context) { for { // TODO(marun) Exercise a wider variety of transactions recipientEthAddress := crypto.PubkeyToAddress(w.key.PublicKey) - err := transferFunds(ctx, w.client, w.key, recipientEthAddress, txAmount) + err := transferFunds(ctx, w.client, w.key, recipientEthAddress, txAmount, w.log) if err != nil { // Log the error and continue since the problem may be // transient. require.NoError is only for errors that should stop // execution. - log.Printf("failed to transfer funds: %s", err) + w.log.Info("failed to transfer funds", + zap.Error(err), + ) } val, err := rand.Int(rand.Reader, big.NewInt(int64(time.Second))) @@ -156,7 +165,7 @@ func getChainURI(nodeURI string, blockchainID string) string { return fmt.Sprintf("%s/ext/bc/%s/rpc", nodeURI, blockchainID) } -func transferFunds(ctx context.Context, client ethclient.Client, key *ecdsa.PrivateKey, recipientAddress common.Address, txAmount uint64) error { +func transferFunds(ctx context.Context, client ethclient.Client, key *ecdsa.PrivateKey, recipientAddress common.Address, txAmount uint64, log logging.Logger) error { chainID, err := client.ChainID(ctx) if err != nil { return fmt.Errorf("failed to fetch chainID: %w", err) @@ -188,17 +197,17 @@ func transferFunds(ctx context.Context, client ethclient.Client, key *ecdsa.Priv return fmt.Errorf("failed to format transaction: %w", err) } - log.Printf("sending transaction with ID %s and nonce %d\n", tx.Hash(), acceptedNonce) + log.Info("sending transaction", zap.Stringer("txID", tx.Hash()), zap.Uint64("nonce", acceptedNonce)) err = client.SendTransaction(ctx, tx) if err != nil { return fmt.Errorf("failed to send transaction: %w", err) } - log.Printf("waiting for acceptance of transaction with ID %s\n", tx.Hash()) + log.Info("waiting for acceptance of transaction", zap.Stringer("txID", tx.Hash())) if _, err := bind.WaitMined(ctx, client, tx); err != nil { return fmt.Errorf("failed to wait for receipt: %v", err) } - log.Printf("confirmed acceptance of transaction with ID %s\n", tx.Hash()) + log.Info("confirmed acceptance of transaction", zap.Stringer("txID", tx.Hash())) return nil } diff --git a/tests/gen_stenv.go b/tests/gen_stenv.go index f026b455e3..96d56d3007 100644 --- a/tests/gen_stenv.go +++ b/tests/gen_stenv.go @@ -7,8 +7,8 @@ import ( "errors" "math/big" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/math" ) var _ = (*stEnvMarshaling)(nil) diff --git a/tests/load/load_test.go b/tests/load/load_test.go index aa5a14783b..296937768a 100644 --- a/tests/load/load_test.go +++ b/tests/load/load_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/tests/fixture/e2e" diff --git a/tests/rlp_test_util.go b/tests/rlp_test_util.go index 5af235bc5a..b5df73438e 100644 --- a/tests/rlp_test_util.go +++ b/tests/rlp_test_util.go @@ -34,7 +34,7 @@ import ( "math/big" "strings" - "github.com/ethereum/go-ethereum/rlp" + "github.com/ava-labs/libevm/rlp" ) // RLPTest is the JSON structure of a single RLP test. diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 13ed011505..9d70f10da4 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -35,6 +35,14 @@ import ( "strconv" "strings" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/core/vm" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/rawdb" @@ -42,16 +50,8 @@ import ( "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/triedb" "github.com/ava-labs/subnet-evm/triedb/hashdb" "github.com/ava-labs/subnet-evm/triedb/pathdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) @@ -462,9 +462,9 @@ type StateTestState struct { func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bool, scheme string) StateTestState { tconf := &triedb.Config{Preimages: true} if scheme == rawdb.HashScheme { - tconf.HashDB = hashdb.Defaults + tconf.DBOverride = hashdb.Defaults.BackendConstructor } else { - tconf.PathDB = pathdb.Defaults + tconf.DBOverride = pathdb.Defaults.BackendConstructor } triedb := triedb.NewDatabase(db, tconf) sdb := state.NewDatabaseWithNodeDB(db, triedb) diff --git a/tests/utils/command.go b/tests/utils/command.go index 33e674e8ae..3b1f679b6f 100644 --- a/tests/utils/command.go +++ b/tests/utils/command.go @@ -12,7 +12,7 @@ import ( "time" "github.com/ava-labs/avalanchego/api/health" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" "github.com/go-cmd/cmd" "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/require" diff --git a/tests/utils/proposervm.go b/tests/utils/proposervm.go index d7f2a37530..fab40a3800 100644 --- a/tests/utils/proposervm.go +++ b/tests/utils/proposervm.go @@ -8,12 +8,12 @@ import ( "crypto/ecdsa" "math/big" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/params" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" ) const numTriggerTxs = 2 // Number of txs needed to activate the proposer VM fork diff --git a/tests/utils/subnet.go b/tests/utils/subnet.go index 6f7aea3500..1ace855d25 100644 --- a/tests/utils/subnet.go +++ b/tests/utils/subnet.go @@ -19,9 +19,9 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/vms/secp256k1fx" wallet "github.com/ava-labs/avalanchego/wallet/subnet/primary" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/plugin/evm" - "github.com/ethereum/go-ethereum/log" "github.com/go-cmd/cmd" "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/require" @@ -64,7 +64,7 @@ func CreateSubnetsSuite(genesisFiles map[string]string) *SubnetSuite { // each test case. Each test case has its own subnet, therefore all tests // can run in parallel without any issue. // - var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { + _ = ginkgo.SynchronizedBeforeSuite(func() []byte { ctx, cancel := context.WithTimeout(context.Background(), BootAvalancheNodeTimeout) defer cancel() @@ -101,7 +101,7 @@ func CreateSubnetsSuite(genesisFiles map[string]string) *SubnetSuite { // SynchronizedAfterSuite() takes two functions, the first runs after each test suite is done and the second // function is executed once when all the tests are done. This function is used // to gracefully shutdown the AvalancheGo node. - var _ = ginkgo.SynchronizedAfterSuite(func() {}, func() { + _ = ginkgo.SynchronizedAfterSuite(func() {}, func() { require.NotNil(startCmd) require.NoError(startCmd.Stop()) }) @@ -118,11 +118,7 @@ func CreateNewSubnet(ctx context.Context, genesisFilePath string) string { // MakeWallet fetches the available UTXOs owned by [kc] on the network // that [LocalAPIURI] is hosting. - wallet, err := wallet.MakeWallet(ctx, &wallet.WalletConfig{ - URI: DefaultLocalNodeURI, - AVAXKeychain: kc, - EthKeychain: kc, - }) + wallet, err := wallet.MakeWallet(ctx, DefaultLocalNodeURI, kc, kc, wallet.WalletConfig{}) require.NoError(err) pWallet := wallet.P() diff --git a/tests/warp/warp_test.go b/tests/warp/warp_test.go index 57567ae451..09d10e8d08 100644 --- a/tests/warp/warp_test.go +++ b/tests/warp/warp_test.go @@ -20,9 +20,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/ids" @@ -31,6 +31,7 @@ import ( "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/api" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" @@ -402,9 +403,9 @@ func (w *warpTest) aggregateSignaturesViaAPI() { // If the destination turns out to be the Primary Network as well, then this is a no-op. var validators map[ids.NodeID]*validators.GetValidatorOutput if w.sendingSubnet.SubnetID == constants.PrimaryNetworkID { - validators, err = pChainClient.GetValidatorsAt(ctx, w.receivingSubnet.SubnetID, pChainHeight) + validators, err = pChainClient.GetValidatorsAt(ctx, w.receivingSubnet.SubnetID, api.Height(pChainHeight)) } else { - validators, err = pChainClient.GetValidatorsAt(ctx, w.sendingSubnet.SubnetID, pChainHeight) + validators, err = pChainClient.GetValidatorsAt(ctx, w.sendingSubnet.SubnetID, api.Height(pChainHeight)) } require.NoError(err) require.NotZero(len(validators)) diff --git a/tools.go b/tools.go new file mode 100644 index 0000000000..312a2d6302 --- /dev/null +++ b/tools.go @@ -0,0 +1,8 @@ +// (c) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package subnetevm + +import ( + _ "golang.org/x/mod/modfile" // golang.org/x/mod to satisfy requirement for go.uber.org/mock/mockgen@v0.4 +) diff --git a/trie/committer.go b/trie/committer.go deleted file mode 100644 index 97d7ff6f6f..0000000000 --- a/trie/committer.go +++ /dev/null @@ -1,192 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2020 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "fmt" - - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" -) - -// committer is the tool used for the trie Commit operation. The committer will -// capture all dirty nodes during the commit process and keep them cached in -// insertion order. -type committer struct { - nodes *trienode.NodeSet - tracer *tracer - collectLeaf bool -} - -// newCommitter creates a new committer or picks one from the pool. -func newCommitter(nodeset *trienode.NodeSet, tracer *tracer, collectLeaf bool) *committer { - return &committer{ - nodes: nodeset, - tracer: tracer, - collectLeaf: collectLeaf, - } -} - -// Commit collapses a node down into a hash node. -func (c *committer) Commit(n node) hashNode { - return c.commit(nil, n).(hashNode) -} - -// commit collapses a node down into a hash node and returns it. -func (c *committer) commit(path []byte, n node) node { - // if this path is clean, use available cached data - hash, dirty := n.cache() - if hash != nil && !dirty { - return hash - } - // Commit children, then parent, and remove the dirty flag. - switch cn := n.(type) { - case *shortNode: - // Commit child - collapsed := cn.copy() - - // If the child is fullNode, recursively commit, - // otherwise it can only be hashNode or valueNode. - if _, ok := cn.Val.(*fullNode); ok { - collapsed.Val = c.commit(append(path, cn.Key...), cn.Val) - } - // The key needs to be copied, since we're adding it to the - // modified nodeset. - collapsed.Key = hexToCompact(cn.Key) - hashedNode := c.store(path, collapsed) - if hn, ok := hashedNode.(hashNode); ok { - return hn - } - return collapsed - case *fullNode: - hashedKids := c.commitChildren(path, cn) - collapsed := cn.copy() - collapsed.Children = hashedKids - - hashedNode := c.store(path, collapsed) - if hn, ok := hashedNode.(hashNode); ok { - return hn - } - return collapsed - case hashNode: - return cn - default: - // nil, valuenode shouldn't be committed - panic(fmt.Sprintf("%T: invalid node: %v", n, n)) - } -} - -// commitChildren commits the children of the given fullnode -func (c *committer) commitChildren(path []byte, n *fullNode) [17]node { - var children [17]node - for i := 0; i < 16; i++ { - child := n.Children[i] - if child == nil { - continue - } - // If it's the hashed child, save the hash value directly. - // Note: it's impossible that the child in range [0, 15] - // is a valueNode. - if hn, ok := child.(hashNode); ok { - children[i] = hn - continue - } - // Commit the child recursively and store the "hashed" value. - // Note the returned node can be some embedded nodes, so it's - // possible the type is not hashNode. - children[i] = c.commit(append(path, byte(i)), child) - } - // For the 17th child, it's possible the type is valuenode. - if n.Children[16] != nil { - children[16] = n.Children[16] - } - return children -} - -// store hashes the node n and adds it to the modified nodeset. If leaf collection -// is enabled, leaf nodes will be tracked in the modified nodeset as well. -func (c *committer) store(path []byte, n node) node { - // Larger nodes are replaced by their hash and stored in the database. - var hash, _ = n.cache() - - // This was not generated - must be a small node stored in the parent. - // In theory, we should check if the node is leaf here (embedded node - // usually is leaf node). But small value (less than 32bytes) is not - // our target (leaves in account trie only). - if hash == nil { - // The node is embedded in its parent, in other words, this node - // will not be stored in the database independently, mark it as - // deleted only if the node was existent in database before. - _, ok := c.tracer.accessList[string(path)] - if ok { - c.nodes.AddNode(path, trienode.NewDeleted()) - } - return n - } - // Collect the dirty node to nodeset for return. - nhash := common.BytesToHash(hash) - c.nodes.AddNode(path, trienode.New(nhash, nodeToBytes(n))) - - // Collect the corresponding leaf node if it's required. We don't check - // full node since it's impossible to store value in fullNode. The key - // length of leaves should be exactly same. - if c.collectLeaf { - if sn, ok := n.(*shortNode); ok { - if val, ok := sn.Val.(valueNode); ok { - c.nodes.AddLeaf(nhash, val) - } - } - } - return hash -} - -// MerkleResolver the children resolver in merkle-patricia-tree. -type MerkleResolver struct{} - -// ForEach implements childResolver, decodes the provided node and -// traverses the children inside. -func (resolver MerkleResolver) ForEach(node []byte, onChild func(common.Hash)) { - forGatherChildren(mustDecodeNodeUnsafe(nil, node), onChild) -} - -// forGatherChildren traverses the node hierarchy and invokes the callback -// for all the hashnode children. -func forGatherChildren(n node, onChild func(hash common.Hash)) { - switch n := n.(type) { - case *shortNode: - forGatherChildren(n.Val, onChild) - case *fullNode: - for i := 0; i < 16; i++ { - forGatherChildren(n.Children[i], onChild) - } - case hashNode: - onChild(common.BytesToHash(n)) - case valueNode, nil: - default: - panic(fmt.Sprintf("unknown node type: %T", n)) - } -} diff --git a/trie/database_test.go b/trie/database_test.go deleted file mode 100644 index d844eb4a37..0000000000 --- a/trie/database_test.go +++ /dev/null @@ -1,162 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2019 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/triedb/database" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" -) - -// testReader implements database.Reader interface, providing function to -// access trie nodes. -type testReader struct { - db ethdb.Database - scheme string - nodes []*trienode.MergedNodeSet // sorted from new to old -} - -// Node implements database.Reader interface, retrieving trie node with -// all available cached layers. -func (r *testReader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) { - // Check the node presence with the cached layer, from latest to oldest. - for _, nodes := range r.nodes { - if _, ok := nodes.Sets[owner]; !ok { - continue - } - n, ok := nodes.Sets[owner].Nodes[string(path)] - if !ok { - continue - } - if n.IsDeleted() || n.Hash != hash { - return nil, &MissingNodeError{Owner: owner, Path: path, NodeHash: hash} - } - return n.Blob, nil - } - // Check the node presence in database. - return rawdb.ReadTrieNode(r.db, owner, path, hash, r.scheme), nil -} - -// testDb implements database.Database interface, using for testing purpose. -type testDb struct { - disk ethdb.Database - root common.Hash - scheme string - nodes map[common.Hash]*trienode.MergedNodeSet - parents map[common.Hash]common.Hash -} - -func newTestDatabase(diskdb ethdb.Database, scheme string) *testDb { - return &testDb{ - disk: diskdb, - root: types.EmptyRootHash, - scheme: scheme, - nodes: make(map[common.Hash]*trienode.MergedNodeSet), - parents: make(map[common.Hash]common.Hash), - } -} - -func (db *testDb) Reader(stateRoot common.Hash) (database.Reader, error) { - nodes, _ := db.dirties(stateRoot, true) - return &testReader{db: db.disk, scheme: db.scheme, nodes: nodes}, nil -} - -func (db *testDb) Preimage(hash common.Hash) []byte { - return rawdb.ReadPreimage(db.disk, hash) -} - -func (db *testDb) InsertPreimage(preimages map[common.Hash][]byte) { - rawdb.WritePreimages(db.disk, preimages) -} - -func (db *testDb) Scheme() string { return db.scheme } - -func (db *testDb) Update(root common.Hash, parent common.Hash, nodes *trienode.MergedNodeSet) error { - if root == parent { - return nil - } - if _, ok := db.nodes[root]; ok { - return nil - } - db.parents[root] = parent - db.nodes[root] = nodes - return nil -} - -func (db *testDb) dirties(root common.Hash, topToBottom bool) ([]*trienode.MergedNodeSet, []common.Hash) { - var ( - pending []*trienode.MergedNodeSet - roots []common.Hash - ) - for { - if root == db.root { - break - } - nodes, ok := db.nodes[root] - if !ok { - break - } - if topToBottom { - pending = append(pending, nodes) - roots = append(roots, root) - } else { - pending = append([]*trienode.MergedNodeSet{nodes}, pending...) - roots = append([]common.Hash{root}, roots...) - } - root = db.parents[root] - } - return pending, roots -} - -func (db *testDb) Commit(root common.Hash) error { - if root == db.root { - return nil - } - pending, roots := db.dirties(root, false) - for i, nodes := range pending { - for owner, set := range nodes.Sets { - if owner == (common.Hash{}) { - continue - } - set.ForEachWithOrder(func(path string, n *trienode.Node) { - rawdb.WriteTrieNode(db.disk, owner, []byte(path), n.Hash, n.Blob, db.scheme) - }) - } - nodes.Sets[common.Hash{}].ForEachWithOrder(func(path string, n *trienode.Node) { - rawdb.WriteTrieNode(db.disk, common.Hash{}, []byte(path), n.Hash, n.Blob, db.scheme) - }) - db.root = roots[i] - } - for _, root := range roots { - delete(db.nodes, root) - delete(db.parents, root) - } - return nil -} diff --git a/trie/encoding.go b/trie/encoding.go deleted file mode 100644 index aaa131ef1f..0000000000 --- a/trie/encoding.go +++ /dev/null @@ -1,154 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -// Trie keys are dealt with in three distinct encodings: -// -// KEYBYTES encoding contains the actual key and nothing else. This encoding is the -// input to most API functions. -// -// HEX encoding contains one byte for each nibble of the key and an optional trailing -// 'terminator' byte of value 0x10 which indicates whether or not the node at the key -// contains a value. Hex key encoding is used for nodes loaded in memory because it's -// convenient to access. -// -// COMPACT encoding is defined by the Ethereum Yellow Paper (it's called "hex prefix -// encoding" there) and contains the bytes of the key and a flag. The high nibble of the -// first byte contains the flag; the lowest bit encoding the oddness of the length and -// the second-lowest encoding whether the node at the key is a value node. The low nibble -// of the first byte is zero in the case of an even number of nibbles and the first nibble -// in the case of an odd number. All remaining nibbles (now an even number) fit properly -// into the remaining bytes. Compact encoding is used for nodes stored on disk. - -func hexToCompact(hex []byte) []byte { - terminator := byte(0) - if hasTerm(hex) { - terminator = 1 - hex = hex[:len(hex)-1] - } - buf := make([]byte, len(hex)/2+1) - buf[0] = terminator << 5 // the flag byte - if len(hex)&1 == 1 { - buf[0] |= 1 << 4 // odd flag - buf[0] |= hex[0] // first nibble is contained in the first byte - hex = hex[1:] - } - decodeNibbles(hex, buf[1:]) - return buf -} - -// hexToCompactInPlace places the compact key in input buffer, returning the compacted key. -func hexToCompactInPlace(hex []byte) []byte { - var ( - hexLen = len(hex) // length of the hex input - firstByte = byte(0) - ) - // Check if we have a terminator there - if hexLen > 0 && hex[hexLen-1] == 16 { - firstByte = 1 << 5 - hexLen-- // last part was the terminator, ignore that - } - var ( - binLen = hexLen/2 + 1 - ni = 0 // index in hex - bi = 1 // index in bin (compact) - ) - if hexLen&1 == 1 { - firstByte |= 1 << 4 // odd flag - firstByte |= hex[0] // first nibble is contained in the first byte - ni++ - } - for ; ni < hexLen; bi, ni = bi+1, ni+2 { - hex[bi] = hex[ni]<<4 | hex[ni+1] - } - hex[0] = firstByte - return hex[:binLen] -} - -func compactToHex(compact []byte) []byte { - if len(compact) == 0 { - return compact - } - base := keybytesToHex(compact) - // delete terminator flag - if base[0] < 2 { - base = base[:len(base)-1] - } - // apply odd flag - chop := 2 - base[0]&1 - return base[chop:] -} - -func keybytesToHex(str []byte) []byte { - l := len(str)*2 + 1 - var nibbles = make([]byte, l) - for i, b := range str { - nibbles[i*2] = b / 16 - nibbles[i*2+1] = b % 16 - } - nibbles[l-1] = 16 - return nibbles -} - -// hexToKeybytes turns hex nibbles into key bytes. -// This can only be used for keys of even length. -func hexToKeybytes(hex []byte) []byte { - if hasTerm(hex) { - hex = hex[:len(hex)-1] - } - if len(hex)&1 != 0 { - panic("can't convert hex key of odd length") - } - key := make([]byte, len(hex)/2) - decodeNibbles(hex, key) - return key -} - -func decodeNibbles(nibbles []byte, bytes []byte) { - for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 { - bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1] - } -} - -// prefixLen returns the length of the common prefix of a and b. -func prefixLen(a, b []byte) int { - var i, length = 0, len(a) - if len(b) < length { - length = len(b) - } - for ; i < length; i++ { - if a[i] != b[i] { - break - } - } - return i -} - -// hasTerm returns whether a hex key has the terminator flag. -func hasTerm(s []byte) bool { - return len(s) > 0 && s[len(s)-1] == 16 -} diff --git a/trie/encoding_test.go b/trie/encoding_test.go deleted file mode 100644 index e25e4ae600..0000000000 --- a/trie/encoding_test.go +++ /dev/null @@ -1,156 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - crand "crypto/rand" - "encoding/hex" - "math/rand" - "testing" -) - -func TestHexCompact(t *testing.T) { - tests := []struct{ hex, compact []byte }{ - // empty keys, with and without terminator. - {hex: []byte{}, compact: []byte{0x00}}, - {hex: []byte{16}, compact: []byte{0x20}}, - // odd length, no terminator - {hex: []byte{1, 2, 3, 4, 5}, compact: []byte{0x11, 0x23, 0x45}}, - // even length, no terminator - {hex: []byte{0, 1, 2, 3, 4, 5}, compact: []byte{0x00, 0x01, 0x23, 0x45}}, - // odd length, terminator - {hex: []byte{15, 1, 12, 11, 8, 16 /*term*/}, compact: []byte{0x3f, 0x1c, 0xb8}}, - // even length, terminator - {hex: []byte{0, 15, 1, 12, 11, 8, 16 /*term*/}, compact: []byte{0x20, 0x0f, 0x1c, 0xb8}}, - } - for _, test := range tests { - if c := hexToCompact(test.hex); !bytes.Equal(c, test.compact) { - t.Errorf("hexToCompact(%x) -> %x, want %x", test.hex, c, test.compact) - } - if h := compactToHex(test.compact); !bytes.Equal(h, test.hex) { - t.Errorf("compactToHex(%x) -> %x, want %x", test.compact, h, test.hex) - } - } -} - -func TestHexKeybytes(t *testing.T) { - tests := []struct{ key, hexIn, hexOut []byte }{ - {key: []byte{}, hexIn: []byte{16}, hexOut: []byte{16}}, - {key: []byte{}, hexIn: []byte{}, hexOut: []byte{16}}, - { - key: []byte{0x12, 0x34, 0x56}, - hexIn: []byte{1, 2, 3, 4, 5, 6, 16}, - hexOut: []byte{1, 2, 3, 4, 5, 6, 16}, - }, - { - key: []byte{0x12, 0x34, 0x5}, - hexIn: []byte{1, 2, 3, 4, 0, 5, 16}, - hexOut: []byte{1, 2, 3, 4, 0, 5, 16}, - }, - { - key: []byte{0x12, 0x34, 0x56}, - hexIn: []byte{1, 2, 3, 4, 5, 6}, - hexOut: []byte{1, 2, 3, 4, 5, 6, 16}, - }, - } - for _, test := range tests { - if h := keybytesToHex(test.key); !bytes.Equal(h, test.hexOut) { - t.Errorf("keybytesToHex(%x) -> %x, want %x", test.key, h, test.hexOut) - } - if k := hexToKeybytes(test.hexIn); !bytes.Equal(k, test.key) { - t.Errorf("hexToKeybytes(%x) -> %x, want %x", test.hexIn, k, test.key) - } - } -} - -func TestHexToCompactInPlace(t *testing.T) { - for i, key := range []string{ - "00", - "060a040c0f000a090b040803010801010900080d090a0a0d0903000b10", - "10", - } { - hexBytes, _ := hex.DecodeString(key) - exp := hexToCompact(hexBytes) - got := hexToCompactInPlace(hexBytes) - if !bytes.Equal(exp, got) { - t.Fatalf("test %d: encoding err\ninp %v\ngot %x\nexp %x\n", i, key, got, exp) - } - } -} - -func TestHexToCompactInPlaceRandom(t *testing.T) { - for i := 0; i < 10000; i++ { - l := rand.Intn(128) - key := make([]byte, l) - crand.Read(key) - hexBytes := keybytesToHex(key) - hexOrig := []byte(string(hexBytes)) - exp := hexToCompact(hexBytes) - got := hexToCompactInPlace(hexBytes) - - if !bytes.Equal(exp, got) { - t.Fatalf("encoding err \ncpt %x\nhex %x\ngot %x\nexp %x\n", - key, hexOrig, got, exp) - } - } -} - -func BenchmarkHexToCompact(b *testing.B) { - testBytes := []byte{0, 15, 1, 12, 11, 8, 16 /*term*/} - for i := 0; i < b.N; i++ { - hexToCompact(testBytes) - } -} - -func BenchmarkHexToCompactInPlace(b *testing.B) { - testBytes := []byte{0, 15, 1, 12, 11, 8, 16 /*term*/} - for i := 0; i < b.N; i++ { - hexToCompactInPlace(testBytes) - } -} - -func BenchmarkCompactToHex(b *testing.B) { - testBytes := []byte{0, 15, 1, 12, 11, 8, 16 /*term*/} - for i := 0; i < b.N; i++ { - compactToHex(testBytes) - } -} - -func BenchmarkKeybytesToHex(b *testing.B) { - testBytes := []byte{7, 6, 6, 5, 7, 2, 6, 2, 16} - for i := 0; i < b.N; i++ { - keybytesToHex(testBytes) - } -} - -func BenchmarkHexToKeybytes(b *testing.B) { - testBytes := []byte{7, 6, 6, 5, 7, 2, 6, 2, 16} - for i := 0; i < b.N; i++ { - hexToKeybytes(testBytes) - } -} diff --git a/trie/errors.go b/trie/errors.go deleted file mode 100644 index 307a5f8747..0000000000 --- a/trie/errors.go +++ /dev/null @@ -1,62 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common" -) - -// ErrCommitted is returned when a already committed trie is requested for usage. -// The potential usages can be `Get`, `Update`, `Delete`, `NodeIterator`, `Prove` -// and so on. -var ErrCommitted = errors.New("trie is already committed") - -// MissingNodeError is returned by the trie functions (Get, Update, Delete) -// in the case where a trie node is not present in the local database. It contains -// information necessary for retrieving the missing node. -type MissingNodeError struct { - Owner common.Hash // owner of the trie if it's 2-layered trie - NodeHash common.Hash // hash of the missing node - Path []byte // hex-encoded path to the missing node - err error // concrete error for missing trie node -} - -// Unwrap returns the concrete error for missing trie node which -// allows us for further analysis outside. -func (err *MissingNodeError) Unwrap() error { - return err.err -} - -func (err *MissingNodeError) Error() string { - if err.Owner == (common.Hash{}) { - return fmt.Sprintf("missing trie node %x (path %x) %v", err.NodeHash, err.Path, err.err) - } - return fmt.Sprintf("missing trie node %x (owner %x) (path %x) %v", err.NodeHash, err.Owner, err.Path, err.err) -} diff --git a/trie/hasher.go b/trie/hasher.go deleted file mode 100644 index d281547e11..0000000000 --- a/trie/hasher.go +++ /dev/null @@ -1,218 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "sync" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/crypto/sha3" -) - -// hasher is a type used for the trie Hash operation. A hasher has some -// internal preallocated temp space -type hasher struct { - sha crypto.KeccakState - tmp []byte - encbuf rlp.EncoderBuffer - parallel bool // Whether to use parallel threads when hashing -} - -// hasherPool holds pureHashers -var hasherPool = sync.Pool{ - New: func() interface{} { - return &hasher{ - tmp: make([]byte, 0, 550), // cap is as large as a full fullNode. - sha: sha3.NewLegacyKeccak256().(crypto.KeccakState), - encbuf: rlp.NewEncoderBuffer(nil), - } - }, -} - -func newHasher(parallel bool) *hasher { - h := hasherPool.Get().(*hasher) - h.parallel = parallel - return h -} - -func returnHasherToPool(h *hasher) { - hasherPool.Put(h) -} - -// hash collapses a node down into a hash node, also returning a copy of the -// original node initialized with the computed hash to replace the original one. -func (h *hasher) hash(n node, force bool) (hashed node, cached node) { - // Return the cached hash if it's available - if hash, _ := n.cache(); hash != nil { - return hash, n - } - // Trie not processed yet, walk the children - switch n := n.(type) { - case *shortNode: - collapsed, cached := h.hashShortNodeChildren(n) - hashed := h.shortnodeToHash(collapsed, force) - // We need to retain the possibly _not_ hashed node, in case it was too - // small to be hashed - if hn, ok := hashed.(hashNode); ok { - cached.flags.hash = hn - } else { - cached.flags.hash = nil - } - return hashed, cached - case *fullNode: - collapsed, cached := h.hashFullNodeChildren(n) - hashed = h.fullnodeToHash(collapsed, force) - if hn, ok := hashed.(hashNode); ok { - cached.flags.hash = hn - } else { - cached.flags.hash = nil - } - return hashed, cached - default: - // Value and hash nodes don't have children, so they're left as were - return n, n - } -} - -// hashShortNodeChildren collapses the short node. The returned collapsed node -// holds a live reference to the Key, and must not be modified. -func (h *hasher) hashShortNodeChildren(n *shortNode) (collapsed, cached *shortNode) { - // Hash the short node's child, caching the newly hashed subtree - collapsed, cached = n.copy(), n.copy() - // Previously, we did copy this one. We don't seem to need to actually - // do that, since we don't overwrite/reuse keys - // cached.Key = common.CopyBytes(n.Key) - collapsed.Key = hexToCompact(n.Key) - // Unless the child is a valuenode or hashnode, hash it - switch n.Val.(type) { - case *fullNode, *shortNode: - collapsed.Val, cached.Val = h.hash(n.Val, false) - } - return collapsed, cached -} - -func (h *hasher) hashFullNodeChildren(n *fullNode) (collapsed *fullNode, cached *fullNode) { - // Hash the full node's children, caching the newly hashed subtrees - cached = n.copy() - collapsed = n.copy() - if h.parallel { - var wg sync.WaitGroup - wg.Add(16) - for i := 0; i < 16; i++ { - go func(i int) { - hasher := newHasher(false) - if child := n.Children[i]; child != nil { - collapsed.Children[i], cached.Children[i] = hasher.hash(child, false) - } else { - collapsed.Children[i] = nilValueNode - } - returnHasherToPool(hasher) - wg.Done() - }(i) - } - wg.Wait() - } else { - for i := 0; i < 16; i++ { - if child := n.Children[i]; child != nil { - collapsed.Children[i], cached.Children[i] = h.hash(child, false) - } else { - collapsed.Children[i] = nilValueNode - } - } - } - return collapsed, cached -} - -// shortnodeToHash creates a hashNode from a shortNode. The supplied shortnode -// should have hex-type Key, which will be converted (without modification) -// into compact form for RLP encoding. -// If the rlp data is smaller than 32 bytes, `nil` is returned. -func (h *hasher) shortnodeToHash(n *shortNode, force bool) node { - n.encode(h.encbuf) - enc := h.encodedBytes() - - if len(enc) < 32 && !force { - return n // Nodes smaller than 32 bytes are stored inside their parent - } - return h.hashData(enc) -} - -// fullnodeToHash is used to create a hashNode from a fullNode, (which -// may contain nil values) -func (h *hasher) fullnodeToHash(n *fullNode, force bool) node { - n.encode(h.encbuf) - enc := h.encodedBytes() - - if len(enc) < 32 && !force { - return n // Nodes smaller than 32 bytes are stored inside their parent - } - return h.hashData(enc) -} - -// encodedBytes returns the result of the last encoding operation on h.encbuf. -// This also resets the encoder buffer. -// -// All node encoding must be done like this: -// -// node.encode(h.encbuf) -// enc := h.encodedBytes() -// -// This convention exists because node.encode can only be inlined/escape-analyzed when -// called on a concrete receiver type. -func (h *hasher) encodedBytes() []byte { - h.tmp = h.encbuf.AppendToBytes(h.tmp[:0]) - h.encbuf.Reset(nil) - return h.tmp -} - -// hashData hashes the provided data -func (h *hasher) hashData(data []byte) hashNode { - n := make(hashNode, 32) - h.sha.Reset() - h.sha.Write(data) - h.sha.Read(n) - return n -} - -// proofHash is used to construct trie proofs, and returns the 'collapsed' -// node (for later RLP encoding) as well as the hashed node -- unless the -// node is smaller than 32 bytes, in which case it will be returned as is. -// This method does not do anything on value- or hash-nodes. -func (h *hasher) proofHash(original node) (collapsed, hashed node) { - switch n := original.(type) { - case *shortNode: - sn, _ := h.hashShortNodeChildren(n) - return sn, h.shortnodeToHash(sn, false) - case *fullNode: - fn, _ := h.hashFullNodeChildren(n) - return fn, h.fullnodeToHash(fn, false) - default: - // Value and hash nodes don't have children, so they're left as were - return n, n - } -} diff --git a/trie/iterator.go b/trie/iterator.go deleted file mode 100644 index 86d57f4ef2..0000000000 --- a/trie/iterator.go +++ /dev/null @@ -1,801 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "container/heap" - "errors" - - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ethereum/go-ethereum/common" -) - -// NodeResolver is used for looking up trie nodes before reaching into the real -// persistent layer. This is not mandatory, rather is an optimization for cases -// where trie nodes can be recovered from some external mechanism without reading -// from disk. In those cases, this resolver allows short circuiting accesses and -// returning them from memory. -type NodeResolver func(owner common.Hash, path []byte, hash common.Hash) []byte - -// Iterator is a key-value trie iterator that traverses a Trie. -type Iterator struct { - nodeIt NodeIterator - - Key []byte // Current data key on which the iterator is positioned on - Value []byte // Current data value on which the iterator is positioned on - Err error -} - -// NewIterator creates a new key-value iterator from a node iterator. -// Note that the value returned by the iterator is raw. If the content is encoded -// (e.g. storage value is RLP-encoded), it's caller's duty to decode it. -func NewIterator(it NodeIterator) *Iterator { - return &Iterator{ - nodeIt: it, - } -} - -// Next moves the iterator forward one key-value entry. -func (it *Iterator) Next() bool { - for it.nodeIt.Next(true) { - if it.nodeIt.Leaf() { - it.Key = it.nodeIt.LeafKey() - it.Value = it.nodeIt.LeafBlob() - return true - } - } - it.Key = nil - it.Value = nil - it.Err = it.nodeIt.Error() - return false -} - -// Prove generates the Merkle proof for the leaf node the iterator is currently -// positioned on. -func (it *Iterator) Prove() [][]byte { - return it.nodeIt.LeafProof() -} - -// NodeIterator is an iterator to traverse the trie pre-order. -type NodeIterator interface { - // Next moves the iterator to the next node. If the parameter is false, any child - // nodes will be skipped. - Next(bool) bool - - // Error returns the error status of the iterator. - Error() error - - // Hash returns the hash of the current node. - Hash() common.Hash - - // Parent returns the hash of the parent of the current node. The hash may be the one - // grandparent if the immediate parent is an internal node with no hash. - Parent() common.Hash - - // Path returns the hex-encoded path to the current node. - // Callers must not retain references to the return value after calling Next. - // For leaf nodes, the last element of the path is the 'terminator symbol' 0x10. - Path() []byte - - // NodeBlob returns the rlp-encoded value of the current iterated node. - // If the node is an embedded node in its parent, nil is returned then. - NodeBlob() []byte - - // Leaf returns true iff the current node is a leaf node. - Leaf() bool - - // LeafKey returns the key of the leaf. The method panics if the iterator is not - // positioned at a leaf. Callers must not retain references to the value after - // calling Next. - LeafKey() []byte - - // LeafBlob returns the content of the leaf. The method panics if the iterator - // is not positioned at a leaf. Callers must not retain references to the value - // after calling Next. - LeafBlob() []byte - - // LeafProof returns the Merkle proof of the leaf. The method panics if the - // iterator is not positioned at a leaf. Callers must not retain references - // to the value after calling Next. - LeafProof() [][]byte - - // AddResolver sets a node resolver to use for looking up trie nodes before - // reaching into the real persistent layer. - // - // This is not required for normal operation, rather is an optimization for - // cases where trie nodes can be recovered from some external mechanism without - // reading from disk. In those cases, this resolver allows short circuiting - // accesses and returning them from memory. - // - // Before adding a similar mechanism to any other place in Geth, consider - // making trie.Database an interface and wrapping at that level. It's a huge - // refactor, but it could be worth it if another occurrence arises. - AddResolver(NodeResolver) -} - -// nodeIteratorState represents the iteration state at one particular node of the -// trie, which can be resumed at a later invocation. -type nodeIteratorState struct { - hash common.Hash // Hash of the node being iterated (nil if not standalone) - node node // Trie node being iterated - parent common.Hash // Hash of the first full ancestor node (nil if current is the root) - index int // Child to be processed next - pathlen int // Length of the path to this node -} - -type nodeIterator struct { - trie *Trie // Trie being iterated - stack []*nodeIteratorState // Hierarchy of trie nodes persisting the iteration state - path []byte // Path to the current node - err error // Failure set in case of an internal error in the iterator - - resolver NodeResolver // optional node resolver for avoiding disk hits - pool []*nodeIteratorState // local pool for iteratorstates -} - -// errIteratorEnd is stored in nodeIterator.err when iteration is done. -var errIteratorEnd = errors.New("end of iteration") - -// seekError is stored in nodeIterator.err if the initial seek has failed. -type seekError struct { - key []byte - err error -} - -func (e seekError) Error() string { - return "seek error: " + e.err.Error() -} - -func newNodeIterator(trie *Trie, start []byte) NodeIterator { - if trie.Hash() == types.EmptyRootHash { - return &nodeIterator{ - trie: trie, - err: errIteratorEnd, - } - } - it := &nodeIterator{trie: trie} - it.err = it.seek(start) - return it -} - -func (it *nodeIterator) putInPool(item *nodeIteratorState) { - if len(it.pool) < 40 { - item.node = nil - it.pool = append(it.pool, item) - } -} - -func (it *nodeIterator) getFromPool() *nodeIteratorState { - idx := len(it.pool) - 1 - if idx < 0 { - return new(nodeIteratorState) - } - el := it.pool[idx] - it.pool[idx] = nil - it.pool = it.pool[:idx] - return el -} - -func (it *nodeIterator) AddResolver(resolver NodeResolver) { - it.resolver = resolver -} - -func (it *nodeIterator) Hash() common.Hash { - if len(it.stack) == 0 { - return common.Hash{} - } - return it.stack[len(it.stack)-1].hash -} - -func (it *nodeIterator) Parent() common.Hash { - if len(it.stack) == 0 { - return common.Hash{} - } - return it.stack[len(it.stack)-1].parent -} - -func (it *nodeIterator) Leaf() bool { - return hasTerm(it.path) -} - -func (it *nodeIterator) LeafKey() []byte { - if len(it.stack) > 0 { - if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { - return hexToKeybytes(it.path) - } - } - panic("not at leaf") -} - -func (it *nodeIterator) LeafBlob() []byte { - if len(it.stack) > 0 { - if node, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { - return node - } - } - panic("not at leaf") -} - -func (it *nodeIterator) LeafProof() [][]byte { - if len(it.stack) > 0 { - if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { - hasher := newHasher(false) - defer returnHasherToPool(hasher) - proofs := make([][]byte, 0, len(it.stack)) - - for i, item := range it.stack[:len(it.stack)-1] { - // Gather nodes that end up as hash nodes (or the root) - node, hashed := hasher.proofHash(item.node) - if _, ok := hashed.(hashNode); ok || i == 0 { - proofs = append(proofs, nodeToBytes(node)) - } - } - return proofs - } - } - panic("not at leaf") -} - -func (it *nodeIterator) Path() []byte { - return it.path -} - -func (it *nodeIterator) NodeBlob() []byte { - if it.Hash() == (common.Hash{}) { - return nil // skip the non-standalone node - } - blob, err := it.resolveBlob(it.Hash().Bytes(), it.Path()) - if err != nil { - it.err = err - return nil - } - return blob -} - -func (it *nodeIterator) Error() error { - if it.err == errIteratorEnd { - return nil - } - if seek, ok := it.err.(seekError); ok { - return seek.err - } - return it.err -} - -// Next moves the iterator to the next node, returning whether there are any -// further nodes. In case of an internal error this method returns false and -// sets the Error field to the encountered failure. If `descend` is false, -// skips iterating over any subnodes of the current node. -func (it *nodeIterator) Next(descend bool) bool { - if it.err == errIteratorEnd { - return false - } - if seek, ok := it.err.(seekError); ok { - if it.err = it.seek(seek.key); it.err != nil { - return false - } - } - // Otherwise step forward with the iterator and report any errors. - state, parentIndex, path, err := it.peek(descend) - it.err = err - if it.err != nil { - return false - } - it.push(state, parentIndex, path) - return true -} - -func (it *nodeIterator) seek(prefix []byte) error { - // The path we're looking for is the hex encoded key without terminator. - key := keybytesToHex(prefix) - key = key[:len(key)-1] - // Move forward until we're just before the closest match to key. - for { - state, parentIndex, path, err := it.peekSeek(key) - if err == errIteratorEnd { - return errIteratorEnd - } else if err != nil { - return seekError{prefix, err} - } else if bytes.Compare(path, key) >= 0 { - return nil - } - it.push(state, parentIndex, path) - } -} - -// init initializes the iterator. -func (it *nodeIterator) init() (*nodeIteratorState, error) { - root := it.trie.Hash() - state := &nodeIteratorState{node: it.trie.root, index: -1} - if root != types.EmptyRootHash { - state.hash = root - } - return state, state.resolve(it, nil) -} - -// peek creates the next state of the iterator. -func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, error) { - // Initialize the iterator if we've just started. - if len(it.stack) == 0 { - state, err := it.init() - return state, nil, nil, err - } - if !descend { - // If we're skipping children, pop the current node first - it.pop() - } - - // Continue iteration to the next child - for len(it.stack) > 0 { - parent := it.stack[len(it.stack)-1] - ancestor := parent.hash - if (ancestor == common.Hash{}) { - ancestor = parent.parent - } - state, path, ok := it.nextChild(parent, ancestor) - if ok { - if err := state.resolve(it, path); err != nil { - return parent, &parent.index, path, err - } - return state, &parent.index, path, nil - } - // No more child nodes, move back up. - it.pop() - } - return nil, nil, nil, errIteratorEnd -} - -// peekSeek is like peek, but it also tries to skip resolving hashes by skipping -// over the siblings that do not lead towards the desired seek position. -func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []byte, error) { - // Initialize the iterator if we've just started. - if len(it.stack) == 0 { - state, err := it.init() - return state, nil, nil, err - } - if !bytes.HasPrefix(seekKey, it.path) { - // If we're skipping children, pop the current node first - it.pop() - } - - // Continue iteration to the next child - for len(it.stack) > 0 { - parent := it.stack[len(it.stack)-1] - ancestor := parent.hash - if (ancestor == common.Hash{}) { - ancestor = parent.parent - } - state, path, ok := it.nextChildAt(parent, ancestor, seekKey) - if ok { - if err := state.resolve(it, path); err != nil { - return parent, &parent.index, path, err - } - return state, &parent.index, path, nil - } - // No more child nodes, move back up. - it.pop() - } - return nil, nil, nil, errIteratorEnd -} - -func (it *nodeIterator) resolveHash(hash hashNode, path []byte) (node, error) { - if it.resolver != nil { - if blob := it.resolver(it.trie.owner, path, common.BytesToHash(hash)); len(blob) > 0 { - if resolved, err := decodeNode(hash, blob); err == nil { - return resolved, nil - } - } - } - // Retrieve the specified node from the underlying node reader. - // it.trie.resolveAndTrack is not used since in that function the - // loaded blob will be tracked, while it's not required here since - // all loaded nodes won't be linked to trie at all and track nodes - // may lead to out-of-memory issue. - blob, err := it.trie.reader.node(path, common.BytesToHash(hash)) - if err != nil { - return nil, err - } - // The raw-blob format nodes are loaded either from the - // clean cache or the database, they are all in their own - // copy and safe to use unsafe decoder. - return mustDecodeNodeUnsafe(hash, blob), nil -} - -func (it *nodeIterator) resolveBlob(hash hashNode, path []byte) ([]byte, error) { - if it.resolver != nil { - if blob := it.resolver(it.trie.owner, path, common.BytesToHash(hash)); len(blob) > 0 { - return blob, nil - } - } - // Retrieve the specified node from the underlying node reader. - // it.trie.resolveAndTrack is not used since in that function the - // loaded blob will be tracked, while it's not required here since - // all loaded nodes won't be linked to trie at all and track nodes - // may lead to out-of-memory issue. - return it.trie.reader.node(path, common.BytesToHash(hash)) -} - -func (st *nodeIteratorState) resolve(it *nodeIterator, path []byte) error { - if hash, ok := st.node.(hashNode); ok { - resolved, err := it.resolveHash(hash, path) - if err != nil { - return err - } - st.node = resolved - st.hash = common.BytesToHash(hash) - } - return nil -} - -func (it *nodeIterator) findChild(n *fullNode, index int, ancestor common.Hash) (node, *nodeIteratorState, []byte, int) { - var ( - path = it.path - child node - state *nodeIteratorState - childPath []byte - ) - for ; index < len(n.Children); index++ { - if n.Children[index] != nil { - child = n.Children[index] - hash, _ := child.cache() - state = it.getFromPool() - state.hash = common.BytesToHash(hash) - state.node = child - state.parent = ancestor - state.index = -1 - state.pathlen = len(path) - childPath = append(childPath, path...) - childPath = append(childPath, byte(index)) - return child, state, childPath, index - } - } - return nil, nil, nil, 0 -} - -func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Hash) (*nodeIteratorState, []byte, bool) { - switch node := parent.node.(type) { - case *fullNode: - // Full node, move to the first non-nil child. - if child, state, path, index := it.findChild(node, parent.index+1, ancestor); child != nil { - parent.index = index - 1 - return state, path, true - } - case *shortNode: - // Short node, return the pointer singleton child - if parent.index < 0 { - hash, _ := node.Val.cache() - state := it.getFromPool() - state.hash = common.BytesToHash(hash) - state.node = node.Val - state.parent = ancestor - state.index = -1 - state.pathlen = len(it.path) - path := append(it.path, node.Key...) - return state, path, true - } - } - return parent, it.path, false -} - -// nextChildAt is similar to nextChild, except that it targets a child as close to the -// target key as possible, thus skipping siblings. -func (it *nodeIterator) nextChildAt(parent *nodeIteratorState, ancestor common.Hash, key []byte) (*nodeIteratorState, []byte, bool) { - switch n := parent.node.(type) { - case *fullNode: - // Full node, move to the first non-nil child before the desired key position - child, state, path, index := it.findChild(n, parent.index+1, ancestor) - if child == nil { - // No more children in this fullnode - return parent, it.path, false - } - // If the child we found is already past the seek position, just return it. - if bytes.Compare(path, key) >= 0 { - parent.index = index - 1 - return state, path, true - } - // The child is before the seek position. Try advancing - for { - nextChild, nextState, nextPath, nextIndex := it.findChild(n, index+1, ancestor) - // If we run out of children, or skipped past the target, return the - // previous one - if nextChild == nil || bytes.Compare(nextPath, key) >= 0 { - parent.index = index - 1 - return state, path, true - } - // We found a better child closer to the target - state, path, index = nextState, nextPath, nextIndex - } - case *shortNode: - // Short node, return the pointer singleton child - if parent.index < 0 { - hash, _ := n.Val.cache() - state := it.getFromPool() - state.hash = common.BytesToHash(hash) - state.node = n.Val - state.parent = ancestor - state.index = -1 - state.pathlen = len(it.path) - path := append(it.path, n.Key...) - return state, path, true - } - } - return parent, it.path, false -} - -func (it *nodeIterator) push(state *nodeIteratorState, parentIndex *int, path []byte) { - it.path = path - it.stack = append(it.stack, state) - if parentIndex != nil { - *parentIndex++ - } -} - -func (it *nodeIterator) pop() { - last := it.stack[len(it.stack)-1] - it.path = it.path[:last.pathlen] - it.stack[len(it.stack)-1] = nil - it.stack = it.stack[:len(it.stack)-1] - // last is now unused - it.putInPool(last) -} - -func compareNodes(a, b NodeIterator) int { - if cmp := bytes.Compare(a.Path(), b.Path()); cmp != 0 { - return cmp - } - if a.Leaf() && !b.Leaf() { - return -1 - } else if b.Leaf() && !a.Leaf() { - return 1 - } - if cmp := bytes.Compare(a.Hash().Bytes(), b.Hash().Bytes()); cmp != 0 { - return cmp - } - if a.Leaf() && b.Leaf() { - return bytes.Compare(a.LeafBlob(), b.LeafBlob()) - } - return 0 -} - -type differenceIterator struct { - a, b NodeIterator // Nodes returned are those in b - a. - eof bool // Indicates a has run out of elements - count int // Number of nodes scanned on either trie -} - -// NewDifferenceIterator constructs a NodeIterator that iterates over elements in b that -// are not in a. Returns the iterator, and a pointer to an integer recording the number -// of nodes seen. -func NewDifferenceIterator(a, b NodeIterator) (NodeIterator, *int) { - a.Next(true) - it := &differenceIterator{ - a: a, - b: b, - } - return it, &it.count -} - -func (it *differenceIterator) Hash() common.Hash { - return it.b.Hash() -} - -func (it *differenceIterator) Parent() common.Hash { - return it.b.Parent() -} - -func (it *differenceIterator) Leaf() bool { - return it.b.Leaf() -} - -func (it *differenceIterator) LeafKey() []byte { - return it.b.LeafKey() -} - -func (it *differenceIterator) LeafBlob() []byte { - return it.b.LeafBlob() -} - -func (it *differenceIterator) LeafProof() [][]byte { - return it.b.LeafProof() -} - -func (it *differenceIterator) Path() []byte { - return it.b.Path() -} - -func (it *differenceIterator) NodeBlob() []byte { - return it.b.NodeBlob() -} - -func (it *differenceIterator) AddResolver(resolver NodeResolver) { - panic("not implemented") -} - -func (it *differenceIterator) Next(bool) bool { - // Invariants: - // - We always advance at least one element in b. - // - At the start of this function, a's path is lexically greater than b's. - if !it.b.Next(true) { - return false - } - it.count++ - - if it.eof { - // a has reached eof, so we just return all elements from b - return true - } - - for { - switch compareNodes(it.a, it.b) { - case -1: - // b jumped past a; advance a - if !it.a.Next(true) { - it.eof = true - return true - } - it.count++ - case 1: - // b is before a - return true - case 0: - // a and b are identical; skip this whole subtree if the nodes have hashes - hasHash := it.a.Hash() == common.Hash{} - if !it.b.Next(hasHash) { - return false - } - it.count++ - if !it.a.Next(hasHash) { - it.eof = true - return true - } - it.count++ - } - } -} - -func (it *differenceIterator) Error() error { - if err := it.a.Error(); err != nil { - return err - } - return it.b.Error() -} - -type nodeIteratorHeap []NodeIterator - -func (h nodeIteratorHeap) Len() int { return len(h) } -func (h nodeIteratorHeap) Less(i, j int) bool { return compareNodes(h[i], h[j]) < 0 } -func (h nodeIteratorHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } -func (h *nodeIteratorHeap) Push(x interface{}) { *h = append(*h, x.(NodeIterator)) } -func (h *nodeIteratorHeap) Pop() interface{} { - n := len(*h) - x := (*h)[n-1] - *h = (*h)[0 : n-1] - return x -} - -type unionIterator struct { - items *nodeIteratorHeap // Nodes returned are the union of the ones in these iterators - count int // Number of nodes scanned across all tries -} - -// NewUnionIterator constructs a NodeIterator that iterates over elements in the union -// of the provided NodeIterators. Returns the iterator, and a pointer to an integer -// recording the number of nodes visited. -func NewUnionIterator(iters []NodeIterator) (NodeIterator, *int) { - h := make(nodeIteratorHeap, len(iters)) - copy(h, iters) - heap.Init(&h) - - ui := &unionIterator{items: &h} - return ui, &ui.count -} - -func (it *unionIterator) Hash() common.Hash { - return (*it.items)[0].Hash() -} - -func (it *unionIterator) Parent() common.Hash { - return (*it.items)[0].Parent() -} - -func (it *unionIterator) Leaf() bool { - return (*it.items)[0].Leaf() -} - -func (it *unionIterator) LeafKey() []byte { - return (*it.items)[0].LeafKey() -} - -func (it *unionIterator) LeafBlob() []byte { - return (*it.items)[0].LeafBlob() -} - -func (it *unionIterator) LeafProof() [][]byte { - return (*it.items)[0].LeafProof() -} - -func (it *unionIterator) Path() []byte { - return (*it.items)[0].Path() -} - -func (it *unionIterator) NodeBlob() []byte { - return (*it.items)[0].NodeBlob() -} - -func (it *unionIterator) AddResolver(resolver NodeResolver) { - panic("not implemented") -} - -// Next returns the next node in the union of tries being iterated over. -// -// It does this by maintaining a heap of iterators, sorted by the iteration -// order of their next elements, with one entry for each source trie. Each -// time Next() is called, it takes the least element from the heap to return, -// advancing any other iterators that also point to that same element. These -// iterators are called with descend=false, since we know that any nodes under -// these nodes will also be duplicates, found in the currently selected iterator. -// Whenever an iterator is advanced, it is pushed back into the heap if it still -// has elements remaining. -// -// In the case that descend=false - eg, we're asked to ignore all subnodes of the -// current node - we also advance any iterators in the heap that have the current -// path as a prefix. -func (it *unionIterator) Next(descend bool) bool { - if len(*it.items) == 0 { - return false - } - - // Get the next key from the union - least := heap.Pop(it.items).(NodeIterator) - - // Skip over other nodes as long as they're identical, or, if we're not descending, as - // long as they have the same prefix as the current node. - for len(*it.items) > 0 && ((!descend && bytes.HasPrefix((*it.items)[0].Path(), least.Path())) || compareNodes(least, (*it.items)[0]) == 0) { - skipped := heap.Pop(it.items).(NodeIterator) - // Skip the whole subtree if the nodes have hashes; otherwise just skip this node - if skipped.Next(skipped.Hash() == common.Hash{}) { - it.count++ - // If there are more elements, push the iterator back on the heap - heap.Push(it.items, skipped) - } - } - if least.Next(descend) { - it.count++ - heap.Push(it.items, least) - } - return len(*it.items) > 0 -} - -func (it *unionIterator) Error() error { - for i := 0; i < len(*it.items); i++ { - if err := (*it.items)[i].Error(); err != nil { - return err - } - } - return nil -} diff --git a/trie/iterator_test.go b/trie/iterator_test.go deleted file mode 100644 index a329e27f6e..0000000000 --- a/trie/iterator_test.go +++ /dev/null @@ -1,641 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "fmt" - "math/rand" - "testing" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -func TestEmptyIterator(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - iter := trie.MustNodeIterator(nil) - - seen := make(map[string]struct{}) - for iter.Next(true) { - seen[string(iter.Path())] = struct{}{} - } - if len(seen) != 0 { - t.Fatal("Unexpected trie node iterated") - } -} - -func TestIterator(t *testing.T) { - db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie := NewEmpty(db) - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - all := make(map[string]string) - for _, val := range vals { - all[val.k] = val.v - trie.MustUpdate([]byte(val.k), []byte(val.v)) - } - root, nodes, _ := trie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - - trie, _ = New(TrieID(root), db) - found := make(map[string]string) - it := NewIterator(trie.MustNodeIterator(nil)) - for it.Next() { - found[string(it.Key)] = string(it.Value) - } - - for k, v := range all { - if found[k] != v { - t.Errorf("iterator value mismatch for %s: got %q want %q", k, found[k], v) - } - } -} - -type kv struct { - k, v []byte - t bool -} - -func (k *kv) cmp(other *kv) int { - return bytes.Compare(k.k, other.k) -} - -func TestIteratorLargeData(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - vals := make(map[string]*kv) - - for i := byte(0); i < 255; i++ { - value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} - value2 := &kv{common.LeftPadBytes([]byte{10, i}, 32), []byte{i}, false} - trie.MustUpdate(value.k, value.v) - trie.MustUpdate(value2.k, value2.v) - vals[string(value.k)] = value - vals[string(value2.k)] = value2 - } - - it := NewIterator(trie.MustNodeIterator(nil)) - for it.Next() { - vals[string(it.Key)].t = true - } - - var untouched []*kv - for _, value := range vals { - if !value.t { - untouched = append(untouched, value) - } - } - - if len(untouched) > 0 { - t.Errorf("Missed %d nodes", len(untouched)) - for _, value := range untouched { - t.Error(value) - } - } -} - -type iterationElement struct { - hash common.Hash - path []byte - blob []byte -} - -// Tests that the node iterator indeed walks over the entire database contents. -func TestNodeIteratorCoverage(t *testing.T) { - testNodeIteratorCoverage(t, rawdb.HashScheme) - testNodeIteratorCoverage(t, rawdb.PathScheme) -} - -func testNodeIteratorCoverage(t *testing.T, scheme string) { - // Create some arbitrary test trie to iterate - db, nodeDb, trie, _ := makeTestTrie(scheme) - - // Gather all the node hashes found by the iterator - var elements = make(map[common.Hash]iterationElement) - for it := trie.MustNodeIterator(nil); it.Next(true); { - if it.Hash() != (common.Hash{}) { - elements[it.Hash()] = iterationElement{ - hash: it.Hash(), - path: common.CopyBytes(it.Path()), - blob: common.CopyBytes(it.NodeBlob()), - } - } - } - // Cross check the hashes and the database itself - reader, err := nodeDb.Reader(trie.Hash()) - if err != nil { - t.Fatalf("state is not available %x", trie.Hash()) - } - for _, element := range elements { - if blob, err := reader.Node(common.Hash{}, element.path, element.hash); err != nil { - t.Errorf("failed to retrieve reported node %x: %v", element.hash, err) - } else if !bytes.Equal(blob, element.blob) { - t.Errorf("node blob is different, want %v got %v", element.blob, blob) - } - } - var ( - count int - it = db.NewIterator(nil, nil) - ) - for it.Next() { - res, _, _ := isTrieNode(nodeDb.Scheme(), it.Key(), it.Value()) - if !res { - continue - } - count += 1 - if elem, ok := elements[crypto.Keccak256Hash(it.Value())]; !ok { - t.Error("state entry not reported") - } else if !bytes.Equal(it.Value(), elem.blob) { - t.Errorf("node blob is different, want %v got %v", elem.blob, it.Value()) - } - } - it.Release() - if count != len(elements) { - t.Errorf("state entry is mismatched %d %d", count, len(elements)) - } -} - -type kvs struct{ k, v string } - -var testdata1 = []kvs{ - {"barb", "ba"}, - {"bard", "bc"}, - {"bars", "bb"}, - {"bar", "b"}, - {"fab", "z"}, - {"food", "ab"}, - {"foos", "aa"}, - {"foo", "a"}, -} - -var testdata2 = []kvs{ - {"aardvark", "c"}, - {"bar", "b"}, - {"barb", "bd"}, - {"bars", "be"}, - {"fab", "z"}, - {"foo", "a"}, - {"foos", "aa"}, - {"food", "ab"}, - {"jars", "d"}, -} - -func TestIteratorSeek(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - for _, val := range testdata1 { - trie.MustUpdate([]byte(val.k), []byte(val.v)) - } - - // Seek to the middle. - it := NewIterator(trie.MustNodeIterator([]byte("fab"))) - if err := checkIteratorOrder(testdata1[4:], it); err != nil { - t.Fatal(err) - } - - // Seek to a non-existent key. - it = NewIterator(trie.MustNodeIterator([]byte("barc"))) - if err := checkIteratorOrder(testdata1[1:], it); err != nil { - t.Fatal(err) - } - - // Seek beyond the end. - it = NewIterator(trie.MustNodeIterator([]byte("z"))) - if err := checkIteratorOrder(nil, it); err != nil { - t.Fatal(err) - } -} - -func checkIteratorOrder(want []kvs, it *Iterator) error { - for it.Next() { - if len(want) == 0 { - return fmt.Errorf("didn't expect any more values, got key %q", it.Key) - } - if !bytes.Equal(it.Key, []byte(want[0].k)) { - return fmt.Errorf("wrong key: got %q, want %q", it.Key, want[0].k) - } - want = want[1:] - } - if len(want) > 0 { - return fmt.Errorf("iterator ended early, want key %q", want[0]) - } - return nil -} - -func TestDifferenceIterator(t *testing.T) { - dba := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - triea := NewEmpty(dba) - for _, val := range testdata1 { - triea.MustUpdate([]byte(val.k), []byte(val.v)) - } - rootA, nodesA, _ := triea.Commit(false) - dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) - triea, _ = New(TrieID(rootA), dba) - - dbb := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trieb := NewEmpty(dbb) - for _, val := range testdata2 { - trieb.MustUpdate([]byte(val.k), []byte(val.v)) - } - rootB, nodesB, _ := trieb.Commit(false) - dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) - trieb, _ = New(TrieID(rootB), dbb) - - found := make(map[string]string) - di, _ := NewDifferenceIterator(triea.MustNodeIterator(nil), trieb.MustNodeIterator(nil)) - it := NewIterator(di) - for it.Next() { - found[string(it.Key)] = string(it.Value) - } - - all := []struct{ k, v string }{ - {"aardvark", "c"}, - {"barb", "bd"}, - {"bars", "be"}, - {"jars", "d"}, - } - for _, item := range all { - if found[item.k] != item.v { - t.Errorf("iterator value mismatch for %s: got %v want %v", item.k, found[item.k], item.v) - } - } - if len(found) != len(all) { - t.Errorf("iterator count mismatch: got %d values, want %d", len(found), len(all)) - } -} - -func TestUnionIterator(t *testing.T) { - dba := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - triea := NewEmpty(dba) - for _, val := range testdata1 { - triea.MustUpdate([]byte(val.k), []byte(val.v)) - } - rootA, nodesA, _ := triea.Commit(false) - dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) - triea, _ = New(TrieID(rootA), dba) - - dbb := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trieb := NewEmpty(dbb) - for _, val := range testdata2 { - trieb.MustUpdate([]byte(val.k), []byte(val.v)) - } - rootB, nodesB, _ := trieb.Commit(false) - dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) - trieb, _ = New(TrieID(rootB), dbb) - - di, _ := NewUnionIterator([]NodeIterator{triea.MustNodeIterator(nil), trieb.MustNodeIterator(nil)}) - it := NewIterator(di) - - all := []struct{ k, v string }{ - {"aardvark", "c"}, - {"barb", "ba"}, - {"barb", "bd"}, - {"bard", "bc"}, - {"bars", "bb"}, - {"bars", "be"}, - {"bar", "b"}, - {"fab", "z"}, - {"food", "ab"}, - {"foos", "aa"}, - {"foo", "a"}, - {"jars", "d"}, - } - - for i, kv := range all { - if !it.Next() { - t.Errorf("Iterator ends prematurely at element %d", i) - } - if kv.k != string(it.Key) { - t.Errorf("iterator value mismatch for element %d: got key %s want %s", i, it.Key, kv.k) - } - if kv.v != string(it.Value) { - t.Errorf("iterator value mismatch for element %d: got value %s want %s", i, it.Value, kv.v) - } - } - if it.Next() { - t.Errorf("Iterator returned extra values.") - } -} - -func TestIteratorNoDups(t *testing.T) { - db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - tr := NewEmpty(db) - for _, val := range testdata1 { - tr.MustUpdate([]byte(val.k), []byte(val.v)) - } - checkIteratorNoDups(t, tr.MustNodeIterator(nil), nil) -} - -// This test checks that nodeIterator.Next can be retried after inserting missing trie nodes. -func TestIteratorContinueAfterError(t *testing.T) { - testIteratorContinueAfterError(t, false, rawdb.HashScheme) - testIteratorContinueAfterError(t, true, rawdb.HashScheme) - testIteratorContinueAfterError(t, false, rawdb.PathScheme) - testIteratorContinueAfterError(t, true, rawdb.PathScheme) -} - -func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) { - diskdb := rawdb.NewMemoryDatabase() - tdb := newTestDatabase(diskdb, scheme) - - tr := NewEmpty(tdb) - for _, val := range testdata1 { - tr.MustUpdate([]byte(val.k), []byte(val.v)) - } - root, nodes, _ := tr.Commit(false) - tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - if !memonly { - tdb.Commit(root) - } - tr, _ = New(TrieID(root), tdb) - wantNodeCount := checkIteratorNoDups(t, tr.MustNodeIterator(nil), nil) - - var ( - paths [][]byte - hashes []common.Hash - ) - if memonly { - for path, n := range nodes.Nodes { - paths = append(paths, []byte(path)) - hashes = append(hashes, n.Hash) - } - } else { - it := diskdb.NewIterator(nil, nil) - for it.Next() { - ok, path, hash := isTrieNode(tdb.Scheme(), it.Key(), it.Value()) - if !ok { - continue - } - paths = append(paths, path) - hashes = append(hashes, hash) - } - it.Release() - } - for i := 0; i < 20; i++ { - // Create trie that will load all nodes from DB. - tr, _ := New(TrieID(tr.Hash()), tdb) - - // Remove a random node from the database. It can't be the root node - // because that one is already loaded. - var ( - rval []byte - rpath []byte - rhash common.Hash - ) - for { - if memonly { - rpath = paths[rand.Intn(len(paths))] - n := nodes.Nodes[string(rpath)] - if n == nil { - continue - } - rhash = n.Hash - } else { - index := rand.Intn(len(paths)) - rpath = paths[index] - rhash = hashes[index] - } - if rhash != tr.Hash() { - break - } - } - if memonly { - tr.reader.banned = map[string]struct{}{string(rpath): {}} - } else { - rval = rawdb.ReadTrieNode(diskdb, common.Hash{}, rpath, rhash, tdb.Scheme()) - rawdb.DeleteTrieNode(diskdb, common.Hash{}, rpath, rhash, tdb.Scheme()) - } - // Iterate until the error is hit. - seen := make(map[string]bool) - it := tr.MustNodeIterator(nil) - checkIteratorNoDups(t, it, seen) - missing, ok := it.Error().(*MissingNodeError) - if !ok || missing.NodeHash != rhash { - t.Fatal("didn't hit missing node, got", it.Error()) - } - - // Add the node back and continue iteration. - if memonly { - delete(tr.reader.banned, string(rpath)) - } else { - rawdb.WriteTrieNode(diskdb, common.Hash{}, rpath, rhash, rval, tdb.Scheme()) - } - checkIteratorNoDups(t, it, seen) - if it.Error() != nil { - t.Fatal("unexpected error", it.Error()) - } - if len(seen) != wantNodeCount { - t.Fatal("wrong node iteration count, got", len(seen), "want", wantNodeCount) - } - } -} - -// Similar to the test above, this one checks that failure to create nodeIterator at a -// certain key prefix behaves correctly when Next is called. The expectation is that Next -// should retry seeking before returning true for the first time. -func TestIteratorContinueAfterSeekError(t *testing.T) { - testIteratorContinueAfterSeekError(t, false, rawdb.HashScheme) - testIteratorContinueAfterSeekError(t, true, rawdb.HashScheme) - testIteratorContinueAfterSeekError(t, false, rawdb.PathScheme) - testIteratorContinueAfterSeekError(t, true, rawdb.PathScheme) -} - -func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme string) { - // Commit test trie to db, then remove the node containing "bars". - var ( - barNodePath []byte - barNodeHash = common.HexToHash("05041990364eb72fcb1127652ce40d8bab765f2bfe53225b1170d276cc101c2e") - ) - diskdb := rawdb.NewMemoryDatabase() - triedb := newTestDatabase(diskdb, scheme) - ctr := NewEmpty(triedb) - for _, val := range testdata1 { - ctr.MustUpdate([]byte(val.k), []byte(val.v)) - } - root, nodes, _ := ctr.Commit(false) - for path, n := range nodes.Nodes { - if n.Hash == barNodeHash { - barNodePath = []byte(path) - break - } - } - triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - if !memonly { - triedb.Commit(root) - } - var ( - barNodeBlob []byte - ) - tr, _ := New(TrieID(root), triedb) - if memonly { - tr.reader.banned = map[string]struct{}{string(barNodePath): {}} - } else { - barNodeBlob = rawdb.ReadTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, triedb.Scheme()) - rawdb.DeleteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, triedb.Scheme()) - } - // Create a new iterator that seeks to "bars". Seeking can't proceed because - // the node is missing. - it := tr.MustNodeIterator([]byte("bars")) - missing, ok := it.Error().(*MissingNodeError) - if !ok { - t.Fatal("want MissingNodeError, got", it.Error()) - } else if missing.NodeHash != barNodeHash { - t.Fatal("wrong node missing") - } - // Reinsert the missing node. - if memonly { - delete(tr.reader.banned, string(barNodePath)) - } else { - rawdb.WriteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, barNodeBlob, triedb.Scheme()) - } - // Check that iteration produces the right set of values. - if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil { - t.Fatal(err) - } -} - -func checkIteratorNoDups(t *testing.T, it NodeIterator, seen map[string]bool) int { - if seen == nil { - seen = make(map[string]bool) - } - for it.Next(true) { - if seen[string(it.Path())] { - t.Fatalf("iterator visited node path %x twice", it.Path()) - } - seen[string(it.Path())] = true - } - return len(seen) -} - -func TestIteratorNodeBlob(t *testing.T) { - testIteratorNodeBlob(t, rawdb.HashScheme) - testIteratorNodeBlob(t, rawdb.PathScheme) -} - -func testIteratorNodeBlob(t *testing.T, scheme string) { - var ( - db = rawdb.NewMemoryDatabase() - triedb = newTestDatabase(db, scheme) - trie = NewEmpty(triedb) - ) - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - all := make(map[string]string) - for _, val := range vals { - all[val.k] = val.v - trie.MustUpdate([]byte(val.k), []byte(val.v)) - } - root, nodes, _ := trie.Commit(false) - triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - triedb.Commit(root) - - var found = make(map[common.Hash][]byte) - trie, _ = New(TrieID(root), triedb) - it := trie.MustNodeIterator(nil) - for it.Next(true) { - if it.Hash() == (common.Hash{}) { - continue - } - found[it.Hash()] = it.NodeBlob() - } - - dbIter := db.NewIterator(nil, nil) - defer dbIter.Release() - - var count int - for dbIter.Next() { - ok, _, _ := isTrieNode(triedb.Scheme(), dbIter.Key(), dbIter.Value()) - if !ok { - continue - } - got, present := found[crypto.Keccak256Hash(dbIter.Value())] - if !present { - t.Fatal("Miss trie node") - } - if !bytes.Equal(got, dbIter.Value()) { - t.Fatalf("Unexpected trie node want %v got %v", dbIter.Value(), got) - } - count += 1 - } - if count != len(found) { - t.Fatal("Find extra trie node via iterator") - } -} - -// isTrieNode is a helper function which reports if the provided -// database entry belongs to a trie node or not. Note in tests -// only single layer trie is used, namely storage trie is not -// considered at all. -func isTrieNode(scheme string, key, val []byte) (bool, []byte, common.Hash) { - var ( - path []byte - hash common.Hash - ) - if scheme == rawdb.HashScheme { - ok := rawdb.IsLegacyTrieNode(key, val) - if !ok { - return false, nil, common.Hash{} - } - hash = common.BytesToHash(key) - } else { - ok, remain := rawdb.ResolveAccountTrieNodeKey(key) - if !ok { - return false, nil, common.Hash{} - } - path = common.CopyBytes(remain) - hash = crypto.Keccak256Hash(val) - } - return true, path, hash -} - -func BenchmarkIterator(b *testing.B) { - diskDb, srcDb, tr, _ := makeTestTrie(rawdb.HashScheme) - root := tr.Hash() - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := checkTrieConsistency(diskDb, srcDb.Scheme(), root, false); err != nil { - b.Fatal(err) - } - } -} diff --git a/trie/node.go b/trie/node.go deleted file mode 100644 index 8a8bc3ad1a..0000000000 --- a/trie/node.go +++ /dev/null @@ -1,264 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "fmt" - "io" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" -) - -var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "[17]"} - -type node interface { - cache() (hashNode, bool) - encode(w rlp.EncoderBuffer) - fstring(string) string -} - -type ( - fullNode struct { - Children [17]node // Actual trie node data to encode/decode (needs custom encoder) - flags nodeFlag - } - shortNode struct { - Key []byte - Val node - flags nodeFlag - } - hashNode []byte - valueNode []byte -) - -// nilValueNode is used when collapsing internal trie nodes for hashing, since -// unset children need to serialize correctly. -var nilValueNode = valueNode(nil) - -// EncodeRLP encodes a full node into the consensus RLP format. -func (n *fullNode) EncodeRLP(w io.Writer) error { - eb := rlp.NewEncoderBuffer(w) - n.encode(eb) - return eb.Flush() -} - -func (n *fullNode) copy() *fullNode { copy := *n; return © } -func (n *shortNode) copy() *shortNode { copy := *n; return © } - -// nodeFlag contains caching-related metadata about a node. -type nodeFlag struct { - hash hashNode // cached hash of the node (may be nil) - dirty bool // whether the node has changes that must be written to the database -} - -func (n *fullNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty } -func (n *shortNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty } -func (n hashNode) cache() (hashNode, bool) { return nil, true } -func (n valueNode) cache() (hashNode, bool) { return nil, true } - -// Pretty printing. -func (n *fullNode) String() string { return n.fstring("") } -func (n *shortNode) String() string { return n.fstring("") } -func (n hashNode) String() string { return n.fstring("") } -func (n valueNode) String() string { return n.fstring("") } - -func (n *fullNode) fstring(ind string) string { - resp := fmt.Sprintf("[\n%s ", ind) - for i, node := range &n.Children { - if node == nil { - resp += fmt.Sprintf("%s: ", indices[i]) - } else { - resp += fmt.Sprintf("%s: %v", indices[i], node.fstring(ind+" ")) - } - } - return resp + fmt.Sprintf("\n%s] ", ind) -} -func (n *shortNode) fstring(ind string) string { - return fmt.Sprintf("{%x: %v} ", n.Key, n.Val.fstring(ind+" ")) -} -func (n hashNode) fstring(ind string) string { - return fmt.Sprintf("<%x> ", []byte(n)) -} -func (n valueNode) fstring(ind string) string { - return fmt.Sprintf("%x ", []byte(n)) -} - -// rawNode is a simple binary blob used to differentiate between collapsed trie -// nodes and already encoded RLP binary blobs (while at the same time store them -// in the same cache fields). -type rawNode []byte - -func (n rawNode) cache() (hashNode, bool) { panic("this should never end up in a live trie") } -func (n rawNode) fstring(ind string) string { panic("this should never end up in a live trie") } - -func (n rawNode) EncodeRLP(w io.Writer) error { - _, err := w.Write(n) - return err -} - -// mustDecodeNode is a wrapper of decodeNode and panic if any error is encountered. -func mustDecodeNode(hash, buf []byte) node { - n, err := decodeNode(hash, buf) - if err != nil { - panic(fmt.Sprintf("node %x: %v", hash, err)) - } - return n -} - -// mustDecodeNodeUnsafe is a wrapper of decodeNodeUnsafe and panic if any error is -// encountered. -func mustDecodeNodeUnsafe(hash, buf []byte) node { - n, err := decodeNodeUnsafe(hash, buf) - if err != nil { - panic(fmt.Sprintf("node %x: %v", hash, err)) - } - return n -} - -// decodeNode parses the RLP encoding of a trie node. It will deep-copy the passed -// byte slice for decoding, so it's safe to modify the byte slice afterwards. The- -// decode performance of this function is not optimal, but it is suitable for most -// scenarios with low performance requirements and hard to determine whether the -// byte slice be modified or not. -func decodeNode(hash, buf []byte) (node, error) { - return decodeNodeUnsafe(hash, common.CopyBytes(buf)) -} - -// decodeNodeUnsafe parses the RLP encoding of a trie node. The passed byte slice -// will be directly referenced by node without bytes deep copy, so the input MUST -// not be changed after. -func decodeNodeUnsafe(hash, buf []byte) (node, error) { - if len(buf) == 0 { - return nil, io.ErrUnexpectedEOF - } - elems, _, err := rlp.SplitList(buf) - if err != nil { - return nil, fmt.Errorf("decode error: %v", err) - } - switch c, _ := rlp.CountValues(elems); c { - case 2: - n, err := decodeShort(hash, elems) - return n, wrapError(err, "short") - case 17: - n, err := decodeFull(hash, elems) - return n, wrapError(err, "full") - default: - return nil, fmt.Errorf("invalid number of list elements: %v", c) - } -} - -func decodeShort(hash, elems []byte) (node, error) { - kbuf, rest, err := rlp.SplitString(elems) - if err != nil { - return nil, err - } - flag := nodeFlag{hash: hash} - key := compactToHex(kbuf) - if hasTerm(key) { - // value node - val, _, err := rlp.SplitString(rest) - if err != nil { - return nil, fmt.Errorf("invalid value node: %v", err) - } - return &shortNode{key, valueNode(val), flag}, nil - } - r, _, err := decodeRef(rest) - if err != nil { - return nil, wrapError(err, "val") - } - return &shortNode{key, r, flag}, nil -} - -func decodeFull(hash, elems []byte) (*fullNode, error) { - n := &fullNode{flags: nodeFlag{hash: hash}} - for i := 0; i < 16; i++ { - cld, rest, err := decodeRef(elems) - if err != nil { - return n, wrapError(err, fmt.Sprintf("[%d]", i)) - } - n.Children[i], elems = cld, rest - } - val, _, err := rlp.SplitString(elems) - if err != nil { - return n, err - } - if len(val) > 0 { - n.Children[16] = valueNode(val) - } - return n, nil -} - -const hashLen = len(common.Hash{}) - -func decodeRef(buf []byte) (node, []byte, error) { - kind, val, rest, err := rlp.Split(buf) - if err != nil { - return nil, buf, err - } - switch { - case kind == rlp.List: - // 'embedded' node reference. The encoding must be smaller - // than a hash in order to be valid. - if size := len(buf) - len(rest); size > hashLen { - err := fmt.Errorf("oversized embedded node (size is %d bytes, want size < %d)", size, hashLen) - return nil, buf, err - } - n, err := decodeNode(nil, buf) - return n, rest, err - case kind == rlp.String && len(val) == 0: - // empty node - return nil, rest, nil - case kind == rlp.String && len(val) == 32: - return hashNode(val), rest, nil - default: - return nil, nil, fmt.Errorf("invalid RLP string size %d (want 0 or 32)", len(val)) - } -} - -// wraps a decoding error with information about the path to the -// invalid child node (for debugging encoding issues). -type decodeError struct { - what error - stack []string -} - -func wrapError(err error, ctx string) error { - if err == nil { - return nil - } - if decErr, ok := err.(*decodeError); ok { - decErr.stack = append(decErr.stack, ctx) - return decErr - } - return &decodeError{err, []string{ctx}} -} - -func (err *decodeError) Error() string { - return fmt.Sprintf("%v (decode path: %s)", err.what, strings.Join(err.stack, "<-")) -} diff --git a/trie/node_enc.go b/trie/node_enc.go deleted file mode 100644 index dc053e1070..0000000000 --- a/trie/node_enc.go +++ /dev/null @@ -1,74 +0,0 @@ -// (c) 2022, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "github.com/ethereum/go-ethereum/rlp" -) - -func nodeToBytes(n node) []byte { - w := rlp.NewEncoderBuffer(nil) - n.encode(w) - result := w.ToBytes() - w.Flush() - return result -} - -func (n *fullNode) encode(w rlp.EncoderBuffer) { - offset := w.List() - for _, c := range n.Children { - if c != nil { - c.encode(w) - } else { - w.Write(rlp.EmptyString) - } - } - w.ListEnd(offset) -} - -func (n *shortNode) encode(w rlp.EncoderBuffer) { - offset := w.List() - w.WriteBytes(n.Key) - if n.Val != nil { - n.Val.encode(w) - } else { - w.Write(rlp.EmptyString) - } - w.ListEnd(offset) -} - -func (n hashNode) encode(w rlp.EncoderBuffer) { - w.WriteBytes(n) -} - -func (n valueNode) encode(w rlp.EncoderBuffer) { - w.WriteBytes(n) -} - -func (n rawNode) encode(w rlp.EncoderBuffer) { - w.Write(n) -} diff --git a/trie/node_test.go b/trie/node_test.go deleted file mode 100644 index 2308a1c2e2..0000000000 --- a/trie/node_test.go +++ /dev/null @@ -1,225 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "testing" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" -) - -func newTestFullNode(v []byte) []interface{} { - fullNodeData := []interface{}{} - for i := 0; i < 16; i++ { - k := bytes.Repeat([]byte{byte(i + 1)}, 32) - fullNodeData = append(fullNodeData, k) - } - fullNodeData = append(fullNodeData, v) - return fullNodeData -} - -func TestDecodeNestedNode(t *testing.T) { - fullNodeData := newTestFullNode([]byte("fullnode")) - - data := [][]byte{} - for i := 0; i < 16; i++ { - data = append(data, nil) - } - data = append(data, []byte("subnode")) - fullNodeData[15] = data - - buf := bytes.NewBuffer([]byte{}) - rlp.Encode(buf, fullNodeData) - - if _, err := decodeNode([]byte("testdecode"), buf.Bytes()); err != nil { - t.Fatalf("decode nested full node err: %v", err) - } -} - -func TestDecodeFullNodeWrongSizeChild(t *testing.T) { - fullNodeData := newTestFullNode([]byte("wrongsizechild")) - fullNodeData[0] = []byte("00") - buf := bytes.NewBuffer([]byte{}) - rlp.Encode(buf, fullNodeData) - - _, err := decodeNode([]byte("testdecode"), buf.Bytes()) - if _, ok := err.(*decodeError); !ok { - t.Fatalf("decodeNode returned wrong err: %v", err) - } -} - -func TestDecodeFullNodeWrongNestedFullNode(t *testing.T) { - fullNodeData := newTestFullNode([]byte("fullnode")) - - data := [][]byte{} - for i := 0; i < 16; i++ { - data = append(data, []byte("123456")) - } - data = append(data, []byte("subnode")) - fullNodeData[15] = data - - buf := bytes.NewBuffer([]byte{}) - rlp.Encode(buf, fullNodeData) - - _, err := decodeNode([]byte("testdecode"), buf.Bytes()) - if _, ok := err.(*decodeError); !ok { - t.Fatalf("decodeNode returned wrong err: %v", err) - } -} - -func TestDecodeFullNode(t *testing.T) { - fullNodeData := newTestFullNode([]byte("decodefullnode")) - buf := bytes.NewBuffer([]byte{}) - rlp.Encode(buf, fullNodeData) - - _, err := decodeNode([]byte("testdecode"), buf.Bytes()) - if err != nil { - t.Fatalf("decode full node err: %v", err) - } -} - -// goos: darwin -// goarch: arm64 -// pkg: github.com/ava-labs/subnet-evm/trie -// BenchmarkEncodeShortNode -// BenchmarkEncodeShortNode-8 16878850 70.81 ns/op 48 B/op 1 allocs/op -func BenchmarkEncodeShortNode(b *testing.B) { - node := &shortNode{ - Key: []byte{0x1, 0x2}, - Val: hashNode(randBytes(32)), - } - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - nodeToBytes(node) - } -} - -// goos: darwin -// goarch: arm64 -// pkg: github.com/ava-labs/subnet-evm/trie -// BenchmarkEncodeFullNode -// BenchmarkEncodeFullNode-8 4323273 284.4 ns/op 576 B/op 1 allocs/op -func BenchmarkEncodeFullNode(b *testing.B) { - node := &fullNode{} - for i := 0; i < 16; i++ { - node.Children[i] = hashNode(randBytes(32)) - } - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - nodeToBytes(node) - } -} - -// goos: darwin -// goarch: arm64 -// pkg: github.com/ava-labs/subnet-evm/trie -// BenchmarkDecodeShortNode -// BenchmarkDecodeShortNode-8 7925638 151.0 ns/op 157 B/op 4 allocs/op -func BenchmarkDecodeShortNode(b *testing.B) { - node := &shortNode{ - Key: []byte{0x1, 0x2}, - Val: hashNode(randBytes(32)), - } - blob := nodeToBytes(node) - hash := crypto.Keccak256(blob) - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - mustDecodeNode(hash, blob) - } -} - -// goos: darwin -// goarch: arm64 -// pkg: github.com/ava-labs/subnet-evm/trie -// BenchmarkDecodeShortNodeUnsafe -// BenchmarkDecodeShortNodeUnsafe-8 9027476 128.6 ns/op 109 B/op 3 allocs/op -func BenchmarkDecodeShortNodeUnsafe(b *testing.B) { - node := &shortNode{ - Key: []byte{0x1, 0x2}, - Val: hashNode(randBytes(32)), - } - blob := nodeToBytes(node) - hash := crypto.Keccak256(blob) - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - mustDecodeNodeUnsafe(hash, blob) - } -} - -// goos: darwin -// goarch: arm64 -// pkg: github.com/ava-labs/subnet-evm/trie -// BenchmarkDecodeFullNode -// BenchmarkDecodeFullNode-8 1597462 761.9 ns/op 1280 B/op 18 allocs/op -func BenchmarkDecodeFullNode(b *testing.B) { - node := &fullNode{} - for i := 0; i < 16; i++ { - node.Children[i] = hashNode(randBytes(32)) - } - blob := nodeToBytes(node) - hash := crypto.Keccak256(blob) - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - mustDecodeNode(hash, blob) - } -} - -// goos: darwin -// goarch: arm64 -// pkg: github.com/ava-labs/subnet-evm/trie -// BenchmarkDecodeFullNodeUnsafe -// BenchmarkDecodeFullNodeUnsafe-8 1789070 687.1 ns/op 704 B/op 17 allocs/op -func BenchmarkDecodeFullNodeUnsafe(b *testing.B) { - node := &fullNode{} - for i := 0; i < 16; i++ { - node.Children[i] = hashNode(randBytes(32)) - } - blob := nodeToBytes(node) - hash := crypto.Keccak256(blob) - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - mustDecodeNodeUnsafe(hash, blob) - } -} diff --git a/trie/proof.go b/trie/proof.go deleted file mode 100644 index 4bedbf0bc6..0000000000 --- a/trie/proof.go +++ /dev/null @@ -1,626 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" -) - -// Prove constructs a merkle proof for key. The result contains all encoded nodes -// on the path to the value at key. The value itself is also included in the last -// node and can be retrieved by verifying the proof. -// -// If the trie does not contain a value for key, the returned proof contains all -// nodes of the longest existing prefix of the key (at least the root node), ending -// with the node that proves the absence of the key. -func (t *Trie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error { - // Short circuit if the trie is already committed and not usable. - if t.committed { - return ErrCommitted - } - // Collect all nodes on the path to key. - var ( - prefix []byte - nodes []node - tn = t.root - ) - key = keybytesToHex(key) - for len(key) > 0 && tn != nil { - switch n := tn.(type) { - case *shortNode: - if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { - // The trie doesn't contain the key. - tn = nil - } else { - tn = n.Val - prefix = append(prefix, n.Key...) - key = key[len(n.Key):] - } - nodes = append(nodes, n) - case *fullNode: - tn = n.Children[key[0]] - prefix = append(prefix, key[0]) - key = key[1:] - nodes = append(nodes, n) - case hashNode: - // Retrieve the specified node from the underlying node reader. - // trie.resolveAndTrack is not used since in that function the - // loaded blob will be tracked, while it's not required here since - // all loaded nodes won't be linked to trie at all and track nodes - // may lead to out-of-memory issue. - blob, err := t.reader.node(prefix, common.BytesToHash(n)) - if err != nil { - log.Error("Unhandled trie error in Trie.Prove", "err", err) - return err - } - // The raw-blob format nodes are loaded either from the - // clean cache or the database, they are all in their own - // copy and safe to use unsafe decoder. - tn = mustDecodeNodeUnsafe(n, blob) - default: - panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) - } - } - hasher := newHasher(false) - defer returnHasherToPool(hasher) - - for i, n := range nodes { - var hn node - n, hn = hasher.proofHash(n) - if hash, ok := hn.(hashNode); ok || i == 0 { - // If the node's database encoding is a hash (or is the - // root node), it becomes a proof element. - enc := nodeToBytes(n) - if !ok { - hash = hasher.hashData(enc) - } - proofDb.Put(hash, enc) - } - } - return nil -} - -// Prove constructs a merkle proof for key. The result contains all encoded nodes -// on the path to the value at key. The value itself is also included in the last -// node and can be retrieved by verifying the proof. -// -// If the trie does not contain a value for key, the returned proof contains all -// nodes of the longest existing prefix of the key (at least the root node), ending -// with the node that proves the absence of the key. -func (t *StateTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error { - return t.trie.Prove(key, proofDb) -} - -// VerifyProof checks merkle proofs. The given proof must contain the value for -// key in a trie with the given root hash. VerifyProof returns an error if the -// proof contains invalid trie nodes or the wrong value. -func VerifyProof(rootHash common.Hash, key []byte, proofDb ethdb.KeyValueReader) (value []byte, err error) { - key = keybytesToHex(key) - wantHash := rootHash - for i := 0; ; i++ { - buf, _ := proofDb.Get(wantHash[:]) - if buf == nil { - return nil, fmt.Errorf("proof node %d (hash %064x) missing", i, wantHash) - } - n, err := decodeNode(wantHash[:], buf) - if err != nil { - return nil, fmt.Errorf("bad proof node %d: %v", i, err) - } - keyrest, cld := get(n, key, true) - switch cld := cld.(type) { - case nil: - // The trie doesn't contain the key. - return nil, nil - case hashNode: - key = keyrest - copy(wantHash[:], cld) - case valueNode: - return cld, nil - } - } -} - -// proofToPath converts a merkle proof to trie node path. The main purpose of -// this function is recovering a node path from the merkle proof stream. All -// necessary nodes will be resolved and leave the remaining as hashnode. -// -// The given edge proof is allowed to be an existent or non-existent proof. -func proofToPath(rootHash common.Hash, root node, key []byte, proofDb ethdb.KeyValueReader, allowNonExistent bool) (node, []byte, error) { - // resolveNode retrieves and resolves trie node from merkle proof stream - resolveNode := func(hash common.Hash) (node, error) { - buf, _ := proofDb.Get(hash[:]) - if buf == nil { - return nil, fmt.Errorf("proof node (hash %064x) missing", hash) - } - n, err := decodeNode(hash[:], buf) - if err != nil { - return nil, fmt.Errorf("bad proof node %v", err) - } - return n, err - } - // If the root node is empty, resolve it first. - // Root node must be included in the proof. - if root == nil { - n, err := resolveNode(rootHash) - if err != nil { - return nil, nil, err - } - root = n - } - var ( - err error - child, parent node - keyrest []byte - valnode []byte - ) - key, parent = keybytesToHex(key), root - for { - keyrest, child = get(parent, key, false) - switch cld := child.(type) { - case nil: - // The trie doesn't contain the key. It's possible - // the proof is a non-existing proof, but at least - // we can prove all resolved nodes are correct, it's - // enough for us to prove range. - if allowNonExistent { - return root, nil, nil - } - return nil, nil, errors.New("the node is not contained in trie") - case *shortNode: - key, parent = keyrest, child // Already resolved - continue - case *fullNode: - key, parent = keyrest, child // Already resolved - continue - case hashNode: - child, err = resolveNode(common.BytesToHash(cld)) - if err != nil { - return nil, nil, err - } - case valueNode: - valnode = cld - } - // Link the parent and child. - switch pnode := parent.(type) { - case *shortNode: - pnode.Val = child - case *fullNode: - pnode.Children[key[0]] = child - default: - panic(fmt.Sprintf("%T: invalid node: %v", pnode, pnode)) - } - if len(valnode) > 0 { - return root, valnode, nil // The whole path is resolved - } - key, parent = keyrest, child - } -} - -// unsetInternal removes all internal node references(hashnode, embedded node). -// It should be called after a trie is constructed with two edge paths. Also -// the given boundary keys must be the one used to construct the edge paths. -// -// It's the key step for range proof. All visited nodes should be marked dirty -// since the node content might be modified. Besides it can happen that some -// fullnodes only have one child which is disallowed. But if the proof is valid, -// the missing children will be filled, otherwise it will be thrown anyway. -// -// Note we have the assumption here the given boundary keys are different -// and right is larger than left. -func unsetInternal(n node, left []byte, right []byte) (bool, error) { - left, right = keybytesToHex(left), keybytesToHex(right) - - // Step down to the fork point. There are two scenarios can happen: - // - the fork point is a shortnode: either the key of left proof or - // right proof doesn't match with shortnode's key. - // - the fork point is a fullnode: both two edge proofs are allowed - // to point to a non-existent key. - var ( - pos = 0 - parent node - - // fork indicator, 0 means no fork, -1 means proof is less, 1 means proof is greater - shortForkLeft, shortForkRight int - ) -findFork: - for { - switch rn := (n).(type) { - case *shortNode: - rn.flags = nodeFlag{dirty: true} - - // If either the key of left proof or right proof doesn't match with - // shortnode, stop here and the forkpoint is the shortnode. - if len(left)-pos < len(rn.Key) { - shortForkLeft = bytes.Compare(left[pos:], rn.Key) - } else { - shortForkLeft = bytes.Compare(left[pos:pos+len(rn.Key)], rn.Key) - } - if len(right)-pos < len(rn.Key) { - shortForkRight = bytes.Compare(right[pos:], rn.Key) - } else { - shortForkRight = bytes.Compare(right[pos:pos+len(rn.Key)], rn.Key) - } - if shortForkLeft != 0 || shortForkRight != 0 { - break findFork - } - parent = n - n, pos = rn.Val, pos+len(rn.Key) - case *fullNode: - rn.flags = nodeFlag{dirty: true} - - // If either the node pointed by left proof or right proof is nil, - // stop here and the forkpoint is the fullnode. - leftnode, rightnode := rn.Children[left[pos]], rn.Children[right[pos]] - if leftnode == nil || rightnode == nil || leftnode != rightnode { - break findFork - } - parent = n - n, pos = rn.Children[left[pos]], pos+1 - default: - panic(fmt.Sprintf("%T: invalid node: %v", n, n)) - } - } - switch rn := n.(type) { - case *shortNode: - // There can have these five scenarios: - // - both proofs are less than the trie path => no valid range - // - both proofs are greater than the trie path => no valid range - // - left proof is less and right proof is greater => valid range, unset the shortnode entirely - // - left proof points to the shortnode, but right proof is greater - // - right proof points to the shortnode, but left proof is less - if shortForkLeft == -1 && shortForkRight == -1 { - return false, errors.New("empty range") - } - if shortForkLeft == 1 && shortForkRight == 1 { - return false, errors.New("empty range") - } - if shortForkLeft != 0 && shortForkRight != 0 { - // The fork point is root node, unset the entire trie - if parent == nil { - return true, nil - } - parent.(*fullNode).Children[left[pos-1]] = nil - return false, nil - } - // Only one proof points to non-existent key. - if shortForkRight != 0 { - if _, ok := rn.Val.(valueNode); ok { - // The fork point is root node, unset the entire trie - if parent == nil { - return true, nil - } - parent.(*fullNode).Children[left[pos-1]] = nil - return false, nil - } - return false, unset(rn, rn.Val, left[pos:], len(rn.Key), false) - } - if shortForkLeft != 0 { - if _, ok := rn.Val.(valueNode); ok { - // The fork point is root node, unset the entire trie - if parent == nil { - return true, nil - } - parent.(*fullNode).Children[right[pos-1]] = nil - return false, nil - } - return false, unset(rn, rn.Val, right[pos:], len(rn.Key), true) - } - return false, nil - case *fullNode: - // unset all internal nodes in the forkpoint - for i := left[pos] + 1; i < right[pos]; i++ { - rn.Children[i] = nil - } - if err := unset(rn, rn.Children[left[pos]], left[pos:], 1, false); err != nil { - return false, err - } - if err := unset(rn, rn.Children[right[pos]], right[pos:], 1, true); err != nil { - return false, err - } - return false, nil - default: - panic(fmt.Sprintf("%T: invalid node: %v", n, n)) - } -} - -// unset removes all internal node references either the left most or right most. -// It can meet these scenarios: -// -// - The given path is existent in the trie, unset the associated nodes with the -// specific direction -// - The given path is non-existent in the trie -// - the fork point is a fullnode, the corresponding child pointed by path -// is nil, return -// - the fork point is a shortnode, the shortnode is included in the range, -// keep the entire branch and return. -// - the fork point is a shortnode, the shortnode is excluded in the range, -// unset the entire branch. -func unset(parent node, child node, key []byte, pos int, removeLeft bool) error { - switch cld := child.(type) { - case *fullNode: - if removeLeft { - for i := 0; i < int(key[pos]); i++ { - cld.Children[i] = nil - } - cld.flags = nodeFlag{dirty: true} - } else { - for i := key[pos] + 1; i < 16; i++ { - cld.Children[i] = nil - } - cld.flags = nodeFlag{dirty: true} - } - return unset(cld, cld.Children[key[pos]], key, pos+1, removeLeft) - case *shortNode: - if len(key[pos:]) < len(cld.Key) || !bytes.Equal(cld.Key, key[pos:pos+len(cld.Key)]) { - // Find the fork point, it's an non-existent branch. - if removeLeft { - if bytes.Compare(cld.Key, key[pos:]) < 0 { - // The key of fork shortnode is less than the path - // (it belongs to the range), unset the entire - // branch. The parent must be a fullnode. - fn := parent.(*fullNode) - fn.Children[key[pos-1]] = nil - } - //else { - // The key of fork shortnode is greater than the - // path(it doesn't belong to the range), keep - // it with the cached hash available. - //} - } else { - if bytes.Compare(cld.Key, key[pos:]) > 0 { - // The key of fork shortnode is greater than the - // path(it belongs to the range), unset the entries - // branch. The parent must be a fullnode. - fn := parent.(*fullNode) - fn.Children[key[pos-1]] = nil - } - //else { - // The key of fork shortnode is less than the - // path(it doesn't belong to the range), keep - // it with the cached hash available. - //} - } - return nil - } - if _, ok := cld.Val.(valueNode); ok { - fn := parent.(*fullNode) - fn.Children[key[pos-1]] = nil - return nil - } - cld.flags = nodeFlag{dirty: true} - return unset(cld, cld.Val, key, pos+len(cld.Key), removeLeft) - case nil: - // If the node is nil, then it's a child of the fork point - // fullnode(it's a non-existent branch). - return nil - default: - panic("it shouldn't happen") // hashNode, valueNode - } -} - -// hasRightElement returns the indicator whether there exists more elements -// on the right side of the given path. The given path can point to an existent -// key or a non-existent one. This function has the assumption that the whole -// path should already be resolved. -func hasRightElement(node node, key []byte) bool { - pos, key := 0, keybytesToHex(key) - for node != nil { - switch rn := node.(type) { - case *fullNode: - for i := key[pos] + 1; i < 16; i++ { - if rn.Children[i] != nil { - return true - } - } - node, pos = rn.Children[key[pos]], pos+1 - case *shortNode: - if len(key)-pos < len(rn.Key) || !bytes.Equal(rn.Key, key[pos:pos+len(rn.Key)]) { - return bytes.Compare(rn.Key, key[pos:]) > 0 - } - node, pos = rn.Val, pos+len(rn.Key) - case valueNode: - return false // We have resolved the whole path - default: - panic(fmt.Sprintf("%T: invalid node: %v", node, node)) // hashnode - } - } - return false -} - -// VerifyRangeProof checks whether the given leaf nodes and edge proof -// can prove the given trie leaves range is matched with the specific root. -// Besides, the range should be consecutive (no gap inside) and monotonic -// increasing. -// -// Note the given proof actually contains two edge proofs. Both of them can -// be non-existent proofs. For example the first proof is for a non-existent -// key 0x03, the last proof is for a non-existent key 0x10. The given batch -// leaves are [0x04, 0x05, .. 0x09]. It's still feasible to prove the given -// batch is valid. -// -// The firstKey is paired with firstProof, not necessarily the same as keys[0] -// (unless firstProof is an existent proof). Similarly, lastKey and lastProof -// are paired. -// -// Expect the normal case, this function can also be used to verify the following -// range proofs: -// -// - All elements proof. In this case the proof can be nil, but the range should -// be all the leaves in the trie. -// -// - One element proof. In this case no matter the edge proof is a non-existent -// proof or not, we can always verify the correctness of the proof. -// -// - Zero element proof. In this case a single non-existent proof is enough to prove. -// Besides, if there are still some other leaves available on the right side, then -// an error will be returned. -// -// Except returning the error to indicate the proof is valid or not, the function will -// also return a flag to indicate whether there exists more accounts/slots in the trie. -// -// Note: This method does not verify that the proof is of minimal form. If the input -// proofs are 'bloated' with neighbour leaves or random data, aside from the 'useful' -// data, then the proof will still be accepted. -func VerifyRangeProof(rootHash common.Hash, firstKey []byte, keys [][]byte, values [][]byte, proof ethdb.KeyValueReader) (bool, error) { - if len(keys) != len(values) { - return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values)) - } - // Ensure the received batch is monotonic increasing and contains no deletions - for i := 0; i < len(keys)-1; i++ { - if bytes.Compare(keys[i], keys[i+1]) >= 0 { - return false, errors.New("range is not monotonically increasing") - } - } - for _, value := range values { - if len(value) == 0 { - return false, errors.New("range contains deletion") - } - } - // Special case, there is no edge proof at all. The given range is expected - // to be the whole leaf-set in the trie. - if proof == nil { - tr := NewStackTrie(nil) - for index, key := range keys { - tr.Update(key, values[index]) - } - if have, want := tr.Hash(), rootHash; have != want { - return false, fmt.Errorf("invalid proof, want hash %x, got %x", want, have) - } - return false, nil // No more elements - } - // Special case, there is a provided edge proof but zero key/value - // pairs, ensure there are no more accounts / slots in the trie. - if len(keys) == 0 { - root, val, err := proofToPath(rootHash, nil, firstKey, proof, true) - if err != nil { - return false, err - } - if val != nil || hasRightElement(root, firstKey) { - return false, errors.New("more entries available") - } - return false, nil - } - var lastKey = keys[len(keys)-1] - // Special case, there is only one element and two edge keys are same. - // In this case, we can't construct two edge paths. So handle it here. - if len(keys) == 1 && bytes.Equal(firstKey, lastKey) { - root, val, err := proofToPath(rootHash, nil, firstKey, proof, false) - if err != nil { - return false, err - } - if !bytes.Equal(firstKey, keys[0]) { - return false, errors.New("correct proof but invalid key") - } - if !bytes.Equal(val, values[0]) { - return false, errors.New("correct proof but invalid data") - } - return hasRightElement(root, firstKey), nil - } - // Ok, in all other cases, we require two edge paths available. - // First check the validity of edge keys. - if bytes.Compare(firstKey, lastKey) >= 0 { - return false, errors.New("invalid edge keys") - } - // todo(rjl493456442) different length edge keys should be supported - if len(firstKey) != len(lastKey) { - return false, fmt.Errorf("inconsistent edge keys (%d != %d)", len(firstKey), len(lastKey)) - } - // Convert the edge proofs to edge trie paths. Then we can - // have the same tree architecture with the original one. - // For the first edge proof, non-existent proof is allowed. - root, _, err := proofToPath(rootHash, nil, firstKey, proof, true) - if err != nil { - return false, err - } - // Pass the root node here, the second path will be merged - // with the first one. For the last edge proof, non-existent - // proof is also allowed. - root, _, err = proofToPath(rootHash, root, lastKey, proof, true) - if err != nil { - return false, err - } - // Remove all internal references. All the removed parts should - // be re-filled(or re-constructed) by the given leaves range. - empty, err := unsetInternal(root, firstKey, lastKey) - if err != nil { - return false, err - } - // Rebuild the trie with the leaf stream, the shape of trie - // should be same with the original one. - tr := &Trie{root: root, reader: newEmptyReader(), tracer: newTracer()} - if empty { - tr.root = nil - } - for index, key := range keys { - tr.Update(key, values[index]) - } - if tr.Hash() != rootHash { - return false, fmt.Errorf("invalid proof, want hash %x, got %x", rootHash, tr.Hash()) - } - return hasRightElement(tr.root, keys[len(keys)-1]), nil -} - -// get returns the child of the given node. Return nil if the -// node with specified key doesn't exist at all. -// -// There is an additional flag `skipResolved`. If it's set then -// all resolved nodes won't be returned. -func get(tn node, key []byte, skipResolved bool) ([]byte, node) { - for { - switch n := tn.(type) { - case *shortNode: - if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { - return nil, nil - } - tn = n.Val - key = key[len(n.Key):] - if !skipResolved { - return key, tn - } - case *fullNode: - tn = n.Children[key[0]] - key = key[1:] - if !skipResolved { - return key, tn - } - case hashNode: - return key, n - case nil: - return key, nil - case valueNode: - return nil, n - default: - panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) - } - } -} diff --git a/trie/proof_test.go b/trie/proof_test.go deleted file mode 100644 index 91a5c64ac0..0000000000 --- a/trie/proof_test.go +++ /dev/null @@ -1,1012 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - crand "crypto/rand" - "encoding/binary" - "fmt" - mrand "math/rand" - "testing" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb/memorydb" - "golang.org/x/exp/slices" -) - -// Prng is a pseudo random number generator seeded by strong randomness. -// The randomness is printed on startup in order to make failures reproducible. -var prng = initRnd() - -func initRnd() *mrand.Rand { - var seed [8]byte - crand.Read(seed[:]) - rnd := mrand.New(mrand.NewSource(int64(binary.LittleEndian.Uint64(seed[:])))) - fmt.Printf("Seed: %x\n", seed) - return rnd -} - -func randBytes(n int) []byte { - r := make([]byte, n) - prng.Read(r) - return r -} - -// makeProvers creates Merkle trie provers based on different implementations to -// test all variations. -func makeProvers(trie *Trie) []func(key []byte) *memorydb.Database { - var provers []func(key []byte) *memorydb.Database - - // Create a direct trie based Merkle prover - provers = append(provers, func(key []byte) *memorydb.Database { - proof := memorydb.New() - trie.Prove(key, proof) - return proof - }) - // Create a leaf iterator based Merkle prover - provers = append(provers, func(key []byte) *memorydb.Database { - proof := memorydb.New() - if it := NewIterator(trie.MustNodeIterator(key)); it.Next() && bytes.Equal(key, it.Key) { - for _, p := range it.Prove() { - proof.Put(crypto.Keccak256(p), p) - } - } - return proof - }) - return provers -} - -func TestProof(t *testing.T) { - trie, vals := randomTrie(500) - root := trie.Hash() - for i, prover := range makeProvers(trie) { - for _, kv := range vals { - proof := prover(kv.k) - if proof == nil { - t.Fatalf("prover %d: missing key %x while constructing proof", i, kv.k) - } - val, err := VerifyProof(root, kv.k, proof) - if err != nil { - t.Fatalf("prover %d: failed to verify proof for key %x: %v\nraw proof: %x", i, kv.k, err, proof) - } - if !bytes.Equal(val, kv.v) { - t.Fatalf("prover %d: verified value mismatch for key %x: have %x, want %x", i, kv.k, val, kv.v) - } - } - } -} - -func TestOneElementProof(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - updateString(trie, "k", "v") - for i, prover := range makeProvers(trie) { - proof := prover([]byte("k")) - if proof == nil { - t.Fatalf("prover %d: nil proof", i) - } - if proof.Len() != 1 { - t.Errorf("prover %d: proof should have one element", i) - } - val, err := VerifyProof(trie.Hash(), []byte("k"), proof) - if err != nil { - t.Fatalf("prover %d: failed to verify proof: %v\nraw proof: %x", i, err, proof) - } - if !bytes.Equal(val, []byte("v")) { - t.Fatalf("prover %d: verified value mismatch: have %x, want 'k'", i, val) - } - } -} - -func TestBadProof(t *testing.T) { - trie, vals := randomTrie(800) - root := trie.Hash() - for i, prover := range makeProvers(trie) { - for _, kv := range vals { - proof := prover(kv.k) - if proof == nil { - t.Fatalf("prover %d: nil proof", i) - } - it := proof.NewIterator(nil, nil) - for i, d := 0, mrand.Intn(proof.Len()); i <= d; i++ { - it.Next() - } - key := it.Key() - val, _ := proof.Get(key) - proof.Delete(key) - it.Release() - - mutateByte(val) - proof.Put(crypto.Keccak256(val), val) - - if _, err := VerifyProof(root, kv.k, proof); err == nil { - t.Fatalf("prover %d: expected proof to fail for key %x", i, kv.k) - } - } - } -} - -// Tests that missing keys can also be proven. The test explicitly uses a single -// entry trie and checks for missing keys both before and after the single entry. -func TestMissingKeyProof(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - updateString(trie, "k", "v") - - for i, key := range []string{"a", "j", "l", "z"} { - proof := memorydb.New() - trie.Prove([]byte(key), proof) - - if proof.Len() != 1 { - t.Errorf("test %d: proof should have one element", i) - } - val, err := VerifyProof(trie.Hash(), []byte(key), proof) - if err != nil { - t.Fatalf("test %d: failed to verify proof: %v\nraw proof: %x", i, err, proof) - } - if val != nil { - t.Fatalf("test %d: verified value mismatch: have %x, want nil", i, val) - } - } -} - -// TestRangeProof tests normal range proof with both edge proofs -// as the existent proof. The test cases are generated randomly. -func TestRangeProof(t *testing.T) { - trie, vals := randomTrie(4096) - var entries []*kv - for _, kv := range vals { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - for i := 0; i < 500; i++ { - start := mrand.Intn(len(entries)) - end := mrand.Intn(len(entries)-start) + start + 1 - - proof := memorydb.New() - if err := trie.Prove(entries[start].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[end-1].k, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - var keys [][]byte - var vals [][]byte - for i := start; i < end; i++ { - keys = append(keys, entries[i].k) - vals = append(vals, entries[i].v) - } - _, err := VerifyRangeProof(trie.Hash(), keys[0], keys, vals, proof) - if err != nil { - t.Fatalf("Case %d(%d->%d) expect no error, got %v", i, start, end-1, err) - } - } -} - -// TestRangeProof tests normal range proof with two non-existent proofs. -// The test cases are generated randomly. -func TestRangeProofWithNonExistentProof(t *testing.T) { - trie, vals := randomTrie(4096) - var entries []*kv - for _, kv := range vals { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - for i := 0; i < 500; i++ { - start := mrand.Intn(len(entries)) - end := mrand.Intn(len(entries)-start) + start + 1 - proof := memorydb.New() - - // Short circuit if the decreased key is same with the previous key - first := decreaseKey(common.CopyBytes(entries[start].k)) - if start != 0 && bytes.Equal(first, entries[start-1].k) { - continue - } - // Short circuit if the decreased key is underflow - if bytes.Compare(first, entries[start].k) > 0 { - continue - } - if err := trie.Prove(first, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[end-1].k, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - var keys [][]byte - var vals [][]byte - for i := start; i < end; i++ { - keys = append(keys, entries[i].k) - vals = append(vals, entries[i].v) - } - _, err := VerifyRangeProof(trie.Hash(), first, keys, vals, proof) - if err != nil { - t.Fatalf("Case %d(%d->%d) expect no error, got %v", i, start, end-1, err) - } - } -} - -// TestRangeProofWithInvalidNonExistentProof tests such scenarios: -// - There exists a gap between the first element and the left edge proof -func TestRangeProofWithInvalidNonExistentProof(t *testing.T) { - trie, vals := randomTrie(4096) - var entries []*kv - for _, kv := range vals { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - - // Case 1 - start, end := 100, 200 - first := decreaseKey(common.CopyBytes(entries[start].k)) - - proof := memorydb.New() - if err := trie.Prove(first, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[end-1].k, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - start = 105 // Gap created - k := make([][]byte, 0) - v := make([][]byte, 0) - for i := start; i < end; i++ { - k = append(k, entries[i].k) - v = append(v, entries[i].v) - } - _, err := VerifyRangeProof(trie.Hash(), first, k, v, proof) - if err == nil { - t.Fatalf("Expected to detect the error, got nil") - } -} - -// TestOneElementRangeProof tests the proof with only one -// element. The first edge proof can be existent one or -// non-existent one. -func TestOneElementRangeProof(t *testing.T) { - trie, vals := randomTrie(4096) - var entries []*kv - for _, kv := range vals { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - - // One element with existent edge proof, both edge proofs - // point to the SAME key. - start := 1000 - proof := memorydb.New() - if err := trie.Prove(entries[start].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - _, err := VerifyRangeProof(trie.Hash(), entries[start].k, [][]byte{entries[start].k}, [][]byte{entries[start].v}, proof) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - // One element with left non-existent edge proof - start = 1000 - first := decreaseKey(common.CopyBytes(entries[start].k)) - proof = memorydb.New() - if err := trie.Prove(first, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[start].k, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - _, err = VerifyRangeProof(trie.Hash(), first, [][]byte{entries[start].k}, [][]byte{entries[start].v}, proof) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - // One element with right non-existent edge proof - start = 1000 - last := increaseKey(common.CopyBytes(entries[start].k)) - proof = memorydb.New() - if err := trie.Prove(entries[start].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(last, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - _, err = VerifyRangeProof(trie.Hash(), entries[start].k, [][]byte{entries[start].k}, [][]byte{entries[start].v}, proof) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - // One element with two non-existent edge proofs - start = 1000 - first, last = decreaseKey(common.CopyBytes(entries[start].k)), increaseKey(common.CopyBytes(entries[start].k)) - proof = memorydb.New() - if err := trie.Prove(first, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(last, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - _, err = VerifyRangeProof(trie.Hash(), first, [][]byte{entries[start].k}, [][]byte{entries[start].v}, proof) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - // Test the mini trie with only a single element. - tinyTrie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - entry := &kv{randBytes(32), randBytes(20), false} - tinyTrie.MustUpdate(entry.k, entry.v) - - first = common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000").Bytes() - last = entry.k - proof = memorydb.New() - if err := tinyTrie.Prove(first, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := tinyTrie.Prove(last, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - _, err = VerifyRangeProof(tinyTrie.Hash(), first, [][]byte{entry.k}, [][]byte{entry.v}, proof) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } -} - -// TestAllElementsProof tests the range proof with all elements. -// The edge proofs can be nil. -func TestAllElementsProof(t *testing.T) { - trie, vals := randomTrie(4096) - var entries []*kv - for _, kv := range vals { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - - var k [][]byte - var v [][]byte - for i := 0; i < len(entries); i++ { - k = append(k, entries[i].k) - v = append(v, entries[i].v) - } - _, err := VerifyRangeProof(trie.Hash(), nil, k, v, nil) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - // With edge proofs, it should still work. - proof := memorydb.New() - if err := trie.Prove(entries[0].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[len(entries)-1].k, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - _, err = VerifyRangeProof(trie.Hash(), k[0], k, v, proof) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - // Even with non-existent edge proofs, it should still work. - proof = memorydb.New() - first := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000").Bytes() - if err := trie.Prove(first, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[len(entries)-1].k, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - _, err = VerifyRangeProof(trie.Hash(), first, k, v, proof) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } -} - -// TestSingleSideRangeProof tests the range starts from zero. -func TestSingleSideRangeProof(t *testing.T) { - for i := 0; i < 64; i++ { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - var entries []*kv - for i := 0; i < 4096; i++ { - value := &kv{randBytes(32), randBytes(20), false} - trie.MustUpdate(value.k, value.v) - entries = append(entries, value) - } - slices.SortFunc(entries, (*kv).cmp) - - var cases = []int{0, 1, 50, 100, 1000, 2000, len(entries) - 1} - for _, pos := range cases { - proof := memorydb.New() - if err := trie.Prove(common.Hash{}.Bytes(), proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[pos].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - k := make([][]byte, 0) - v := make([][]byte, 0) - for i := 0; i <= pos; i++ { - k = append(k, entries[i].k) - v = append(v, entries[i].v) - } - _, err := VerifyRangeProof(trie.Hash(), common.Hash{}.Bytes(), k, v, proof) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - } - } -} - -// TestBadRangeProof tests a few cases which the proof is wrong. -// The prover is expected to detect the error. -func TestBadRangeProof(t *testing.T) { - trie, vals := randomTrie(4096) - var entries []*kv - for _, kv := range vals { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - - for i := 0; i < 500; i++ { - start := mrand.Intn(len(entries)) - end := mrand.Intn(len(entries)-start) + start + 1 - proof := memorydb.New() - if err := trie.Prove(entries[start].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[end-1].k, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - var keys [][]byte - var vals [][]byte - for i := start; i < end; i++ { - keys = append(keys, entries[i].k) - vals = append(vals, entries[i].v) - } - var first = keys[0] - testcase := mrand.Intn(6) - var index int - switch testcase { - case 0: - // Modified key - index = mrand.Intn(end - start) - keys[index] = randBytes(32) // In theory it can't be same - case 1: - // Modified val - index = mrand.Intn(end - start) - vals[index] = randBytes(20) // In theory it can't be same - case 2: - // Gapped entry slice - index = mrand.Intn(end - start) - if (index == 0 && start < 100) || (index == end-start-1) { - continue - } - keys = append(keys[:index], keys[index+1:]...) - vals = append(vals[:index], vals[index+1:]...) - case 3: - // Out of order - index1 := mrand.Intn(end - start) - index2 := mrand.Intn(end - start) - if index1 == index2 { - continue - } - keys[index1], keys[index2] = keys[index2], keys[index1] - vals[index1], vals[index2] = vals[index2], vals[index1] - case 4: - // Set random key to nil, do nothing - index = mrand.Intn(end - start) - keys[index] = nil - case 5: - // Set random value to nil, deletion - index = mrand.Intn(end - start) - vals[index] = nil - } - _, err := VerifyRangeProof(trie.Hash(), first, keys, vals, proof) - if err == nil { - t.Fatalf("%d Case %d index %d range: (%d->%d) expect error, got nil", i, testcase, index, start, end-1) - } - } -} - -// TestGappedRangeProof focuses on the small trie with embedded nodes. -// If the gapped node is embedded in the trie, it should be detected too. -func TestGappedRangeProof(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - var entries []*kv // Sorted entries - for i := byte(0); i < 10; i++ { - value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} - trie.MustUpdate(value.k, value.v) - entries = append(entries, value) - } - first, last := 2, 8 - proof := memorydb.New() - if err := trie.Prove(entries[first].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[last-1].k, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - var keys [][]byte - var vals [][]byte - for i := first; i < last; i++ { - if i == (first+last)/2 { - continue - } - keys = append(keys, entries[i].k) - vals = append(vals, entries[i].v) - } - _, err := VerifyRangeProof(trie.Hash(), keys[0], keys, vals, proof) - if err == nil { - t.Fatal("expect error, got nil") - } -} - -// TestSameSideProofs tests the element is not in the range covered by proofs -func TestSameSideProofs(t *testing.T) { - trie, vals := randomTrie(4096) - var entries []*kv - for _, kv := range vals { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - - pos := 1000 - first := common.CopyBytes(entries[0].k) - - proof := memorydb.New() - if err := trie.Prove(first, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[2000].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - _, err := VerifyRangeProof(trie.Hash(), first, [][]byte{entries[pos].k}, [][]byte{entries[pos].v}, proof) - if err == nil { - t.Fatalf("Expected error, got nil") - } - - first = increaseKey(common.CopyBytes(entries[pos].k)) - last := increaseKey(common.CopyBytes(entries[pos].k)) - last = increaseKey(last) - - proof = memorydb.New() - if err := trie.Prove(first, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(last, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - _, err = VerifyRangeProof(trie.Hash(), first, [][]byte{entries[pos].k}, [][]byte{entries[pos].v}, proof) - if err == nil { - t.Fatalf("Expected error, got nil") - } -} - -func TestHasRightElement(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - var entries []*kv - for i := 0; i < 4096; i++ { - value := &kv{randBytes(32), randBytes(20), false} - trie.MustUpdate(value.k, value.v) - entries = append(entries, value) - } - slices.SortFunc(entries, (*kv).cmp) - - var cases = []struct { - start int - end int - hasMore bool - }{ - {-1, 1, true}, // single element with non-existent left proof - {0, 1, true}, // single element with existent left proof - {0, 10, true}, - {50, 100, true}, - {50, len(entries), false}, // No more element expected - {len(entries) - 1, len(entries), false}, // Single last element with two existent proofs(point to same key) - {0, len(entries), false}, // The whole set with existent left proof - {-1, len(entries), false}, // The whole set with non-existent left proof - } - for _, c := range cases { - var ( - firstKey []byte - start = c.start - end = c.end - proof = memorydb.New() - ) - if c.start == -1 { - firstKey, start = common.Hash{}.Bytes(), 0 - if err := trie.Prove(firstKey, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - } else { - firstKey = entries[c.start].k - if err := trie.Prove(entries[c.start].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - } - if err := trie.Prove(entries[c.end-1].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - k := make([][]byte, 0) - v := make([][]byte, 0) - for i := start; i < end; i++ { - k = append(k, entries[i].k) - v = append(v, entries[i].v) - } - hasMore, err := VerifyRangeProof(trie.Hash(), firstKey, k, v, proof) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if hasMore != c.hasMore { - t.Fatalf("Wrong hasMore indicator, want %t, got %t", c.hasMore, hasMore) - } - } -} - -// TestEmptyRangeProof tests the range proof with "no" element. -// The first edge proof must be a non-existent proof. -func TestEmptyRangeProof(t *testing.T) { - trie, vals := randomTrie(4096) - var entries []*kv - for _, kv := range vals { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - - var cases = []struct { - pos int - err bool - }{ - {len(entries) - 1, false}, - {500, true}, - } - for _, c := range cases { - proof := memorydb.New() - first := increaseKey(common.CopyBytes(entries[c.pos].k)) - if err := trie.Prove(first, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - _, err := VerifyRangeProof(trie.Hash(), first, nil, nil, proof) - if c.err && err == nil { - t.Fatalf("Expected error, got nil") - } - if !c.err && err != nil { - t.Fatalf("Expected no error, got %v", err) - } - } -} - -// TestBloatedProof tests a malicious proof, where the proof is more or less the -// whole trie. Previously we didn't accept such packets, but the new APIs do, so -// lets leave this test as a bit weird, but present. -func TestBloatedProof(t *testing.T) { - // Use a small trie - trie, kvs := nonRandomTrie(100) - var entries []*kv - for _, kv := range kvs { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - var keys [][]byte - var vals [][]byte - - proof := memorydb.New() - // In the 'malicious' case, we add proofs for every single item - // (but only one key/value pair used as leaf) - for i, entry := range entries { - trie.Prove(entry.k, proof) - if i == 50 { - keys = append(keys, entry.k) - vals = append(vals, entry.v) - } - } - // For reference, we use the same function, but _only_ prove the first - // and last element - want := memorydb.New() - trie.Prove(keys[0], want) - trie.Prove(keys[len(keys)-1], want) - - if _, err := VerifyRangeProof(trie.Hash(), keys[0], keys, vals, proof); err != nil { - t.Fatalf("expected bloated proof to succeed, got %v", err) - } -} - -// TestEmptyValueRangeProof tests normal range proof with both edge proofs -// as the existent proof, but with an extra empty value included, which is a -// noop technically, but practically should be rejected. -func TestEmptyValueRangeProof(t *testing.T) { - trie, values := randomTrie(512) - var entries []*kv - for _, kv := range values { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - - // Create a new entry with a slightly modified key - mid := len(entries) / 2 - key := common.CopyBytes(entries[mid-1].k) - for n := len(key) - 1; n >= 0; n-- { - if key[n] < 0xff { - key[n]++ - break - } - } - noop := &kv{key, []byte{}, false} - entries = append(append(append([]*kv{}, entries[:mid]...), noop), entries[mid:]...) - - start, end := 1, len(entries)-1 - - proof := memorydb.New() - if err := trie.Prove(entries[start].k, proof); err != nil { - t.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[end-1].k, proof); err != nil { - t.Fatalf("Failed to prove the last node %v", err) - } - var keys [][]byte - var vals [][]byte - for i := start; i < end; i++ { - keys = append(keys, entries[i].k) - vals = append(vals, entries[i].v) - } - _, err := VerifyRangeProof(trie.Hash(), keys[0], keys, vals, proof) - if err == nil { - t.Fatalf("Expected failure on noop entry") - } -} - -// TestAllElementsEmptyValueRangeProof tests the range proof with all elements, -// but with an extra empty value included, which is a noop technically, but -// practically should be rejected. -func TestAllElementsEmptyValueRangeProof(t *testing.T) { - trie, values := randomTrie(512) - var entries []*kv - for _, kv := range values { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - - // Create a new entry with a slightly modified key - mid := len(entries) / 2 - key := common.CopyBytes(entries[mid-1].k) - for n := len(key) - 1; n >= 0; n-- { - if key[n] < 0xff { - key[n]++ - break - } - } - noop := &kv{key, []byte{}, false} - entries = append(append(append([]*kv{}, entries[:mid]...), noop), entries[mid:]...) - - var keys [][]byte - var vals [][]byte - for i := 0; i < len(entries); i++ { - keys = append(keys, entries[i].k) - vals = append(vals, entries[i].v) - } - _, err := VerifyRangeProof(trie.Hash(), nil, keys, vals, nil) - if err == nil { - t.Fatalf("Expected failure on noop entry") - } -} - -// mutateByte changes one byte in b. -func mutateByte(b []byte) { - for r := mrand.Intn(len(b)); ; { - new := byte(mrand.Intn(255)) - if new != b[r] { - b[r] = new - break - } - } -} - -func increaseKey(key []byte) []byte { - for i := len(key) - 1; i >= 0; i-- { - key[i]++ - if key[i] != 0x0 { - break - } - } - return key -} - -func decreaseKey(key []byte) []byte { - for i := len(key) - 1; i >= 0; i-- { - key[i]-- - if key[i] != 0xff { - break - } - } - return key -} - -func BenchmarkProve(b *testing.B) { - trie, vals := randomTrie(100) - var keys []string - for k := range vals { - keys = append(keys, k) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - kv := vals[keys[i%len(keys)]] - proofs := memorydb.New() - if trie.Prove(kv.k, proofs); proofs.Len() == 0 { - b.Fatalf("zero length proof for %x", kv.k) - } - } -} - -func BenchmarkVerifyProof(b *testing.B) { - trie, vals := randomTrie(100) - root := trie.Hash() - var keys []string - var proofs []*memorydb.Database - for k := range vals { - keys = append(keys, k) - proof := memorydb.New() - trie.Prove([]byte(k), proof) - proofs = append(proofs, proof) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - im := i % len(keys) - if _, err := VerifyProof(root, []byte(keys[im]), proofs[im]); err != nil { - b.Fatalf("key %x: %v", keys[im], err) - } - } -} - -func BenchmarkVerifyRangeProof10(b *testing.B) { benchmarkVerifyRangeProof(b, 10) } -func BenchmarkVerifyRangeProof100(b *testing.B) { benchmarkVerifyRangeProof(b, 100) } -func BenchmarkVerifyRangeProof1000(b *testing.B) { benchmarkVerifyRangeProof(b, 1000) } -func BenchmarkVerifyRangeProof5000(b *testing.B) { benchmarkVerifyRangeProof(b, 5000) } - -func benchmarkVerifyRangeProof(b *testing.B, size int) { - trie, vals := randomTrie(8192) - var entries []*kv - for _, kv := range vals { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - - start := 2 - end := start + size - proof := memorydb.New() - if err := trie.Prove(entries[start].k, proof); err != nil { - b.Fatalf("Failed to prove the first node %v", err) - } - if err := trie.Prove(entries[end-1].k, proof); err != nil { - b.Fatalf("Failed to prove the last node %v", err) - } - var keys [][]byte - var values [][]byte - for i := start; i < end; i++ { - keys = append(keys, entries[i].k) - values = append(values, entries[i].v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err := VerifyRangeProof(trie.Hash(), keys[0], keys, values, proof) - if err != nil { - b.Fatalf("Case %d(%d->%d) expect no error, got %v", i, start, end-1, err) - } - } -} - -func BenchmarkVerifyRangeNoProof10(b *testing.B) { benchmarkVerifyRangeNoProof(b, 100) } -func BenchmarkVerifyRangeNoProof500(b *testing.B) { benchmarkVerifyRangeNoProof(b, 500) } -func BenchmarkVerifyRangeNoProof1000(b *testing.B) { benchmarkVerifyRangeNoProof(b, 1000) } - -func benchmarkVerifyRangeNoProof(b *testing.B, size int) { - trie, vals := randomTrie(size) - var entries []*kv - for _, kv := range vals { - entries = append(entries, kv) - } - slices.SortFunc(entries, (*kv).cmp) - - var keys [][]byte - var values [][]byte - for _, entry := range entries { - keys = append(keys, entry.k) - values = append(values, entry.v) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err := VerifyRangeProof(trie.Hash(), keys[0], keys, values, nil) - if err != nil { - b.Fatalf("Expected no error, got %v", err) - } - } -} - -func randomTrie(n int) (*Trie, map[string]*kv) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - vals := make(map[string]*kv) - for i := byte(0); i < 100; i++ { - value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} - value2 := &kv{common.LeftPadBytes([]byte{i + 10}, 32), []byte{i}, false} - trie.MustUpdate(value.k, value.v) - trie.MustUpdate(value2.k, value2.v) - vals[string(value.k)] = value - vals[string(value2.k)] = value2 - } - for i := 0; i < n; i++ { - value := &kv{randBytes(32), randBytes(20), false} - trie.MustUpdate(value.k, value.v) - vals[string(value.k)] = value - } - return trie, vals -} - -func nonRandomTrie(n int) (*Trie, map[string]*kv) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - vals := make(map[string]*kv) - max := uint64(0xffffffffffffffff) - for i := uint64(0); i < uint64(n); i++ { - value := make([]byte, 32) - key := make([]byte, 32) - binary.LittleEndian.PutUint64(key, i) - binary.LittleEndian.PutUint64(value, i-max) - //value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} - elem := &kv{key, value, false} - trie.MustUpdate(elem.k, elem.v) - vals[string(elem.k)] = elem - } - return trie, vals -} - -func TestRangeProofKeysWithSharedPrefix(t *testing.T) { - keys := [][]byte{ - common.Hex2Bytes("aa10000000000000000000000000000000000000000000000000000000000000"), - common.Hex2Bytes("aa20000000000000000000000000000000000000000000000000000000000000"), - } - vals := [][]byte{ - common.Hex2Bytes("02"), - common.Hex2Bytes("03"), - } - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - for i, key := range keys { - trie.MustUpdate(key, vals[i]) - } - root := trie.Hash() - proof := memorydb.New() - start := common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000") - if err := trie.Prove(start, proof); err != nil { - t.Fatalf("failed to prove start: %v", err) - } - if err := trie.Prove(keys[len(keys)-1], proof); err != nil { - t.Fatalf("failed to prove end: %v", err) - } - - more, err := VerifyRangeProof(root, start, keys, vals, proof) - if err != nil { - t.Fatalf("failed to verify range proof: %v", err) - } - if more != false { - t.Error("expected more to be false") - } -} diff --git a/trie/secure_trie.go b/trie/secure_trie.go deleted file mode 100644 index bcf983e0ee..0000000000 --- a/trie/secure_trie.go +++ /dev/null @@ -1,296 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/triedb/database" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" -) - -// SecureTrie is the old name of StateTrie. -// Deprecated: use StateTrie. -type SecureTrie = StateTrie - -// NewSecure creates a new StateTrie. -// Deprecated: use NewStateTrie. -func NewSecure(stateRoot common.Hash, owner common.Hash, root common.Hash, db database.Database) (*SecureTrie, error) { - id := &ID{ - StateRoot: stateRoot, - Owner: owner, - Root: root, - } - return NewStateTrie(id, db) -} - -// StateTrie wraps a trie with key hashing. In a stateTrie trie, all -// access operations hash the key using keccak256. This prevents -// calling code from creating long chains of nodes that -// increase the access time. -// -// Contrary to a regular trie, a StateTrie can only be created with -// New and must have an attached database. The database also stores -// the preimage of each key if preimage recording is enabled. -// -// StateTrie is not safe for concurrent use. -type StateTrie struct { - trie Trie - db database.Database - hashKeyBuf [common.HashLength]byte - secKeyCache map[string][]byte - secKeyCacheOwner *StateTrie // Pointer to self, replace the key cache on mismatch -} - -// NewStateTrie creates a trie with an existing root node from a backing database. -// -// If root is the zero hash or the sha3 hash of an empty string, the -// trie is initially empty. Otherwise, New will panic if db is nil -// and returns MissingNodeError if the root node cannot be found. -func NewStateTrie(id *ID, db database.Database) (*StateTrie, error) { - if db == nil { - panic("trie.NewStateTrie called without a database") - } - trie, err := New(id, db) - if err != nil { - return nil, err - } - return &StateTrie{trie: *trie, db: db}, nil -} - -// MustGet returns the value for key stored in the trie. -// The value bytes must not be modified by the caller. -// -// This function will omit any encountered error but just -// print out an error message. -func (t *StateTrie) MustGet(key []byte) []byte { - return t.trie.MustGet(t.hashKey(key)) -} - -// GetStorage attempts to retrieve a storage slot with provided account address -// and slot key. The value bytes must not be modified by the caller. -// If the specified storage slot is not in the trie, nil will be returned. -// If a trie node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { - enc, err := t.trie.Get(t.hashKey(key)) - if err != nil || len(enc) == 0 { - return nil, err - } - _, content, _, err := rlp.Split(enc) - return content, err -} - -// GetAccount attempts to retrieve an account with provided account address. -// If the specified account is not in the trie, nil will be returned. -// If a trie node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) { - res, err := t.trie.Get(t.hashKey(address.Bytes())) - if res == nil || err != nil { - return nil, err - } - ret := new(types.StateAccount) - err = rlp.DecodeBytes(res, ret) - return ret, err -} - -// GetAccountByHash does the same thing as GetAccount, however it expects an -// account hash that is the hash of address. This constitutes an abstraction -// leak, since the client code needs to know the key format. -func (t *StateTrie) GetAccountByHash(addrHash common.Hash) (*types.StateAccount, error) { - res, err := t.trie.Get(addrHash.Bytes()) - if res == nil || err != nil { - return nil, err - } - ret := new(types.StateAccount) - err = rlp.DecodeBytes(res, ret) - return ret, err -} - -// GetNode attempts to retrieve a trie node by compact-encoded path. It is not -// possible to use keybyte-encoding as the path might contain odd nibbles. -// If the specified trie node is not in the trie, nil will be returned. -// If a trie node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) GetNode(path []byte) ([]byte, int, error) { - return t.trie.GetNode(path) -} - -// MustUpdate associates key with value in the trie. Subsequent calls to -// Get will return value. If value has length zero, any existing value -// is deleted from the trie and calls to Get will return nil. -// -// The value bytes must not be modified by the caller while they are -// stored in the trie. -// -// This function will omit any encountered error but just print out an -// error message. -func (t *StateTrie) MustUpdate(key, value []byte) { - hk := t.hashKey(key) - t.trie.MustUpdate(hk, value) - t.getSecKeyCache()[string(hk)] = common.CopyBytes(key) -} - -// UpdateStorage associates key with value in the trie. Subsequent calls to -// Get will return value. If value has length zero, any existing value -// is deleted from the trie and calls to Get will return nil. -// -// The value bytes must not be modified by the caller while they are -// stored in the trie. -// -// If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error { - hk := t.hashKey(key) - v, _ := rlp.EncodeToBytes(value) - err := t.trie.Update(hk, v) - if err != nil { - return err - } - t.getSecKeyCache()[string(hk)] = common.CopyBytes(key) - return nil -} - -// UpdateAccount will abstract the write of an account to the secure trie. -func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error { - hk := t.hashKey(address.Bytes()) - data, err := rlp.EncodeToBytes(acc) - if err != nil { - return err - } - if err := t.trie.Update(hk, data); err != nil { - return err - } - t.getSecKeyCache()[string(hk)] = address.Bytes() - return nil -} - -func (t *StateTrie) UpdateContractCode(_ common.Address, _ common.Hash, _ []byte) error { - return nil -} - -// MustDelete removes any existing value for key from the trie. This function -// will omit any encountered error but just print out an error message. -func (t *StateTrie) MustDelete(key []byte) { - hk := t.hashKey(key) - delete(t.getSecKeyCache(), string(hk)) - t.trie.MustDelete(hk) -} - -// DeleteStorage removes any existing storage slot from the trie. -// If the specified trie node is not in the trie, nothing will be changed. -// If a node is not found in the database, a MissingNodeError is returned. -func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error { - hk := t.hashKey(key) - delete(t.getSecKeyCache(), string(hk)) - return t.trie.Delete(hk) -} - -// DeleteAccount abstracts an account deletion from the trie. -func (t *StateTrie) DeleteAccount(address common.Address) error { - hk := t.hashKey(address.Bytes()) - delete(t.getSecKeyCache(), string(hk)) - return t.trie.Delete(hk) -} - -// GetKey returns the sha3 preimage of a hashed key that was -// previously used to store a value. -func (t *StateTrie) GetKey(shaKey []byte) []byte { - if key, ok := t.getSecKeyCache()[string(shaKey)]; ok { - return key - } - return t.db.Preimage(common.BytesToHash(shaKey)) -} - -// Commit collects all dirty nodes in the trie and replaces them with the -// corresponding node hash. All collected nodes (including dirty leaves if -// collectLeaf is true) will be encapsulated into a nodeset for return. -// The returned nodeset can be nil if the trie is clean (nothing to commit). -// All cached preimages will be also flushed if preimages recording is enabled. -// Once the trie is committed, it's not usable anymore. A new trie must -// be created with new root and updated trie database for following usage -func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { - // Write all the pre-images to the actual disk database - if len(t.getSecKeyCache()) > 0 { - preimages := make(map[common.Hash][]byte) - for hk, key := range t.secKeyCache { - preimages[common.BytesToHash([]byte(hk))] = key - } - t.db.InsertPreimage(preimages) - t.secKeyCache = make(map[string][]byte) - } - // Commit the trie and return its modified nodeset. - return t.trie.Commit(collectLeaf) -} - -// Hash returns the root hash of StateTrie. It does not write to the -// database and can be used even if the trie doesn't have one. -func (t *StateTrie) Hash() common.Hash { - return t.trie.Hash() -} - -// Copy returns a copy of StateTrie. -func (t *StateTrie) Copy() *StateTrie { - return &StateTrie{ - trie: *t.trie.Copy(), - db: t.db, - secKeyCache: t.secKeyCache, - } -} - -// NodeIterator returns an iterator that returns nodes of the underlying trie. -// Iteration starts at the key after the given start key. -func (t *StateTrie) NodeIterator(start []byte) (NodeIterator, error) { - return t.trie.NodeIterator(start) -} - -// MustNodeIterator is a wrapper of NodeIterator and will omit any encountered -// error but just print out an error message. -func (t *StateTrie) MustNodeIterator(start []byte) NodeIterator { - return t.trie.MustNodeIterator(start) -} - -// hashKey returns the hash of key as an ephemeral buffer. -// The caller must not hold onto the return value because it will become -// invalid on the next call to hashKey or secKey. -func (t *StateTrie) hashKey(key []byte) []byte { - h := newHasher(false) - h.sha.Reset() - h.sha.Write(key) - h.sha.Read(t.hashKeyBuf[:]) - returnHasherToPool(h) - return t.hashKeyBuf[:] -} - -// getSecKeyCache returns the current secure key cache, creating a new one if -// ownership changed (i.e. the current secure trie is a copy of another owning -// the actual cache). -func (t *StateTrie) getSecKeyCache() map[string][]byte { - if t != t.secKeyCacheOwner { - t.secKeyCacheOwner = t - t.secKeyCache = make(map[string][]byte) - } - return t.secKeyCache -} diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go deleted file mode 100644 index 137ecf1074..0000000000 --- a/trie/secure_trie_test.go +++ /dev/null @@ -1,159 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "fmt" - "runtime" - "sync" - "testing" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -func newEmptySecure() *StateTrie { - trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - return trie -} - -// makeTestStateTrie creates a large enough secure trie for testing. -func makeTestStateTrie() (*testDb, *StateTrie, map[string][]byte) { - // Create an empty trie - triedb := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), triedb) - - // Fill it with some arbitrary data - content := make(map[string][]byte) - for i := byte(0); i < 255; i++ { - // Map the same data under multiple keys - key, val := common.LeftPadBytes([]byte{1, i}, 32), []byte{i} - content[string(key)] = val - trie.MustUpdate(key, val) - - key, val = common.LeftPadBytes([]byte{2, i}, 32), []byte{i} - content[string(key)] = val - trie.MustUpdate(key, val) - - // Add some other data to inflate the trie - for j := byte(3); j < 13; j++ { - key, val = common.LeftPadBytes([]byte{j, i}, 32), []byte{j, i} - content[string(key)] = val - trie.MustUpdate(key, val) - } - } - root, nodes, _ := trie.Commit(false) - if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { - panic(fmt.Errorf("failed to commit db %v", err)) - } - // Re-create the trie based on the new state - trie, _ = NewStateTrie(TrieID(root), triedb) - return triedb, trie, content -} - -func TestSecureDelete(t *testing.T) { - trie := newEmptySecure() - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"ether", ""}, - {"dog", "puppy"}, - {"shaman", ""}, - } - for _, val := range vals { - if val.v != "" { - trie.MustUpdate([]byte(val.k), []byte(val.v)) - } else { - trie.MustDelete([]byte(val.k)) - } - } - hash := trie.Hash() - exp := common.HexToHash("29b235a58c3c25ab83010c327d5932bcf05324b7d6b1185e650798034783ca9d") - if hash != exp { - t.Errorf("expected %x got %x", exp, hash) - } -} - -func TestSecureGetKey(t *testing.T) { - trie := newEmptySecure() - trie.MustUpdate([]byte("foo"), []byte("bar")) - - key := []byte("foo") - value := []byte("bar") - seckey := crypto.Keccak256(key) - - if !bytes.Equal(trie.MustGet(key), value) { - t.Errorf("Get did not return bar") - } - if k := trie.GetKey(seckey); !bytes.Equal(k, key) { - t.Errorf("GetKey returned %q, want %q", k, key) - } -} - -func TestStateTrieConcurrency(t *testing.T) { - // Create an initial trie and copy if for concurrent access - _, trie, _ := makeTestStateTrie() - - threads := runtime.NumCPU() - tries := make([]*StateTrie, threads) - for i := 0; i < threads; i++ { - tries[i] = trie.Copy() - } - // Start a batch of goroutines interacting with the trie - pend := new(sync.WaitGroup) - pend.Add(threads) - for i := 0; i < threads; i++ { - go func(index int) { - defer pend.Done() - - for j := byte(0); j < 255; j++ { - // Map the same data under multiple keys - key, val := common.LeftPadBytes([]byte{byte(index), 1, j}, 32), []byte{j} - tries[index].MustUpdate(key, val) - - key, val = common.LeftPadBytes([]byte{byte(index), 2, j}, 32), []byte{j} - tries[index].MustUpdate(key, val) - - // Add some other data to inflate the trie - for k := byte(3); k < 13; k++ { - key, val = common.LeftPadBytes([]byte{byte(index), k, j}, 32), []byte{k, j} - tries[index].MustUpdate(key, val) - } - } - tries[index].Commit(false) - }(i) - } - // Wait for all threads to finish - pend.Wait() -} diff --git a/trie/stacktrie.go b/trie/stacktrie.go deleted file mode 100644 index 6b2be7dd7f..0000000000 --- a/trie/stacktrie.go +++ /dev/null @@ -1,489 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2020 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "errors" - "sync" - - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/metrics" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" -) - -var ( - stPool = sync.Pool{New: func() any { return new(stNode) }} - _ = types.TrieHasher((*StackTrie)(nil)) -) - -// StackTrieOptions contains the configured options for manipulating the stackTrie. -type StackTrieOptions struct { - Writer func(path []byte, hash common.Hash, blob []byte) // The function to commit the dirty nodes - Cleaner func(path []byte) // The function to clean up dangling nodes - - SkipLeftBoundary bool // Flag whether the nodes on the left boundary are skipped for committing - SkipRightBoundary bool // Flag whether the nodes on the right boundary are skipped for committing - boundaryGauge metrics.Gauge // Gauge to track how many boundary nodes are met -} - -// NewStackTrieOptions initializes an empty options for stackTrie. -func NewStackTrieOptions() *StackTrieOptions { return &StackTrieOptions{} } - -// WithWriter configures trie node writer within the options. -func (o *StackTrieOptions) WithWriter(writer func(path []byte, hash common.Hash, blob []byte)) *StackTrieOptions { - o.Writer = writer - return o -} - -// WithCleaner configures the cleaner in the option for removing dangling nodes. -func (o *StackTrieOptions) WithCleaner(cleaner func(path []byte)) *StackTrieOptions { - o.Cleaner = cleaner - return o -} - -// WithSkipBoundary configures whether the left and right boundary nodes are -// filtered for committing, along with a gauge metrics to track how many -// boundary nodes are met. -func (o *StackTrieOptions) WithSkipBoundary(skipLeft, skipRight bool, gauge metrics.Gauge) *StackTrieOptions { - o.SkipLeftBoundary = skipLeft - o.SkipRightBoundary = skipRight - o.boundaryGauge = gauge - return o -} - -// StackTrie is a trie implementation that expects keys to be inserted -// in order. Once it determines that a subtree will no longer be inserted -// into, it will hash it and free up the memory it uses. -type StackTrie struct { - options *StackTrieOptions - root *stNode - h *hasher - - first []byte // The (hex-encoded without terminator) key of first inserted entry, tracked as left boundary. - last []byte // The (hex-encoded without terminator) key of last inserted entry, tracked as right boundary. -} - -// NewStackTrie allocates and initializes an empty trie. -func NewStackTrie(options *StackTrieOptions) *StackTrie { - if options == nil { - options = NewStackTrieOptions() - } - return &StackTrie{ - options: options, - root: stPool.Get().(*stNode), - h: newHasher(false), - } -} - -// Update inserts a (key, value) pair into the stack trie. -func (t *StackTrie) Update(key, value []byte) error { - if len(value) == 0 { - return errors.New("trying to insert empty (deletion)") - } - k := keybytesToHex(key) - k = k[:len(k)-1] // chop the termination flag - if bytes.Compare(t.last, k) >= 0 { - return errors.New("non-ascending key order") - } - // track the first and last inserted entries. - if t.first == nil { - t.first = append([]byte{}, k...) - } - if t.last == nil { - t.last = append([]byte{}, k...) // allocate key slice - } else { - t.last = append(t.last[:0], k...) // reuse key slice - } - t.insert(t.root, k, value, nil) - return nil -} - -// MustUpdate is a wrapper of Update and will omit any encountered error but -// just print out an error message. -func (t *StackTrie) MustUpdate(key, value []byte) { - if err := t.Update(key, value); err != nil { - log.Error("Unhandled trie error in StackTrie.Update", "err", err) - } -} - -// Reset resets the stack trie object to empty state. -func (t *StackTrie) Reset() { - t.options = NewStackTrieOptions() - t.root = stPool.Get().(*stNode) - t.first = nil - t.last = nil -} - -// stNode represents a node within a StackTrie -type stNode struct { - typ uint8 // node type (as in branch, ext, leaf) - key []byte // key chunk covered by this (leaf|ext) node - val []byte // value contained by this node if it's a leaf - children [16]*stNode // list of children (for branch and exts) -} - -// newLeaf constructs a leaf node with provided node key and value. The key -// will be deep-copied in the function and safe to modify afterwards, but -// value is not. -func newLeaf(key, val []byte) *stNode { - st := stPool.Get().(*stNode) - st.typ = leafNode - st.key = append(st.key, key...) - st.val = val - return st -} - -// newExt constructs an extension node with provided node key and child. The -// key will be deep-copied in the function and safe to modify afterwards. -func newExt(key []byte, child *stNode) *stNode { - st := stPool.Get().(*stNode) - st.typ = extNode - st.key = append(st.key, key...) - st.children[0] = child - return st -} - -// List all values that stNode#nodeType can hold -const ( - emptyNode = iota - branchNode - extNode - leafNode - hashedNode -) - -func (n *stNode) reset() *stNode { - n.key = n.key[:0] - n.val = nil - for i := range n.children { - n.children[i] = nil - } - n.typ = emptyNode - return n -} - -// Helper function that, given a full key, determines the index -// at which the chunk pointed by st.keyOffset is different from -// the same chunk in the full key. -func (n *stNode) getDiffIndex(key []byte) int { - for idx, nibble := range n.key { - if nibble != key[idx] { - return idx - } - } - return len(n.key) -} - -// Helper function to that inserts a (key, value) pair into -// the trie. -func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) { - switch st.typ { - case branchNode: /* Branch */ - idx := int(key[0]) - - // Unresolve elder siblings - for i := idx - 1; i >= 0; i-- { - if st.children[i] != nil { - if st.children[i].typ != hashedNode { - t.hash(st.children[i], append(path, byte(i))) - } - break - } - } - - // Add new child - if st.children[idx] == nil { - st.children[idx] = newLeaf(key[1:], value) - } else { - t.insert(st.children[idx], key[1:], value, append(path, key[0])) - } - - case extNode: /* Ext */ - // Compare both key chunks and see where they differ - diffidx := st.getDiffIndex(key) - - // Check if chunks are identical. If so, recurse into - // the child node. Otherwise, the key has to be split - // into 1) an optional common prefix, 2) the fullnode - // representing the two differing path, and 3) a leaf - // for each of the differentiated subtrees. - if diffidx == len(st.key) { - // Ext key and key segment are identical, recurse into - // the child node. - t.insert(st.children[0], key[diffidx:], value, append(path, key[:diffidx]...)) - return - } - // Save the original part. Depending if the break is - // at the extension's last byte or not, create an - // intermediate extension or use the extension's child - // node directly. - var n *stNode - if diffidx < len(st.key)-1 { - // Break on the non-last byte, insert an intermediate - // extension. The path prefix of the newly-inserted - // extension should also contain the different byte. - n = newExt(st.key[diffidx+1:], st.children[0]) - t.hash(n, append(path, st.key[:diffidx+1]...)) - } else { - // Break on the last byte, no need to insert - // an extension node: reuse the current node. - // The path prefix of the original part should - // still be same. - n = st.children[0] - t.hash(n, append(path, st.key...)) - } - var p *stNode - if diffidx == 0 { - // the break is on the first byte, so - // the current node is converted into - // a branch node. - st.children[0] = nil - p = st - st.typ = branchNode - } else { - // the common prefix is at least one byte - // long, insert a new intermediate branch - // node. - st.children[0] = stPool.Get().(*stNode) - st.children[0].typ = branchNode - p = st.children[0] - } - // Create a leaf for the inserted part - o := newLeaf(key[diffidx+1:], value) - - // Insert both child leaves where they belong: - origIdx := st.key[diffidx] - newIdx := key[diffidx] - p.children[origIdx] = n - p.children[newIdx] = o - st.key = st.key[:diffidx] - - case leafNode: /* Leaf */ - // Compare both key chunks and see where they differ - diffidx := st.getDiffIndex(key) - - // Overwriting a key isn't supported, which means that - // the current leaf is expected to be split into 1) an - // optional extension for the common prefix of these 2 - // keys, 2) a fullnode selecting the path on which the - // keys differ, and 3) one leaf for the differentiated - // component of each key. - if diffidx >= len(st.key) { - panic("Trying to insert into existing key") - } - - // Check if the split occurs at the first nibble of the - // chunk. In that case, no prefix extnode is necessary. - // Otherwise, create that - var p *stNode - if diffidx == 0 { - // Convert current leaf into a branch - st.typ = branchNode - p = st - st.children[0] = nil - } else { - // Convert current node into an ext, - // and insert a child branch node. - st.typ = extNode - st.children[0] = stPool.Get().(*stNode) - st.children[0].typ = branchNode - p = st.children[0] - } - - // Create the two child leaves: one containing the original - // value and another containing the new value. The child leaf - // is hashed directly in order to free up some memory. - origIdx := st.key[diffidx] - p.children[origIdx] = newLeaf(st.key[diffidx+1:], st.val) - t.hash(p.children[origIdx], append(path, st.key[:diffidx+1]...)) - - newIdx := key[diffidx] - p.children[newIdx] = newLeaf(key[diffidx+1:], value) - - // Finally, cut off the key part that has been passed - // over to the children. - st.key = st.key[:diffidx] - st.val = nil - - case emptyNode: /* Empty */ - st.typ = leafNode - st.key = key - st.val = value - - case hashedNode: - panic("trying to insert into hash") - - default: - panic("invalid type") - } -} - -// hash converts st into a 'hashedNode', if possible. Possible outcomes: -// -// 1. The rlp-encoded value was >= 32 bytes: -// - Then the 32-byte `hash` will be accessible in `st.val`. -// - And the 'st.type' will be 'hashedNode' -// -// 2. The rlp-encoded value was < 32 bytes -// - Then the <32 byte rlp-encoded value will be accessible in 'st.val'. -// - And the 'st.type' will be 'hashedNode' AGAIN -// -// This method also sets 'st.type' to hashedNode, and clears 'st.key'. -func (t *StackTrie) hash(st *stNode, path []byte) { - var ( - blob []byte // RLP-encoded node blob - internal [][]byte // List of node paths covered by the extension node - ) - switch st.typ { - case hashedNode: - return - - case emptyNode: - st.val = types.EmptyRootHash.Bytes() - st.key = st.key[:0] - st.typ = hashedNode - return - - case branchNode: - var nodes fullNode - for i, child := range st.children { - if child == nil { - nodes.Children[i] = nilValueNode - continue - } - t.hash(child, append(path, byte(i))) - - if len(child.val) < 32 { - nodes.Children[i] = rawNode(child.val) - } else { - nodes.Children[i] = hashNode(child.val) - } - st.children[i] = nil - stPool.Put(child.reset()) // Release child back to pool. - } - nodes.encode(t.h.encbuf) - blob = t.h.encodedBytes() - - case extNode: - // recursively hash and commit child as the first step - t.hash(st.children[0], append(path, st.key...)) - - // Collect the path of internal nodes between shortNode and its **in disk** - // child. This is essential in the case of path mode scheme to avoid leaving - // danging nodes within the range of this internal path on disk, which would - // break the guarantee for state healing. - if len(st.children[0].val) >= 32 && t.options.Cleaner != nil { - for i := 1; i < len(st.key); i++ { - internal = append(internal, append(path, st.key[:i]...)) - } - } - // encode the extension node - n := shortNode{Key: hexToCompactInPlace(st.key)} - if len(st.children[0].val) < 32 { - n.Val = rawNode(st.children[0].val) - } else { - n.Val = hashNode(st.children[0].val) - } - n.encode(t.h.encbuf) - blob = t.h.encodedBytes() - - stPool.Put(st.children[0].reset()) // Release child back to pool. - st.children[0] = nil - - case leafNode: - st.key = append(st.key, byte(16)) - n := shortNode{Key: hexToCompactInPlace(st.key), Val: valueNode(st.val)} - - n.encode(t.h.encbuf) - blob = t.h.encodedBytes() - - default: - panic("invalid node type") - } - - st.typ = hashedNode - st.key = st.key[:0] - - // Skip committing the non-root node if the size is smaller than 32 bytes. - if len(blob) < 32 && len(path) > 0 { - st.val = common.CopyBytes(blob) - return - } - // Write the hash to the 'val'. We allocate a new val here to not mutate - // input values. - st.val = t.h.hashData(blob) - - // Short circuit if the stack trie is not configured for writing. - if t.options.Writer == nil { - return - } - // Skip committing if the node is on the left boundary and stackTrie is - // configured to filter the boundary. - if t.options.SkipLeftBoundary && bytes.HasPrefix(t.first, path) { - if t.options.boundaryGauge != nil { - t.options.boundaryGauge.Inc(1) - } - return - } - // Skip committing if the node is on the right boundary and stackTrie is - // configured to filter the boundary. - if t.options.SkipRightBoundary && bytes.HasPrefix(t.last, path) { - if t.options.boundaryGauge != nil { - t.options.boundaryGauge.Inc(1) - } - return - } - // Clean up the internal dangling nodes covered by the extension node. - // This should be done before writing the node to adhere to the committing - // order from bottom to top. - for _, path := range internal { - t.options.Cleaner(path) - } - t.options.Writer(path, common.BytesToHash(st.val), blob) -} - -// Hash will firstly hash the entire trie if it's still not hashed and then commit -// all nodes to the associated database. Actually most of the trie nodes have been -// committed already. The main purpose here is to commit the nodes on right boundary. -// -// For stack trie, Hash and Commit are functionally identical. -func (t *StackTrie) Hash() common.Hash { - n := t.root - t.hash(n, nil) - return common.BytesToHash(n.val) -} - -// Commit will firstly hash the entire trie if it's still not hashed and then commit -// all nodes to the associated database. Actually most of the trie nodes have been -// committed already. The main purpose here is to commit the nodes on right boundary. -// -// For stack trie, Hash and Commit are functionally identical. -func (t *StackTrie) Commit() common.Hash { - return t.Hash() -} diff --git a/trie/stacktrie_fuzzer_test.go b/trie/stacktrie_fuzzer_test.go deleted file mode 100644 index 379e18026d..0000000000 --- a/trie/stacktrie_fuzzer_test.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2020 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "encoding/binary" - "fmt" - "testing" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "golang.org/x/crypto/sha3" - "golang.org/x/exp/slices" -) - -func FuzzStackTrie(f *testing.F) { - f.Fuzz(func(t *testing.T, data []byte) { - fuzz(data, false) - }) -} - -func fuzz(data []byte, debugging bool) { - // This spongeDb is used to check the sequence of disk-db-writes - var ( - input = bytes.NewReader(data) - spongeA = &spongeDb{sponge: sha3.NewLegacyKeccak256()} - dbA = newTestDatabase(rawdb.NewDatabase(spongeA), rawdb.HashScheme) - trieA = NewEmpty(dbA) - spongeB = &spongeDb{sponge: sha3.NewLegacyKeccak256()} - dbB = newTestDatabase(rawdb.NewDatabase(spongeB), rawdb.HashScheme) - - options = NewStackTrieOptions().WithWriter(func(path []byte, hash common.Hash, blob []byte) { - rawdb.WriteTrieNode(spongeB, common.Hash{}, path, hash, blob, dbB.Scheme()) - }) - trieB = NewStackTrie(options) - vals []*kv - maxElements = 10000 - // operate on unique keys only - keys = make(map[string]struct{}) - ) - // Fill the trie with elements - for i := 0; input.Len() > 0 && i < maxElements; i++ { - k := make([]byte, 32) - input.Read(k) - var a uint16 - binary.Read(input, binary.LittleEndian, &a) - a = 1 + a%100 - v := make([]byte, a) - input.Read(v) - if input.Len() == 0 { - // If it was exhausted while reading, the value may be all zeroes, - // thus 'deletion' which is not supported on stacktrie - break - } - if _, present := keys[string(k)]; present { - // This key is a duplicate, ignore it - continue - } - keys[string(k)] = struct{}{} - vals = append(vals, &kv{k: k, v: v}) - trieA.MustUpdate(k, v) - } - if len(vals) == 0 { - return - } - // Flush trie -> database - rootA, nodes, err := trieA.Commit(false) - if err != nil { - panic(err) - } - if nodes != nil { - dbA.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - } - // Flush memdb -> disk (sponge) - dbA.Commit(rootA) - - // Stacktrie requires sorted insertion - slices.SortFunc(vals, (*kv).cmp) - - for _, kv := range vals { - if debugging { - fmt.Printf("{\"%#x\" , \"%#x\"} // stacktrie.Update\n", kv.k, kv.v) - } - trieB.MustUpdate(kv.k, kv.v) - } - rootB := trieB.Hash() - trieB.Commit() - if rootA != rootB { - panic(fmt.Sprintf("roots differ: (trie) %x != %x (stacktrie)", rootA, rootB)) - } - sumA := spongeA.sponge.Sum(nil) - sumB := spongeB.sponge.Sum(nil) - if !bytes.Equal(sumA, sumB) { - panic(fmt.Sprintf("sequence differ: (trie) %x != %x (stacktrie)", sumA, sumB)) - } - - // Ensure all the nodes are persisted correctly - var ( - nodeset = make(map[string][]byte) // path -> blob - optionsC = NewStackTrieOptions().WithWriter(func(path []byte, hash common.Hash, blob []byte) { - if crypto.Keccak256Hash(blob) != hash { - panic("invalid node blob") - } - nodeset[string(path)] = common.CopyBytes(blob) - }) - trieC = NewStackTrie(optionsC) - checked int - ) - for _, kv := range vals { - trieC.MustUpdate(kv.k, kv.v) - } - rootC := trieC.Commit() - if rootA != rootC { - panic(fmt.Sprintf("roots differ: (trie) %x != %x (stacktrie)", rootA, rootC)) - } - trieA, _ = New(TrieID(rootA), dbA) - iterA := trieA.MustNodeIterator(nil) - for iterA.Next(true) { - if iterA.Hash() == (common.Hash{}) { - if _, present := nodeset[string(iterA.Path())]; present { - panic("unexpected tiny node") - } - continue - } - nodeBlob, present := nodeset[string(iterA.Path())] - if !present { - panic("missing node") - } - if !bytes.Equal(nodeBlob, iterA.NodeBlob()) { - panic("node blob is not matched") - } - checked += 1 - } - if checked != len(nodeset) { - panic("node number is not matched") - } -} diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go deleted file mode 100644 index f9db27ef0e..0000000000 --- a/trie/stacktrie_test.go +++ /dev/null @@ -1,497 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2020 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "math/big" - "math/rand" - "testing" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/trie/testutil" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/stretchr/testify/assert" - "golang.org/x/exp/slices" -) - -func TestStackTrieInsertAndHash(t *testing.T) { - type KeyValueHash struct { - K string // Hex string for key. - V string // Value, directly converted to bytes. - H string // Expected root hash after insert of (K, V) to an existing trie. - } - tests := [][]KeyValueHash{ - { // {0:0, 7:0, f:0} - {"00", "v_______________________0___0", "5cb26357b95bb9af08475be00243ceb68ade0b66b5cd816b0c18a18c612d2d21"}, - {"70", "v_______________________0___1", "8ff64309574f7a437a7ad1628e690eb7663cfde10676f8a904a8c8291dbc1603"}, - {"f0", "v_______________________0___2", "9e3a01bd8d43efb8e9d4b5506648150b8e3ed1caea596f84ee28e01a72635470"}, - }, - { // {1:0cc, e:{1:fc, e:fc}} - {"10cc", "v_______________________1___0", "233e9b257843f3dfdb1cce6676cdaf9e595ac96ee1b55031434d852bc7ac9185"}, - {"e1fc", "v_______________________1___1", "39c5e908ae83d0c78520c7c7bda0b3782daf594700e44546e93def8f049cca95"}, - {"eefc", "v_______________________1___2", "d789567559fd76fe5b7d9cc42f3750f942502ac1c7f2a466e2f690ec4b6c2a7c"}, - }, - { // {b:{a:ac, b:ac}, d:acc} - {"baac", "v_______________________2___0", "8be1c86ba7ec4c61e14c1a9b75055e0464c2633ae66a055a24e75450156a5d42"}, - {"bbac", "v_______________________2___1", "8495159b9895a7d88d973171d737c0aace6fe6ac02a4769fff1bc43bcccce4cc"}, - {"dacc", "v_______________________2___2", "9bcfc5b220a27328deb9dc6ee2e3d46c9ebc9c69e78acda1fa2c7040602c63ca"}, - }, - { // {0:0cccc, 2:456{0:0, 2:2} - {"00cccc", "v_______________________3___0", "e57dc2785b99ce9205080cb41b32ebea7ac3e158952b44c87d186e6d190a6530"}, - {"245600", "v_______________________3___1", "0335354adbd360a45c1871a842452287721b64b4234dfe08760b243523c998db"}, - {"245622", "v_______________________3___2", "9e6832db0dca2b5cf81c0e0727bfde6afc39d5de33e5720bccacc183c162104e"}, - }, - { // {1:4567{1:1c, 3:3c}, 3:0cccccc} - {"1456711c", "v_______________________4___0", "f2389e78d98fed99f3e63d6d1623c1d4d9e8c91cb1d585de81fbc7c0e60d3529"}, - {"1456733c", "v_______________________4___1", "101189b3fab852be97a0120c03d95eefcf984d3ed639f2328527de6def55a9c0"}, - {"30cccccc", "v_______________________4___2", "3780ce111f98d15751dfde1eb21080efc7d3914b429e5c84c64db637c55405b3"}, - }, - { // 8800{1:f, 2:e, 3:d} - {"88001f", "v_______________________5___0", "e817db50d84f341d443c6f6593cafda093fc85e773a762421d47daa6ac993bd5"}, - {"88002e", "v_______________________5___1", "d6e3e6047bdc110edd296a4d63c030aec451bee9d8075bc5a198eee8cda34f68"}, - {"88003d", "v_______________________5___2", "b6bdf8298c703342188e5f7f84921a402042d0e5fb059969dd53a6b6b1fb989e"}, - }, - { // 0{1:fc, 2:ec, 4:dc} - {"01fc", "v_______________________6___0", "693268f2ca80d32b015f61cd2c4dba5a47a6b52a14c34f8e6945fad684e7a0d5"}, - {"02ec", "v_______________________6___1", "e24ddd44469310c2b785a2044618874bf486d2f7822603a9b8dce58d6524d5de"}, - {"04dc", "v_______________________6___2", "33fc259629187bbe54b92f82f0cd8083b91a12e41a9456b84fc155321e334db7"}, - }, - { // f{0:fccc, f:ff{0:f, f:f}} - {"f0fccc", "v_______________________7___0", "b0966b5aa469a3e292bc5fcfa6c396ae7a657255eef552ea7e12f996de795b90"}, - {"ffff0f", "v_______________________7___1", "3b1ca154ec2a3d96d8d77bddef0abfe40a53a64eb03cecf78da9ec43799fa3d0"}, - {"ffffff", "v_______________________7___2", "e75463041f1be8252781be0ace579a44ea4387bf5b2739f4607af676f7719678"}, - }, - { // ff{0:f{0:f, f:f}, f:fcc} - {"ff0f0f", "v_______________________8___0", "0928af9b14718ec8262ab89df430f1e5fbf66fac0fed037aff2b6767ae8c8684"}, - {"ff0fff", "v_______________________8___1", "d870f4d3ce26b0bf86912810a1960693630c20a48ba56be0ad04bc3e9ddb01e6"}, - {"ffffcc", "v_______________________8___2", "4239f10dd9d9915ecf2e047d6a576bdc1733ed77a30830f1bf29deaf7d8e966f"}, - }, - { - {"123d", "x___________________________0", "fc453d88b6f128a77c448669710497380fa4588abbea9f78f4c20c80daa797d0"}, - {"123e", "x___________________________1", "5af48f2d8a9a015c1ff7fa8b8c7f6b676233bd320e8fb57fd7933622badd2cec"}, - {"123f", "x___________________________2", "1164d7299964e74ac40d761f9189b2a3987fae959800d0f7e29d3aaf3eae9e15"}, - }, - { - {"123d", "x___________________________0", "fc453d88b6f128a77c448669710497380fa4588abbea9f78f4c20c80daa797d0"}, - {"123e", "x___________________________1", "5af48f2d8a9a015c1ff7fa8b8c7f6b676233bd320e8fb57fd7933622badd2cec"}, - {"124a", "x___________________________2", "661a96a669869d76b7231380da0649d013301425fbea9d5c5fae6405aa31cfce"}, - }, - { - {"123d", "x___________________________0", "fc453d88b6f128a77c448669710497380fa4588abbea9f78f4c20c80daa797d0"}, - {"123e", "x___________________________1", "5af48f2d8a9a015c1ff7fa8b8c7f6b676233bd320e8fb57fd7933622badd2cec"}, - {"13aa", "x___________________________2", "6590120e1fd3ffd1a90e8de5bb10750b61079bb0776cca4414dd79a24e4d4356"}, - }, - { - {"123d", "x___________________________0", "fc453d88b6f128a77c448669710497380fa4588abbea9f78f4c20c80daa797d0"}, - {"123e", "x___________________________1", "5af48f2d8a9a015c1ff7fa8b8c7f6b676233bd320e8fb57fd7933622badd2cec"}, - {"2aaa", "x___________________________2", "f869b40e0c55eace1918332ef91563616fbf0755e2b946119679f7ef8e44b514"}, - }, - { - {"1234da", "x___________________________0", "1c4b4462e9f56a80ca0f5d77c0d632c41b0102290930343cf1791e971a045a79"}, - {"1234ea", "x___________________________1", "2f502917f3ba7d328c21c8b45ee0f160652e68450332c166d4ad02d1afe31862"}, - {"1234fa", "x___________________________2", "4f4e368ab367090d5bc3dbf25f7729f8bd60df84de309b4633a6b69ab66142c0"}, - }, - { - {"1234da", "x___________________________0", "1c4b4462e9f56a80ca0f5d77c0d632c41b0102290930343cf1791e971a045a79"}, - {"1234ea", "x___________________________1", "2f502917f3ba7d328c21c8b45ee0f160652e68450332c166d4ad02d1afe31862"}, - {"1235aa", "x___________________________2", "21840121d11a91ac8bbad9a5d06af902a5c8d56a47b85600ba813814b7bfcb9b"}, - }, - { - {"1234da", "x___________________________0", "1c4b4462e9f56a80ca0f5d77c0d632c41b0102290930343cf1791e971a045a79"}, - {"1234ea", "x___________________________1", "2f502917f3ba7d328c21c8b45ee0f160652e68450332c166d4ad02d1afe31862"}, - {"124aaa", "x___________________________2", "ea4040ddf6ae3fbd1524bdec19c0ab1581015996262006632027fa5cf21e441e"}, - }, - { - {"1234da", "x___________________________0", "1c4b4462e9f56a80ca0f5d77c0d632c41b0102290930343cf1791e971a045a79"}, - {"1234ea", "x___________________________1", "2f502917f3ba7d328c21c8b45ee0f160652e68450332c166d4ad02d1afe31862"}, - {"13aaaa", "x___________________________2", "e4beb66c67e44f2dd8ba36036e45a44ff68f8d52942472b1911a45f886a34507"}, - }, - { - {"1234da", "x___________________________0", "1c4b4462e9f56a80ca0f5d77c0d632c41b0102290930343cf1791e971a045a79"}, - {"1234ea", "x___________________________1", "2f502917f3ba7d328c21c8b45ee0f160652e68450332c166d4ad02d1afe31862"}, - {"2aaaaa", "x___________________________2", "5f5989b820ff5d76b7d49e77bb64f26602294f6c42a1a3becc669cd9e0dc8ec9"}, - }, - { - {"000000", "x___________________________0", "3b32b7af0bddc7940e7364ee18b5a59702c1825e469452c8483b9c4e0218b55a"}, - {"1234da", "x___________________________1", "3ab152a1285dca31945566f872c1cc2f17a770440eda32aeee46a5e91033dde2"}, - {"1234ea", "x___________________________2", "0cccc87f96ddef55563c1b3be3c64fff6a644333c3d9cd99852cb53b6412b9b8"}, - {"1234fa", "x___________________________3", "65bb3aafea8121111d693ffe34881c14d27b128fd113fa120961f251fe28428d"}, - }, - { - {"000000", "x___________________________0", "3b32b7af0bddc7940e7364ee18b5a59702c1825e469452c8483b9c4e0218b55a"}, - {"1234da", "x___________________________1", "3ab152a1285dca31945566f872c1cc2f17a770440eda32aeee46a5e91033dde2"}, - {"1234ea", "x___________________________2", "0cccc87f96ddef55563c1b3be3c64fff6a644333c3d9cd99852cb53b6412b9b8"}, - {"1235aa", "x___________________________3", "f670e4d2547c533c5f21e0045442e2ecb733f347ad6d29ef36e0f5ba31bb11a8"}, - }, - { - {"000000", "x___________________________0", "3b32b7af0bddc7940e7364ee18b5a59702c1825e469452c8483b9c4e0218b55a"}, - {"1234da", "x___________________________1", "3ab152a1285dca31945566f872c1cc2f17a770440eda32aeee46a5e91033dde2"}, - {"1234ea", "x___________________________2", "0cccc87f96ddef55563c1b3be3c64fff6a644333c3d9cd99852cb53b6412b9b8"}, - {"124aaa", "x___________________________3", "c17464123050a9a6f29b5574bb2f92f6d305c1794976b475b7fb0316b6335598"}, - }, - { - {"000000", "x___________________________0", "3b32b7af0bddc7940e7364ee18b5a59702c1825e469452c8483b9c4e0218b55a"}, - {"1234da", "x___________________________1", "3ab152a1285dca31945566f872c1cc2f17a770440eda32aeee46a5e91033dde2"}, - {"1234ea", "x___________________________2", "0cccc87f96ddef55563c1b3be3c64fff6a644333c3d9cd99852cb53b6412b9b8"}, - {"13aaaa", "x___________________________3", "aa8301be8cb52ea5cd249f5feb79fb4315ee8de2140c604033f4b3fff78f0105"}, - }, - { - {"0000", "x___________________________0", "cb8c09ad07ae882136f602b3f21f8733a9f5a78f1d2525a8d24d1c13258000b2"}, - {"123d", "x___________________________1", "8f09663deb02f08958136410dc48565e077f76bb6c9d8c84d35fc8913a657d31"}, - {"123e", "x___________________________2", "0d230561e398c579e09a9f7b69ceaf7d3970f5a436fdb28b68b7a37c5bdd6b80"}, - {"123f", "x___________________________3", "80f7bad1893ca57e3443bb3305a517723a74d3ba831bcaca22a170645eb7aafb"}, - }, - { - {"0000", "x___________________________0", "cb8c09ad07ae882136f602b3f21f8733a9f5a78f1d2525a8d24d1c13258000b2"}, - {"123d", "x___________________________1", "8f09663deb02f08958136410dc48565e077f76bb6c9d8c84d35fc8913a657d31"}, - {"123e", "x___________________________2", "0d230561e398c579e09a9f7b69ceaf7d3970f5a436fdb28b68b7a37c5bdd6b80"}, - {"124a", "x___________________________3", "383bc1bb4f019e6bc4da3751509ea709b58dd1ac46081670834bae072f3e9557"}, - }, - { - {"0000", "x___________________________0", "cb8c09ad07ae882136f602b3f21f8733a9f5a78f1d2525a8d24d1c13258000b2"}, - {"123d", "x___________________________1", "8f09663deb02f08958136410dc48565e077f76bb6c9d8c84d35fc8913a657d31"}, - {"123e", "x___________________________2", "0d230561e398c579e09a9f7b69ceaf7d3970f5a436fdb28b68b7a37c5bdd6b80"}, - {"13aa", "x___________________________3", "ff0dc70ce2e5db90ee42a4c2ad12139596b890e90eb4e16526ab38fa465b35cf"}, - }, - { // branch node with short values - {"01", "a", "b48605025f5f4b129d40a420e721aa7d504487f015fce85b96e52126365ef7dc"}, - {"80", "b", "2dc6b680daf74db067cb7aeaad73265ded93d96fce190fcbf64f498d475672ab"}, - {"ee", "c", "017dc705a54ac5328dd263fa1bae68d655310fb3e3f7b7bc57e9a43ddf99c4bf"}, - {"ff", "d", "bd5a3584d271d459bd4eb95247b2fc88656b3671b60c1125ffe7bc0b689470d0"}, - }, - { // ext node with short branch node, then becoming long - {"a0", "a", "a83e028cb1e4365935661a9fd36a5c65c30b9ab416eaa877424146ca2a69d088"}, - {"a1", "b", "f586a4639b07b01798ca65e05c253b75d51135ebfbf6f8d6e87c0435089e65f0"}, - {"a2", "c", "63e297c295c008e09a8d531e18d57f270b6bc403e23179b915429db948cd62e3"}, - {"a3", "d", "94a7b721535578e9381f1f4e4b6ec29f8bdc5f0458a30320684c562f5d47b4b5"}, - {"a4", "e", "4b7e66d1c81965cdbe8fab8295ef56bc57fefdc5733d4782d2f8baf630f083c6"}, - {"a5", "f", "2997e7b502198ce1783b5277faacf52b25844fb55a99b63e88bdbbafac573106"}, - {"a6", "g", "bee629dd27a40772b2e1a67ec6db270d26acdf8d3b674dfae27866ad6ae1f48b"}, - }, - { // branch node with short values, then long ones - {"a001", "v1", "b9cc982d995392b51e6787f1915f0b88efd4ad8b30f138da0a3e2242f2323e35"}, - {"b002", "v2", "a7b474bc77ef5097096fa0ee6298fdae8928c0bc3724e7311cd0fa9ed1942fc7"}, - {"c003", "v___________________________3", "dceb5bb7c92b0e348df988a8d9fc36b101397e38ebd405df55ba6ee5f14a264a"}, - {"d004", "v___________________________4", "36e60ecb86b9626165e1c6543c42ecbe4d83bca58e8e1124746961511fce362a"}, - }, - { // ext node to branch node with short values, then long ones - {"8002", "v1", "3258fcb3e9e7d7234ecd3b8d4743999e4ab3a21592565e0a5ca64c141e8620d9"}, - {"8004", "v2", "b6cb95b7024a83c17624a3c9bed09b4b5e8ed426f49f54b8ad13c39028b1e75a"}, - {"8008", "v___________________________3", "c769d82963abe6f0900bf69754738eeb2f84559777cfa87a44f54e1aab417871"}, - {"800d", "v___________________________4", "1cad1fdaab1a6fa95d7b780fd680030e423eb76669971368ba04797a8d9cdfc9"}, - }, - { // ext node with a child of size 31 (Y) and branch node with a child of size 31 (X) - {"000001", "ZZZZZZZZZ", "cef154b87c03c563408520ff9b26923c360cbc3ddb590c079bedeeb25a8c9c77"}, - {"000002", "Y", "2130735e600f612f6e657a32bd7be64ddcaec6512c5694844b19de713922895d"}, - {"000003", "XXXXXXXXXXXXXXXXXXXXXXXXXXXX", "962c0fffdeef7612a4f7bff1950d67e3e81c878e48b9ae45b3b374253b050bd8"}, - }, - } - for i, test := range tests { - // The StackTrie does not allow Insert(), Hash(), Insert(), ... - // so we will create new trie for every sequence length of inserts. - for l := 1; l <= len(test); l++ { - st := NewStackTrie(nil) - for j := 0; j < l; j++ { - kv := &test[j] - if err := st.Update(common.FromHex(kv.K), []byte(kv.V)); err != nil { - t.Fatal(err) - } - } - expected := common.HexToHash(test[l-1].H) - if h := st.Hash(); h != expected { - t.Errorf("%d(%d): root hash mismatch: %x, expected %x", i, l, h, expected) - } - } - } -} - -func TestSizeBug(t *testing.T) { - st := NewStackTrie(nil) - nt := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - - leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") - value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") - - nt.Update(leaf, value) - st.Update(leaf, value) - - if nt.Hash() != st.Hash() { - t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) - } -} - -func TestEmptyBug(t *testing.T) { - st := NewStackTrie(nil) - nt := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - - //leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") - //value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") - kvs := []struct { - K string - V string - }{ - {K: "405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace", V: "9496f4ec2bf9dab484cac6be589e8417d84781be08"}, - {K: "40edb63a35fcf86c08022722aa3287cdd36440d671b4918131b2514795fefa9c", V: "01"}, - {K: "b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6", V: "947a30f7736e48d6599356464ba4c150d8da0302ff"}, - {K: "c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b", V: "02"}, - } - - for _, kv := range kvs { - nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) - st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) - } - - if nt.Hash() != st.Hash() { - t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) - } -} - -func TestValLength56(t *testing.T) { - st := NewStackTrie(nil) - nt := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - - //leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") - //value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") - kvs := []struct { - K string - V string - }{ - {K: "405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace", V: "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"}, - } - - for _, kv := range kvs { - nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) - st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) - } - - if nt.Hash() != st.Hash() { - t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) - } -} - -// TestUpdateSmallNodes tests a case where the leaves are small (both key and value), -// which causes a lot of node-within-node. This case was found via fuzzing. -func TestUpdateSmallNodes(t *testing.T) { - st := NewStackTrie(nil) - nt := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - kvs := []struct { - K string - V string - }{ - {"63303030", "3041"}, // stacktrie.Update - {"65", "3000"}, // stacktrie.Update - } - for _, kv := range kvs { - nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) - st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) - } - if nt.Hash() != st.Hash() { - t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) - } -} - -// TestUpdateVariableKeys contains a case which stacktrie fails: when keys of different -// sizes are used, and the second one has the same prefix as the first, then the -// stacktrie fails, since it's unable to 'expand' on an already added leaf. -// For all practical purposes, this is fine, since keys are fixed-size length -// in account and storage tries. -// -// The test is marked as 'skipped', and exists just to have the behaviour documented. -// This case was found via fuzzing. -func TestUpdateVariableKeys(t *testing.T) { - t.SkipNow() - st := NewStackTrie(nil) - nt := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - kvs := []struct { - K string - V string - }{ - {"0x33303534636532393561313031676174", "303030"}, - {"0x3330353463653239356131303167617430", "313131"}, - } - for _, kv := range kvs { - nt.Update(common.FromHex(kv.K), common.FromHex(kv.V)) - st.Update(common.FromHex(kv.K), common.FromHex(kv.V)) - } - if nt.Hash() != st.Hash() { - t.Fatalf("error %x != %x", st.Hash(), nt.Hash()) - } -} - -// TestStacktrieNotModifyValues checks that inserting blobs of data into the -// stacktrie does not mutate the blobs -func TestStacktrieNotModifyValues(t *testing.T) { - st := NewStackTrie(nil) - { // Test a very small trie - // Give it the value as a slice with large backing alloc, - // so if the stacktrie tries to append, it won't have to realloc - value := make([]byte, 1, 100) - value[0] = 0x2 - want := common.CopyBytes(value) - st.Update([]byte{0x01}, value) - st.Hash() - if have := value; !bytes.Equal(have, want) { - t.Fatalf("tiny trie: have %#x want %#x", have, want) - } - st = NewStackTrie(nil) - } - // Test with a larger trie - keyB := big.NewInt(1) - keyDelta := big.NewInt(1) - var vals [][]byte - getValue := func(i int) []byte { - if i%2 == 0 { // large - return crypto.Keccak256(big.NewInt(int64(i)).Bytes()) - } else { //small - return big.NewInt(int64(i)).Bytes() - } - } - for i := 0; i < 1000; i++ { - key := common.BigToHash(keyB) - value := getValue(i) - st.Update(key.Bytes(), value) - vals = append(vals, value) - keyB = keyB.Add(keyB, keyDelta) - keyDelta.Add(keyDelta, common.Big1) - } - st.Hash() - for i := 0; i < 1000; i++ { - want := getValue(i) - - have := vals[i] - if !bytes.Equal(have, want) { - t.Fatalf("item %d, have %#x want %#x", i, have, want) - } - } -} - -func buildPartialTree(entries []*kv, t *testing.T) map[string]common.Hash { - var ( - options = NewStackTrieOptions() - nodes = make(map[string]common.Hash) - ) - var ( - first int - last = len(entries) - 1 - - noLeft bool - noRight bool - ) - // Enter split mode if there are at least two elements - if rand.Intn(5) != 0 { - for { - first = rand.Intn(len(entries)) - last = rand.Intn(len(entries)) - if first <= last { - break - } - } - if first != 0 { - noLeft = true - } - if last != len(entries)-1 { - noRight = true - } - } - options = options.WithSkipBoundary(noLeft, noRight, nil) - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - nodes[string(path)] = hash - }) - tr := NewStackTrie(options) - - for i := first; i <= last; i++ { - tr.MustUpdate(entries[i].k, entries[i].v) - } - tr.Commit() - return nodes -} - -func TestPartialStackTrie(t *testing.T) { - for round := 0; round < 100; round++ { - var ( - n = rand.Intn(100) + 1 - entries []*kv - ) - for i := 0; i < n; i++ { - var val []byte - if rand.Intn(3) == 0 { - val = testutil.RandBytes(3) - } else { - val = testutil.RandBytes(32) - } - entries = append(entries, &kv{ - k: testutil.RandBytes(32), - v: val, - }) - } - slices.SortFunc(entries, (*kv).cmp) - - var ( - nodes = make(map[string]common.Hash) - options = NewStackTrieOptions().WithWriter(func(path []byte, hash common.Hash, blob []byte) { - nodes[string(path)] = hash - }) - ) - tr := NewStackTrie(options) - - for i := 0; i < len(entries); i++ { - tr.MustUpdate(entries[i].k, entries[i].v) - } - tr.Commit() - - for j := 0; j < 100; j++ { - for path, hash := range buildPartialTree(entries, t) { - if nodes[path] != hash { - t.Errorf("%v, want %x, got %x", []byte(path), nodes[path], hash) - } - } - } - } -} - -func TestStackTrieErrors(t *testing.T) { - s := NewStackTrie(nil) - // Deletion - if err := s.Update(nil, nil); err == nil { - t.Fatal("expected error") - } - if err := s.Update(nil, []byte{}); err == nil { - t.Fatal("expected error") - } - if err := s.Update([]byte{0xa}, []byte{}); err == nil { - t.Fatal("expected error") - } - // Non-ascending keys (going backwards or repeating) - assert.Nil(t, s.Update([]byte{0xaa}, []byte{0xa})) - assert.NotNil(t, s.Update([]byte{0xaa}, []byte{0xa}), "repeat insert same key") - assert.NotNil(t, s.Update([]byte{0xaa}, []byte{0xb}), "repeat insert same key") - assert.Nil(t, s.Update([]byte{0xab}, []byte{0xa})) - assert.NotNil(t, s.Update([]byte{0x10}, []byte{0xb}), "out of order insert") - assert.NotNil(t, s.Update([]byte{0xaa}, []byte{0xb}), "repeat insert same key") -} diff --git a/trie/sync_test.go b/trie/sync_test.go deleted file mode 100644 index e0838a2059..0000000000 --- a/trie/sync_test.go +++ /dev/null @@ -1,97 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "fmt" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" -) - -// makeTestTrie create a sample test trie to test node-wise reconstruction. -func makeTestTrie(scheme string) (ethdb.Database, *testDb, *StateTrie, map[string][]byte) { - // Create an empty trie - db := rawdb.NewMemoryDatabase() - triedb := newTestDatabase(db, scheme) - trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), triedb) - - // Fill it with some arbitrary data - content := make(map[string][]byte) - for i := byte(0); i < 255; i++ { - // Map the same data under multiple keys - key, val := common.LeftPadBytes([]byte{1, i}, 32), []byte{i} - content[string(key)] = val - trie.MustUpdate(key, val) - - key, val = common.LeftPadBytes([]byte{2, i}, 32), []byte{i} - content[string(key)] = val - trie.MustUpdate(key, val) - - // Add some other data to inflate the trie - for j := byte(3); j < 13; j++ { - key, val = common.LeftPadBytes([]byte{j, i}, 32), []byte{j, i} - content[string(key)] = val - trie.MustUpdate(key, val) - } - } - root, nodes, _ := trie.Commit(false) - if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { - panic(fmt.Errorf("failed to commit db %v", err)) - } - if err := triedb.Commit(root); err != nil { - panic(err) - } - // Re-create the trie based on the new state - trie, _ = NewStateTrie(TrieID(root), triedb) - return db, triedb, trie, content -} - -// checkTrieConsistency checks that all nodes in a trie are indeed present. -func checkTrieConsistency(db ethdb.Database, scheme string, root common.Hash, rawTrie bool) error { - ndb := newTestDatabase(db, scheme) - var it NodeIterator - if rawTrie { - trie, err := New(TrieID(root), ndb) - if err != nil { - return nil // Consider a non existent state consistent - } - it = trie.MustNodeIterator(nil) - } else { - trie, err := NewStateTrie(TrieID(root), ndb) - if err != nil { - return nil // Consider a non existent state consistent - } - it = trie.MustNodeIterator(nil) - } - for it.Next(true) { - } - return it.Error() -} diff --git a/trie/testutil/utils.go b/trie/testutil/utils.go deleted file mode 100644 index 88411efec5..0000000000 --- a/trie/testutil/utils.go +++ /dev/null @@ -1,71 +0,0 @@ -// (c) 2024, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2023 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 testutil - -import ( - crand "crypto/rand" - "encoding/binary" - mrand "math/rand" - - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -// Prng is a pseudo random number generator seeded by strong randomness. -// The randomness is printed on startup in order to make failures reproducible. -var prng = initRand() - -func initRand() *mrand.Rand { - var seed [8]byte - crand.Read(seed[:]) - rnd := mrand.New(mrand.NewSource(int64(binary.LittleEndian.Uint64(seed[:])))) - return rnd -} - -// RandBytes generates a random byte slice with specified length. -func RandBytes(n int) []byte { - r := make([]byte, n) - prng.Read(r) - return r -} - -// RandomHash generates a random blob of data and returns it as a hash. -func RandomHash() common.Hash { - return common.BytesToHash(RandBytes(common.HashLength)) -} - -// RandomAddress generates a random blob of data and returns it as an address. -func RandomAddress() common.Address { - return common.BytesToAddress(RandBytes(common.AddressLength)) -} - -// RandomNode generates a random node. -func RandomNode() *trienode.Node { - val := RandBytes(100) - return trienode.New(crypto.Keccak256Hash(val), val) -} diff --git a/trie/tracer.go b/trie/tracer.go deleted file mode 100644 index 5786af4d3e..0000000000 --- a/trie/tracer.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "github.com/ethereum/go-ethereum/common" -) - -// tracer tracks the changes of trie nodes. During the trie operations, -// some nodes can be deleted from the trie, while these deleted nodes -// won't be captured by trie.Hasher or trie.Committer. Thus, these deleted -// nodes won't be removed from the disk at all. Tracer is an auxiliary tool -// used to track all insert and delete operations of trie and capture all -// deleted nodes eventually. -// -// The changed nodes can be mainly divided into two categories: the leaf -// node and intermediate node. The former is inserted/deleted by callers -// while the latter is inserted/deleted in order to follow the rule of trie. -// This tool can track all of them no matter the node is embedded in its -// parent or not, but valueNode is never tracked. -// -// Besides, it's also used for recording the original value of the nodes -// when they are resolved from the disk. The pre-value of the nodes will -// be used to construct trie history in the future. -// -// Note tracer is not thread-safe, callers should be responsible for handling -// the concurrency issues by themselves. -type tracer struct { - inserts map[string]struct{} - deletes map[string]struct{} - accessList map[string][]byte -} - -// newTracer initializes the tracer for capturing trie changes. -func newTracer() *tracer { - return &tracer{ - inserts: make(map[string]struct{}), - deletes: make(map[string]struct{}), - accessList: make(map[string][]byte), - } -} - -// onRead tracks the newly loaded trie node and caches the rlp-encoded -// blob internally. Don't change the value outside of function since -// it's not deep-copied. -func (t *tracer) onRead(path []byte, val []byte) { - t.accessList[string(path)] = val -} - -// onInsert tracks the newly inserted trie node. If it's already -// in the deletion set (resurrected node), then just wipe it from -// the deletion set as it's "untouched". -func (t *tracer) onInsert(path []byte) { - if _, present := t.deletes[string(path)]; present { - delete(t.deletes, string(path)) - return - } - t.inserts[string(path)] = struct{}{} -} - -// onDelete tracks the newly deleted trie node. If it's already -// in the addition set, then just wipe it from the addition set -// as it's untouched. -func (t *tracer) onDelete(path []byte) { - if _, present := t.inserts[string(path)]; present { - delete(t.inserts, string(path)) - return - } - t.deletes[string(path)] = struct{}{} -} - -// reset clears the content tracked by tracer. -func (t *tracer) reset() { - t.inserts = make(map[string]struct{}) - t.deletes = make(map[string]struct{}) - t.accessList = make(map[string][]byte) -} - -// copy returns a deep copied tracer instance. -func (t *tracer) copy() *tracer { - var ( - inserts = make(map[string]struct{}) - deletes = make(map[string]struct{}) - accessList = make(map[string][]byte) - ) - for path := range t.inserts { - inserts[path] = struct{}{} - } - for path := range t.deletes { - deletes[path] = struct{}{} - } - for path, blob := range t.accessList { - accessList[path] = common.CopyBytes(blob) - } - return &tracer{ - inserts: inserts, - deletes: deletes, - accessList: accessList, - } -} - -// deletedNodes returns a list of node paths which are deleted from the trie. -func (t *tracer) deletedNodes() []string { - var paths []string - for path := range t.deletes { - // It's possible a few deleted nodes were embedded - // in their parent before, the deletions can be no - // effect by deleting nothing, filter them out. - _, ok := t.accessList[path] - if !ok { - continue - } - paths = append(paths, path) - } - return paths -} diff --git a/trie/tracer_test.go b/trie/tracer_test.go deleted file mode 100644 index b3735dd1ff..0000000000 --- a/trie/tracer_test.go +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "testing" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" -) - -var ( - tiny = []struct{ k, v string }{ - {"k1", "v1"}, - {"k2", "v2"}, - {"k3", "v3"}, - } - nonAligned = []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - standard = []struct{ k, v string }{ - {string(randBytes(32)), "verb"}, - {string(randBytes(32)), "wookiedoo"}, - {string(randBytes(32)), "stallion"}, - {string(randBytes(32)), "horse"}, - {string(randBytes(32)), "coin"}, - {string(randBytes(32)), "puppy"}, - {string(randBytes(32)), "myothernodedata"}, - } -) - -func TestTrieTracer(t *testing.T) { - testTrieTracer(t, tiny) - testTrieTracer(t, nonAligned) - testTrieTracer(t, standard) -} - -// Tests if the trie diffs are tracked correctly. Tracer should capture -// all non-leaf dirty nodes, no matter the node is embedded or not. -func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { - db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie := NewEmpty(db) - - // Determine all new nodes are tracked - for _, val := range vals { - trie.MustUpdate([]byte(val.k), []byte(val.v)) - } - insertSet := copySet(trie.tracer.inserts) // copy before commit - deleteSet := copySet(trie.tracer.deletes) // copy before commit - root, nodes, _ := trie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - - seen := setKeys(iterNodes(db, root)) - if !compareSet(insertSet, seen) { - t.Fatal("Unexpected insertion set") - } - if !compareSet(deleteSet, nil) { - t.Fatal("Unexpected deletion set") - } - - // Determine all deletions are tracked - trie, _ = New(TrieID(root), db) - for _, val := range vals { - trie.MustDelete([]byte(val.k)) - } - insertSet, deleteSet = copySet(trie.tracer.inserts), copySet(trie.tracer.deletes) - if !compareSet(insertSet, nil) { - t.Fatal("Unexpected insertion set") - } - if !compareSet(deleteSet, seen) { - t.Fatal("Unexpected deletion set") - } -} - -// Test that after inserting a new batch of nodes and deleting them immediately, -// the trie tracer should be cleared normally as no operation happened. -func TestTrieTracerNoop(t *testing.T) { - testTrieTracerNoop(t, tiny) - testTrieTracerNoop(t, nonAligned) - testTrieTracerNoop(t, standard) -} - -func testTrieTracerNoop(t *testing.T, vals []struct{ k, v string }) { - db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie := NewEmpty(db) - for _, val := range vals { - trie.MustUpdate([]byte(val.k), []byte(val.v)) - } - for _, val := range vals { - trie.MustDelete([]byte(val.k)) - } - if len(trie.tracer.inserts) != 0 { - t.Fatal("Unexpected insertion set") - } - if len(trie.tracer.deletes) != 0 { - t.Fatal("Unexpected deletion set") - } -} - -// Tests if the accessList is correctly tracked. -func TestAccessList(t *testing.T) { - testAccessList(t, tiny) - testAccessList(t, nonAligned) - testAccessList(t, standard) -} - -func testAccessList(t *testing.T, vals []struct{ k, v string }) { - var ( - db = newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie = NewEmpty(db) - orig = trie.Copy() - ) - // Create trie from scratch - for _, val := range vals { - trie.MustUpdate([]byte(val.k), []byte(val.v)) - } - root, nodes, _ := trie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - - trie, _ = New(TrieID(root), db) - if err := verifyAccessList(orig, trie, nodes); err != nil { - t.Fatalf("Invalid accessList %v", err) - } - - // Update trie - parent := root - trie, _ = New(TrieID(root), db) - orig = trie.Copy() - for _, val := range vals { - trie.MustUpdate([]byte(val.k), randBytes(32)) - } - root, nodes, _ = trie.Commit(false) - db.Update(root, parent, trienode.NewWithNodeSet(nodes)) - - trie, _ = New(TrieID(root), db) - if err := verifyAccessList(orig, trie, nodes); err != nil { - t.Fatalf("Invalid accessList %v", err) - } - - // Add more new nodes - parent = root - trie, _ = New(TrieID(root), db) - orig = trie.Copy() - var keys []string - for i := 0; i < 30; i++ { - key := randBytes(32) - keys = append(keys, string(key)) - trie.MustUpdate(key, randBytes(32)) - } - root, nodes, _ = trie.Commit(false) - db.Update(root, parent, trienode.NewWithNodeSet(nodes)) - - trie, _ = New(TrieID(root), db) - if err := verifyAccessList(orig, trie, nodes); err != nil { - t.Fatalf("Invalid accessList %v", err) - } - - // Partial deletions - parent = root - trie, _ = New(TrieID(root), db) - orig = trie.Copy() - for _, key := range keys { - trie.MustUpdate([]byte(key), nil) - } - root, nodes, _ = trie.Commit(false) - db.Update(root, parent, trienode.NewWithNodeSet(nodes)) - - trie, _ = New(TrieID(root), db) - if err := verifyAccessList(orig, trie, nodes); err != nil { - t.Fatalf("Invalid accessList %v", err) - } - - // Delete all - parent = root - trie, _ = New(TrieID(root), db) - orig = trie.Copy() - for _, val := range vals { - trie.MustUpdate([]byte(val.k), nil) - } - root, nodes, _ = trie.Commit(false) - db.Update(root, parent, trienode.NewWithNodeSet(nodes)) - - trie, _ = New(TrieID(root), db) - if err := verifyAccessList(orig, trie, nodes); err != nil { - t.Fatalf("Invalid accessList %v", err) - } -} - -// Tests origin values won't be tracked in Iterator or Prover -func TestAccessListLeak(t *testing.T) { - var ( - db = newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie = NewEmpty(db) - ) - // Create trie from scratch - for _, val := range standard { - trie.MustUpdate([]byte(val.k), []byte(val.v)) - } - root, nodes, _ := trie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - - var cases = []struct { - op func(tr *Trie) - }{ - { - func(tr *Trie) { - it := tr.MustNodeIterator(nil) - for it.Next(true) { - } - }, - }, - { - func(tr *Trie) { - it := NewIterator(tr.MustNodeIterator(nil)) - for it.Next() { - } - }, - }, - { - func(tr *Trie) { - for _, val := range standard { - tr.Prove([]byte(val.k), rawdb.NewMemoryDatabase()) - } - }, - }, - } - for _, c := range cases { - trie, _ = New(TrieID(root), db) - n1 := len(trie.tracer.accessList) - c.op(trie) - n2 := len(trie.tracer.accessList) - - if n1 != n2 { - t.Fatalf("AccessList is leaked, prev %d after %d", n1, n2) - } - } -} - -// Tests whether the original tree node is correctly deleted after being embedded -// in its parent due to the smaller size of the original tree node. -func TestTinyTree(t *testing.T) { - var ( - db = newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie = NewEmpty(db) - ) - for _, val := range tiny { - trie.MustUpdate([]byte(val.k), randBytes(32)) - } - root, set, _ := trie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(set)) - - parent := root - trie, _ = New(TrieID(root), db) - orig := trie.Copy() - for _, val := range tiny { - trie.MustUpdate([]byte(val.k), []byte(val.v)) - } - root, set, _ = trie.Commit(false) - db.Update(root, parent, trienode.NewWithNodeSet(set)) - - trie, _ = New(TrieID(root), db) - if err := verifyAccessList(orig, trie, set); err != nil { - t.Fatalf("Invalid accessList %v", err) - } -} - -func compareSet(setA, setB map[string]struct{}) bool { - if len(setA) != len(setB) { - return false - } - for key := range setA { - if _, ok := setB[key]; !ok { - return false - } - } - return true -} - -func forNodes(tr *Trie) map[string][]byte { - var ( - it = tr.MustNodeIterator(nil) - nodes = make(map[string][]byte) - ) - for it.Next(true) { - if it.Leaf() { - continue - } - nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) - } - return nodes -} - -func iterNodes(db *testDb, root common.Hash) map[string][]byte { - tr, _ := New(TrieID(root), db) - return forNodes(tr) -} - -func forHashedNodes(tr *Trie) map[string][]byte { - var ( - it = tr.MustNodeIterator(nil) - nodes = make(map[string][]byte) - ) - for it.Next(true) { - if it.Hash() == (common.Hash{}) { - continue - } - nodes[string(it.Path())] = common.CopyBytes(it.NodeBlob()) - } - return nodes -} - -func diffTries(trieA, trieB *Trie) (map[string][]byte, map[string][]byte, map[string][]byte) { - var ( - nodesA = forHashedNodes(trieA) - nodesB = forHashedNodes(trieB) - inA = make(map[string][]byte) // hashed nodes in trie a but not b - inB = make(map[string][]byte) // hashed nodes in trie b but not a - both = make(map[string][]byte) // hashed nodes in both tries but different value - ) - for path, blobA := range nodesA { - if blobB, ok := nodesB[path]; ok { - if bytes.Equal(blobA, blobB) { - continue - } - both[path] = blobA - continue - } - inA[path] = blobA - } - for path, blobB := range nodesB { - if _, ok := nodesA[path]; ok { - continue - } - inB[path] = blobB - } - return inA, inB, both -} - -func setKeys(set map[string][]byte) map[string]struct{} { - keys := make(map[string]struct{}) - for k := range set { - keys[k] = struct{}{} - } - return keys -} - -func copySet(set map[string]struct{}) map[string]struct{} { - copied := make(map[string]struct{}) - for k := range set { - copied[k] = struct{}{} - } - return copied -} diff --git a/trie/trie.go b/trie/trie.go deleted file mode 100644 index 4370f22f20..0000000000 --- a/trie/trie.go +++ /dev/null @@ -1,683 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie implements Merkle Patricia Tries. -package trie - -import ( - "bytes" - "errors" - "fmt" - - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/triedb/database" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" -) - -// Trie is a Merkle Patricia Trie. Use New to create a trie that sits on -// top of a database. Whenever trie performs a commit operation, the generated -// nodes will be gathered and returned in a set. Once the trie is committed, -// it's not usable anymore. Callers have to re-create the trie with new root -// based on the updated trie database. -// -// Trie is not safe for concurrent use. -type Trie struct { - root node - owner common.Hash - - // Flag whether the commit operation is already performed. If so the - // trie is not usable(latest states is invisible). - committed bool - - // Keep track of the number leaves which have been inserted since the last - // hashing operation. This number will not directly map to the number of - // actually unhashed nodes. - unhashed int - - // reader is the handler trie can retrieve nodes from. - reader *trieReader - - // tracer is the tool to track the trie changes. - // It will be reset after each commit operation. - tracer *tracer -} - -// newFlag returns the cache flag value for a newly created node. -func (t *Trie) newFlag() nodeFlag { - return nodeFlag{dirty: true} -} - -// Copy returns a copy of Trie. -func (t *Trie) Copy() *Trie { - return &Trie{ - root: t.root, - owner: t.owner, - committed: t.committed, - unhashed: t.unhashed, - reader: t.reader, - tracer: t.tracer.copy(), - } -} - -// New creates the trie instance with provided trie id and the read-only -// database. The state specified by trie id must be available, otherwise -// an error will be returned. The trie root specified by trie id can be -// zero hash or the sha3 hash of an empty string, then trie is initially -// empty, otherwise, the root node must be present in database or returns -// a MissingNodeError if not. -func New(id *ID, db database.Database) (*Trie, error) { - reader, err := newTrieReader(id.StateRoot, id.Owner, db) - if err != nil { - return nil, err - } - trie := &Trie{ - owner: id.Owner, - reader: reader, - tracer: newTracer(), - } - if id.Root != (common.Hash{}) && id.Root != types.EmptyRootHash { - rootnode, err := trie.resolveAndTrack(id.Root[:], nil) - if err != nil { - return nil, err - } - trie.root = rootnode - } - return trie, nil -} - -// NewEmpty is a shortcut to create empty tree. It's mostly used in tests. -func NewEmpty(db database.Database) *Trie { - tr, _ := New(TrieID(types.EmptyRootHash), db) - return tr -} - -// MustNodeIterator is a wrapper of NodeIterator and will omit any encountered -// error but just print out an error message. -func (t *Trie) MustNodeIterator(start []byte) NodeIterator { - it, err := t.NodeIterator(start) - if err != nil { - log.Error("Unhandled trie error in Trie.NodeIterator", "err", err) - } - return it -} - -// NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at -// the key after the given start key. -func (t *Trie) NodeIterator(start []byte) (NodeIterator, error) { - // Short circuit if the trie is already committed and not usable. - if t.committed { - return nil, ErrCommitted - } - return newNodeIterator(t, start), nil -} - -// MustGet is a wrapper of Get and will omit any encountered error but just -// print out an error message. -func (t *Trie) MustGet(key []byte) []byte { - res, err := t.Get(key) - if err != nil { - log.Error("Unhandled trie error in Trie.Get", "err", err) - } - return res -} - -// Get returns the value for key stored in the trie. -// The value bytes must not be modified by the caller. -// -// If the requested node is not present in trie, no error will be returned. -// If the trie is corrupted, a MissingNodeError is returned. -func (t *Trie) Get(key []byte) ([]byte, error) { - // Short circuit if the trie is already committed and not usable. - if t.committed { - return nil, ErrCommitted - } - value, newroot, didResolve, err := t.get(t.root, keybytesToHex(key), 0) - if err == nil && didResolve { - t.root = newroot - } - return value, err -} - -func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode node, didResolve bool, err error) { - switch n := (origNode).(type) { - case nil: - return nil, nil, false, nil - case valueNode: - return n, n, false, nil - case *shortNode: - if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) { - // key not found in trie - return nil, n, false, nil - } - value, newnode, didResolve, err = t.get(n.Val, key, pos+len(n.Key)) - if err == nil && didResolve { - n = n.copy() - n.Val = newnode - } - return value, n, didResolve, err - case *fullNode: - value, newnode, didResolve, err = t.get(n.Children[key[pos]], key, pos+1) - if err == nil && didResolve { - n = n.copy() - n.Children[key[pos]] = newnode - } - return value, n, didResolve, err - case hashNode: - child, err := t.resolveAndTrack(n, key[:pos]) - if err != nil { - return nil, n, true, err - } - value, newnode, _, err := t.get(child, key, pos) - return value, newnode, true, err - default: - panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode)) - } -} - -// MustGetNode is a wrapper of GetNode and will omit any encountered error but -// just print out an error message. -func (t *Trie) MustGetNode(path []byte) ([]byte, int) { - item, resolved, err := t.GetNode(path) - if err != nil { - log.Error("Unhandled trie error in Trie.GetNode", "err", err) - } - return item, resolved -} - -// GetNode retrieves a trie node by compact-encoded path. It is not possible -// to use keybyte-encoding as the path might contain odd nibbles. -// -// If the requested node is not present in trie, no error will be returned. -// If the trie is corrupted, a MissingNodeError is returned. -func (t *Trie) GetNode(path []byte) ([]byte, int, error) { - // Short circuit if the trie is already committed and not usable. - if t.committed { - return nil, 0, ErrCommitted - } - item, newroot, resolved, err := t.getNode(t.root, compactToHex(path), 0) - if err != nil { - return nil, resolved, err - } - if resolved > 0 { - t.root = newroot - } - if item == nil { - return nil, resolved, nil - } - return item, resolved, nil -} - -func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnode node, resolved int, err error) { - // If non-existent path requested, abort - if origNode == nil { - return nil, nil, 0, nil - } - // If we reached the requested path, return the current node - if pos >= len(path) { - // Although we most probably have the original node expanded, encoding - // that into consensus form can be nasty (needs to cascade down) and - // time consuming. Instead, just pull the hash up from disk directly. - var hash hashNode - if node, ok := origNode.(hashNode); ok { - hash = node - } else { - hash, _ = origNode.cache() - } - if hash == nil { - return nil, origNode, 0, errors.New("non-consensus node") - } - blob, err := t.reader.node(path, common.BytesToHash(hash)) - return blob, origNode, 1, err - } - // Path still needs to be traversed, descend into children - switch n := (origNode).(type) { - case valueNode: - // Path prematurely ended, abort - return nil, nil, 0, nil - - case *shortNode: - if len(path)-pos < len(n.Key) || !bytes.Equal(n.Key, path[pos:pos+len(n.Key)]) { - // Path branches off from short node - return nil, n, 0, nil - } - item, newnode, resolved, err = t.getNode(n.Val, path, pos+len(n.Key)) - if err == nil && resolved > 0 { - n = n.copy() - n.Val = newnode - } - return item, n, resolved, err - - case *fullNode: - item, newnode, resolved, err = t.getNode(n.Children[path[pos]], path, pos+1) - if err == nil && resolved > 0 { - n = n.copy() - n.Children[path[pos]] = newnode - } - return item, n, resolved, err - - case hashNode: - child, err := t.resolveAndTrack(n, path[:pos]) - if err != nil { - return nil, n, 1, err - } - item, newnode, resolved, err := t.getNode(child, path, pos) - return item, newnode, resolved + 1, err - - default: - panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode)) - } -} - -// MustUpdate is a wrapper of Update and will omit any encountered error but -// just print out an error message. -func (t *Trie) MustUpdate(key, value []byte) { - if err := t.Update(key, value); err != nil { - log.Error("Unhandled trie error in Trie.Update", "err", err) - } -} - -// Update associates key with value in the trie. Subsequent calls to -// Get will return value. If value has length zero, any existing value -// is deleted from the trie and calls to Get will return nil. -// -// The value bytes must not be modified by the caller while they are -// stored in the trie. -// -// If the requested node is not present in trie, no error will be returned. -// If the trie is corrupted, a MissingNodeError is returned. -func (t *Trie) Update(key, value []byte) error { - // Short circuit if the trie is already committed and not usable. - if t.committed { - return ErrCommitted - } - return t.update(key, value) -} - -func (t *Trie) update(key, value []byte) error { - t.unhashed++ - k := keybytesToHex(key) - if len(value) != 0 { - _, n, err := t.insert(t.root, nil, k, valueNode(value)) - if err != nil { - return err - } - t.root = n - } else { - _, n, err := t.delete(t.root, nil, k) - if err != nil { - return err - } - t.root = n - } - return nil -} - -func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error) { - if len(key) == 0 { - if v, ok := n.(valueNode); ok { - return !bytes.Equal(v, value.(valueNode)), value, nil - } - return true, value, nil - } - switch n := n.(type) { - case *shortNode: - matchlen := prefixLen(key, n.Key) - // If the whole key matches, keep this short node as is - // and only update the value. - if matchlen == len(n.Key) { - dirty, nn, err := t.insert(n.Val, append(prefix, key[:matchlen]...), key[matchlen:], value) - if !dirty || err != nil { - return false, n, err - } - return true, &shortNode{n.Key, nn, t.newFlag()}, nil - } - // Otherwise branch out at the index where they differ. - branch := &fullNode{flags: t.newFlag()} - var err error - _, branch.Children[n.Key[matchlen]], err = t.insert(nil, append(prefix, n.Key[:matchlen+1]...), n.Key[matchlen+1:], n.Val) - if err != nil { - return false, nil, err - } - _, branch.Children[key[matchlen]], err = t.insert(nil, append(prefix, key[:matchlen+1]...), key[matchlen+1:], value) - if err != nil { - return false, nil, err - } - // Replace this shortNode with the branch if it occurs at index 0. - if matchlen == 0 { - return true, branch, nil - } - // New branch node is created as a child of the original short node. - // Track the newly inserted node in the tracer. The node identifier - // passed is the path from the root node. - t.tracer.onInsert(append(prefix, key[:matchlen]...)) - - // Replace it with a short node leading up to the branch. - return true, &shortNode{key[:matchlen], branch, t.newFlag()}, nil - - case *fullNode: - dirty, nn, err := t.insert(n.Children[key[0]], append(prefix, key[0]), key[1:], value) - if !dirty || err != nil { - return false, n, err - } - n = n.copy() - n.flags = t.newFlag() - n.Children[key[0]] = nn - return true, n, nil - - case nil: - // New short node is created and track it in the tracer. The node identifier - // passed is the path from the root node. Note the valueNode won't be tracked - // since it's always embedded in its parent. - t.tracer.onInsert(prefix) - - return true, &shortNode{key, value, t.newFlag()}, nil - - case hashNode: - // We've hit a part of the trie that isn't loaded yet. Load - // the node and insert into it. This leaves all child nodes on - // the path to the value in the trie. - rn, err := t.resolveAndTrack(n, prefix) - if err != nil { - return false, nil, err - } - dirty, nn, err := t.insert(rn, prefix, key, value) - if !dirty || err != nil { - return false, rn, err - } - return true, nn, nil - - default: - panic(fmt.Sprintf("%T: invalid node: %v", n, n)) - } -} - -// MustDelete is a wrapper of Delete and will omit any encountered error but -// just print out an error message. -func (t *Trie) MustDelete(key []byte) { - if err := t.Delete(key); err != nil { - log.Error("Unhandled trie error in Trie.Delete", "err", err) - } -} - -// Delete removes any existing value for key from the trie. -// -// If the requested node is not present in trie, no error will be returned. -// If the trie is corrupted, a MissingNodeError is returned. -func (t *Trie) Delete(key []byte) error { - // Short circuit if the trie is already committed and not usable. - if t.committed { - return ErrCommitted - } - t.unhashed++ - k := keybytesToHex(key) - _, n, err := t.delete(t.root, nil, k) - if err != nil { - return err - } - t.root = n - return nil -} - -// delete returns the new root of the trie with key deleted. -// It reduces the trie to minimal form by simplifying -// nodes on the way up after deleting recursively. -func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { - switch n := n.(type) { - case *shortNode: - matchlen := prefixLen(key, n.Key) - if matchlen < len(n.Key) { - return false, n, nil // don't replace n on mismatch - } - if matchlen == len(key) { - // The matched short node is deleted entirely and track - // it in the deletion set. The same the valueNode doesn't - // need to be tracked at all since it's always embedded. - t.tracer.onDelete(prefix) - - return true, nil, nil // remove n entirely for whole matches - } - // The key is longer than n.Key. Remove the remaining suffix - // from the subtrie. Child can never be nil here since the - // subtrie must contain at least two other values with keys - // longer than n.Key. - dirty, child, err := t.delete(n.Val, append(prefix, key[:len(n.Key)]...), key[len(n.Key):]) - if !dirty || err != nil { - return false, n, err - } - switch child := child.(type) { - case *shortNode: - // The child shortNode is merged into its parent, track - // is deleted as well. - t.tracer.onDelete(append(prefix, n.Key...)) - - // Deleting from the subtrie reduced it to another - // short node. Merge the nodes to avoid creating a - // shortNode{..., shortNode{...}}. Use concat (which - // always creates a new slice) instead of append to - // avoid modifying n.Key since it might be shared with - // other nodes. - return true, &shortNode{concat(n.Key, child.Key...), child.Val, t.newFlag()}, nil - default: - return true, &shortNode{n.Key, child, t.newFlag()}, nil - } - - case *fullNode: - dirty, nn, err := t.delete(n.Children[key[0]], append(prefix, key[0]), key[1:]) - if !dirty || err != nil { - return false, n, err - } - n = n.copy() - n.flags = t.newFlag() - n.Children[key[0]] = nn - - // Because n is a full node, it must've contained at least two children - // before the delete operation. If the new child value is non-nil, n still - // has at least two children after the deletion, and cannot be reduced to - // a short node. - if nn != nil { - return true, n, nil - } - // Reduction: - // Check how many non-nil entries are left after deleting and - // reduce the full node to a short node if only one entry is - // left. Since n must've contained at least two children - // before deletion (otherwise it would not be a full node) n - // can never be reduced to nil. - // - // When the loop is done, pos contains the index of the single - // value that is left in n or -2 if n contains at least two - // values. - pos := -1 - for i, cld := range &n.Children { - if cld != nil { - if pos == -1 { - pos = i - } else { - pos = -2 - break - } - } - } - if pos >= 0 { - if pos != 16 { - // If the remaining entry is a short node, it replaces - // n and its key gets the missing nibble tacked to the - // front. This avoids creating an invalid - // shortNode{..., shortNode{...}}. Since the entry - // might not be loaded yet, resolve it just for this - // check. - cnode, err := t.resolve(n.Children[pos], append(prefix, byte(pos))) - if err != nil { - return false, nil, err - } - if cnode, ok := cnode.(*shortNode); ok { - // Replace the entire full node with the short node. - // Mark the original short node as deleted since the - // value is embedded into the parent now. - t.tracer.onDelete(append(prefix, byte(pos))) - - k := append([]byte{byte(pos)}, cnode.Key...) - return true, &shortNode{k, cnode.Val, t.newFlag()}, nil - } - } - // Otherwise, n is replaced by a one-nibble short node - // containing the child. - return true, &shortNode{[]byte{byte(pos)}, n.Children[pos], t.newFlag()}, nil - } - // n still contains at least two values and cannot be reduced. - return true, n, nil - - case valueNode: - return true, nil, nil - - case nil: - return false, nil, nil - - case hashNode: - // We've hit a part of the trie that isn't loaded yet. Load - // the node and delete from it. This leaves all child nodes on - // the path to the value in the trie. - rn, err := t.resolveAndTrack(n, prefix) - if err != nil { - return false, nil, err - } - dirty, nn, err := t.delete(rn, prefix, key) - if !dirty || err != nil { - return false, rn, err - } - return true, nn, nil - - default: - panic(fmt.Sprintf("%T: invalid node: %v (%v)", n, n, key)) - } -} - -func concat(s1 []byte, s2 ...byte) []byte { - r := make([]byte, len(s1)+len(s2)) - copy(r, s1) - copy(r[len(s1):], s2) - return r -} - -func (t *Trie) resolve(n node, prefix []byte) (node, error) { - if n, ok := n.(hashNode); ok { - return t.resolveAndTrack(n, prefix) - } - return n, nil -} - -// resolveAndTrack loads node from the underlying store with the given node hash -// and path prefix and also tracks the loaded node blob in tracer treated as the -// node's original value. The rlp-encoded blob is preferred to be loaded from -// database because it's easy to decode node while complex to encode node to blob. -func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { - blob, err := t.reader.node(prefix, common.BytesToHash(n)) - if err != nil { - return nil, err - } - t.tracer.onRead(prefix, blob) - return mustDecodeNode(n, blob), nil -} - -// Hash returns the root hash of the trie. It does not write to the -// database and can be used even if the trie doesn't have one. -func (t *Trie) Hash() common.Hash { - hash, cached := t.hashRoot() - t.root = cached - return common.BytesToHash(hash.(hashNode)) -} - -// Commit collects all dirty nodes in the trie and replaces them with the -// corresponding node hash. All collected nodes (including dirty leaves if -// collectLeaf is true) will be encapsulated into a nodeset for return. -// The returned nodeset can be nil if the trie is clean (nothing to commit). -// Once the trie is committed, it's not usable anymore. A new trie must -// be created with new root and updated trie database for following usage -func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { - defer t.tracer.reset() - defer func() { - t.committed = true - }() - // Trie is empty and can be classified into two types of situations: - // (a) The trie was empty and no update happens => return nil - // (b) The trie was non-empty and all nodes are dropped => return - // the node set includes all deleted nodes - if t.root == nil { - paths := t.tracer.deletedNodes() - if len(paths) == 0 { - return types.EmptyRootHash, nil, nil // case (a) - } - nodes := trienode.NewNodeSet(t.owner) - for _, path := range paths { - nodes.AddNode([]byte(path), trienode.NewDeleted()) - } - return types.EmptyRootHash, nodes, nil // case (b) - } - // Derive the hash for all dirty nodes first. We hold the assumption - // in the following procedure that all nodes are hashed. - rootHash := t.Hash() - - // Do a quick check if we really need to commit. This can happen e.g. - // if we load a trie for reading storage values, but don't write to it. - if hashedNode, dirty := t.root.cache(); !dirty { - // Replace the root node with the origin hash in order to - // ensure all resolved nodes are dropped after the commit. - t.root = hashedNode - return rootHash, nil, nil - } - nodes := trienode.NewNodeSet(t.owner) - for _, path := range t.tracer.deletedNodes() { - nodes.AddNode([]byte(path), trienode.NewDeleted()) - } - t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root) - return rootHash, nodes, nil -} - -// hashRoot calculates the root hash of the given trie -func (t *Trie) hashRoot() (node, node) { - if t.root == nil { - return hashNode(types.EmptyRootHash.Bytes()), nil - } - // If the number of changes is below 100, we let one thread handle it - h := newHasher(t.unhashed >= 100) - defer func() { - returnHasherToPool(h) - t.unhashed = 0 - }() - hashed, cached := h.hash(t.root, true) - return hashed, cached -} - -// Reset drops the referenced root node and cleans all internal state. -func (t *Trie) Reset() { - t.root = nil - t.owner = common.Hash{} - t.unhashed = 0 - t.tracer.reset() - t.committed = false -} diff --git a/trie/trie_id.go b/trie/trie_id.go deleted file mode 100644 index b3ba417dcc..0000000000 --- a/trie/trie_id.go +++ /dev/null @@ -1,65 +0,0 @@ -// (c) 2023, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import "github.com/ethereum/go-ethereum/common" - -// ID is the identifier for uniquely identifying a trie. -type ID struct { - StateRoot common.Hash // The root of the corresponding state(block.root) - Owner common.Hash // The contract address hash which the trie belongs to - Root common.Hash // The root hash of trie -} - -// StateTrieID constructs an identifier for state trie with the provided state root. -func StateTrieID(root common.Hash) *ID { - return &ID{ - StateRoot: root, - Owner: common.Hash{}, - Root: root, - } -} - -// StorageTrieID constructs an identifier for storage trie which belongs to a certain -// state and contract specified by the stateRoot and owner. -func StorageTrieID(stateRoot common.Hash, owner common.Hash, root common.Hash) *ID { - return &ID{ - StateRoot: stateRoot, - Owner: owner, - Root: root, - } -} - -// TrieID constructs an identifier for a standard trie(not a second-layer trie) -// with provided root. It's mostly used in tests and some other tries like CHT trie. -func TrieID(root common.Hash) *ID { - return &ID{ - StateRoot: root, - Owner: common.Hash{}, - Root: root, - } -} diff --git a/trie/trie_reader.go b/trie/trie_reader.go deleted file mode 100644 index 74c5c2a25c..0000000000 --- a/trie/trie_reader.go +++ /dev/null @@ -1,104 +0,0 @@ -// (c) 2023, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ava-labs/subnet-evm/triedb/database" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" -) - -// trieReader is a wrapper of the underlying node reader. It's not safe -// for concurrent usage. -type trieReader struct { - owner common.Hash - reader database.Reader - banned map[string]struct{} // Marker to prevent node from being accessed, for tests -} - -// newTrieReader initializes the trie reader with the given node reader. -func newTrieReader(stateRoot, owner common.Hash, db database.Database) (*trieReader, error) { - if stateRoot == (common.Hash{}) || stateRoot == types.EmptyRootHash { - if stateRoot == (common.Hash{}) { - log.Error("Zero state root hash!") - } - return &trieReader{owner: owner}, nil - } - reader, err := db.Reader(stateRoot) - if err != nil { - return nil, &MissingNodeError{Owner: owner, NodeHash: stateRoot, err: err} - } - return &trieReader{owner: owner, reader: reader}, nil -} - -// newEmptyReader initializes the pure in-memory reader. All read operations -// should be forbidden and returns the MissingNodeError. -func newEmptyReader() *trieReader { - return &trieReader{} -} - -// node retrieves the rlp-encoded trie node with the provided trie node -// information. An MissingNodeError will be returned in case the node is -// not found or any error is encountered. -func (r *trieReader) node(path []byte, hash common.Hash) ([]byte, error) { - // Perform the logics in tests for preventing trie node access. - if r.banned != nil { - if _, ok := r.banned[string(path)]; ok { - return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} - } - } - if r.reader == nil { - return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path} - } - blob, err := r.reader.Node(r.owner, path, hash) - if err != nil || len(blob) == 0 { - return nil, &MissingNodeError{Owner: r.owner, NodeHash: hash, Path: path, err: err} - } - return blob, nil -} - -// MerkleLoader implements triestate.TrieLoader for constructing tries. -type MerkleLoader struct { - db database.Database -} - -// NewMerkleLoader creates the merkle trie loader. -func NewMerkleLoader(db database.Database) *MerkleLoader { - return &MerkleLoader{db: db} -} - -// OpenTrie opens the main account trie. -func (l *MerkleLoader) OpenTrie(root common.Hash) (triestate.Trie, error) { - return New(TrieID(root), l.db) -} - -// OpenStorageTrie opens the storage trie of an account. -func (l *MerkleLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) { - return New(StorageTrieID(stateRoot, addrHash, root), l.db) -} diff --git a/trie/trie_test.go b/trie/trie_test.go deleted file mode 100644 index edcf805525..0000000000 --- a/trie/trie_test.go +++ /dev/null @@ -1,1224 +0,0 @@ -// (c) 2020-2021, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2014 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "hash" - "io" - "math/rand" - "reflect" - "sort" - "testing" - "testing/quick" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/davecgh/go-spew/spew" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/rlp" - "github.com/holiman/uint256" - "github.com/stretchr/testify/require" - "golang.org/x/crypto/sha3" -) - -func init() { - spew.Config.Indent = " " - spew.Config.DisableMethods = false -} - -func TestEmptyTrie(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - res := trie.Hash() - exp := types.EmptyRootHash - if res != exp { - t.Errorf("expected %x got %x", exp, res) - } -} - -func TestNull(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - key := make([]byte, 32) - value := []byte("test") - trie.MustUpdate(key, value) - if !bytes.Equal(trie.MustGet(key), value) { - t.Fatal("wrong value") - } -} - -func TestMissingRoot(t *testing.T) { - testMissingRoot(t, rawdb.HashScheme) - testMissingRoot(t, rawdb.PathScheme) -} - -func testMissingRoot(t *testing.T, scheme string) { - root := common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") - trie, err := New(TrieID(root), newTestDatabase(rawdb.NewMemoryDatabase(), scheme)) - if trie != nil { - t.Error("New returned non-nil trie for invalid root") - } - if _, ok := err.(*MissingNodeError); !ok { - t.Errorf("New returned wrong error: %v", err) - } -} - -func TestMissingNode(t *testing.T) { - testMissingNode(t, false, rawdb.HashScheme) - testMissingNode(t, false, rawdb.PathScheme) - testMissingNode(t, true, rawdb.HashScheme) - testMissingNode(t, true, rawdb.PathScheme) -} - -func testMissingNode(t *testing.T, memonly bool, scheme string) { - diskdb := rawdb.NewMemoryDatabase() - triedb := newTestDatabase(diskdb, scheme) - - trie := NewEmpty(triedb) - updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") - updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") - root, nodes, _ := trie.Commit(false) - triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - - if !memonly { - require.NoError(t, triedb.Commit(root)) - } - - trie, _ = New(TrieID(root), triedb) - _, err := trie.Get([]byte("120000")) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - trie, _ = New(TrieID(root), triedb) - _, err = trie.Get([]byte("120099")) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - trie, _ = New(TrieID(root), triedb) - _, err = trie.Get([]byte("123456")) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - trie, _ = New(TrieID(root), triedb) - err = trie.Update([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - trie, _ = New(TrieID(root), triedb) - err = trie.Delete([]byte("123456")) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - - var ( - path []byte - hash = common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9") - ) - for p, n := range nodes.Nodes { - if n.Hash == hash { - path = common.CopyBytes([]byte(p)) - break - } - } - trie, _ = New(TrieID(root), triedb) - if memonly { - trie.reader.banned = map[string]struct{}{string(path): {}} - } else { - rawdb.DeleteTrieNode(diskdb, common.Hash{}, path, hash, scheme) - } - - _, err = trie.Get([]byte("120000")) - if _, ok := err.(*MissingNodeError); !ok { - t.Errorf("Wrong error: %v", err) - } - _, err = trie.Get([]byte("120099")) - if _, ok := err.(*MissingNodeError); !ok { - t.Errorf("Wrong error: %v", err) - } - _, err = trie.Get([]byte("123456")) - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - err = trie.Update([]byte("120099"), []byte("zxcv")) - if _, ok := err.(*MissingNodeError); !ok { - t.Errorf("Wrong error: %v", err) - } - err = trie.Delete([]byte("123456")) - if _, ok := err.(*MissingNodeError); !ok { - t.Errorf("Wrong error: %v", err) - } -} - -func TestInsert(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - - updateString(trie, "doe", "reindeer") - updateString(trie, "dog", "puppy") - updateString(trie, "dogglesworth", "cat") - - exp := common.HexToHash("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3") - root := trie.Hash() - if root != exp { - t.Errorf("case 1: exp %x got %x", exp, root) - } - - trie = NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") - - exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") - root, _, _ = trie.Commit(false) - if root != exp { - t.Errorf("case 2: exp %x got %x", exp, root) - } -} - -func TestGet(t *testing.T) { - db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie := NewEmpty(db) - updateString(trie, "doe", "reindeer") - updateString(trie, "dog", "puppy") - updateString(trie, "dogglesworth", "cat") - - for i := 0; i < 2; i++ { - res := getString(trie, "dog") - if !bytes.Equal(res, []byte("puppy")) { - t.Errorf("expected puppy got %x", res) - } - unknown := getString(trie, "unknown") - if unknown != nil { - t.Errorf("expected nil got %x", unknown) - } - if i == 1 { - return - } - root, nodes, _ := trie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - trie, _ = New(TrieID(root), db) - } -} - -func TestDelete(t *testing.T) { - db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie := NewEmpty(db) - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"ether", ""}, - {"dog", "puppy"}, - {"shaman", ""}, - } - for _, val := range vals { - if val.v != "" { - updateString(trie, val.k, val.v) - } else { - deleteString(trie, val.k) - } - } - - hash := trie.Hash() - exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") - if hash != exp { - t.Errorf("expected %x got %x", exp, hash) - } -} - -func TestEmptyValues(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"ether", ""}, - {"dog", "puppy"}, - {"shaman", ""}, - } - for _, val := range vals { - updateString(trie, val.k, val.v) - } - - hash := trie.Hash() - exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") - if hash != exp { - t.Errorf("expected %x got %x", exp, hash) - } -} - -func TestReplication(t *testing.T) { - db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie := NewEmpty(db) - vals := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - {"shaman", "horse"}, - {"doge", "coin"}, - {"dog", "puppy"}, - {"somethingveryoddindeedthis is", "myothernodedata"}, - } - for _, val := range vals { - updateString(trie, val.k, val.v) - } - root, nodes, _ := trie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - - // create a new trie on top of the database and check that lookups work. - trie2, err := New(TrieID(root), db) - if err != nil { - t.Fatalf("can't recreate trie at %x: %v", root, err) - } - for _, kv := range vals { - if string(getString(trie2, kv.k)) != kv.v { - t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) - } - } - hash, nodes, _ := trie2.Commit(false) - if hash != root { - t.Errorf("root failure. expected %x got %x", root, hash) - } - - // recreate the trie after commit - if nodes != nil { - db.Update(hash, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - } - trie2, err = New(TrieID(hash), db) - if err != nil { - t.Fatalf("can't recreate trie at %x: %v", hash, err) - } - // perform some insertions on the new trie. - vals2 := []struct{ k, v string }{ - {"do", "verb"}, - {"ether", "wookiedoo"}, - {"horse", "stallion"}, - // {"shaman", "horse"}, - // {"doge", "coin"}, - // {"ether", ""}, - // {"dog", "puppy"}, - // {"somethingveryoddindeedthis is", "myothernodedata"}, - // {"shaman", ""}, - } - for _, val := range vals2 { - updateString(trie2, val.k, val.v) - } - if trie2.Hash() != hash { - t.Errorf("root failure. expected %x got %x", hash, hash) - } -} - -func TestLargeValue(t *testing.T) { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - trie.MustUpdate([]byte("key1"), []byte{99, 99, 99, 99}) - trie.MustUpdate([]byte("key2"), bytes.Repeat([]byte{1}, 32)) - trie.Hash() -} - -// TestRandomCases tests some cases that were found via random fuzzing -func TestRandomCases(t *testing.T) { - var rt = []randTestStep{ - {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 0 - {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 1 - {op: 0, key: common.Hex2Bytes("d51b182b95d677e5f1c82508c0228de96b73092d78ce78b2230cd948674f66fd1483bd"), value: common.Hex2Bytes("0000000000000002")}, // step 2 - {op: 2, key: common.Hex2Bytes("c2a38512b83107d665c65235b0250002882ac2022eb00711552354832c5f1d030d0e408e"), value: common.Hex2Bytes("")}, // step 3 - {op: 3, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 4 - {op: 3, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 5 - {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 6 - {op: 3, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 7 - {op: 0, key: common.Hex2Bytes("c2a38512b83107d665c65235b0250002882ac2022eb00711552354832c5f1d030d0e408e"), value: common.Hex2Bytes("0000000000000008")}, // step 8 - {op: 0, key: common.Hex2Bytes("d51b182b95d677e5f1c82508c0228de96b73092d78ce78b2230cd948674f66fd1483bd"), value: common.Hex2Bytes("0000000000000009")}, // step 9 - {op: 2, key: common.Hex2Bytes("fd"), value: common.Hex2Bytes("")}, // step 10 - {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 11 - {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 12 - {op: 0, key: common.Hex2Bytes("fd"), value: common.Hex2Bytes("000000000000000d")}, // step 13 - {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 14 - {op: 1, key: common.Hex2Bytes("c2a38512b83107d665c65235b0250002882ac2022eb00711552354832c5f1d030d0e408e"), value: common.Hex2Bytes("")}, // step 15 - {op: 3, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 16 - {op: 0, key: common.Hex2Bytes("c2a38512b83107d665c65235b0250002882ac2022eb00711552354832c5f1d030d0e408e"), value: common.Hex2Bytes("0000000000000011")}, // step 17 - {op: 5, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 18 - {op: 3, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 19 - {op: 0, key: common.Hex2Bytes("d51b182b95d677e5f1c82508c0228de96b73092d78ce78b2230cd948674f66fd1483bd"), value: common.Hex2Bytes("0000000000000014")}, // step 20 - {op: 0, key: common.Hex2Bytes("d51b182b95d677e5f1c82508c0228de96b73092d78ce78b2230cd948674f66fd1483bd"), value: common.Hex2Bytes("0000000000000015")}, // step 21 - {op: 0, key: common.Hex2Bytes("c2a38512b83107d665c65235b0250002882ac2022eb00711552354832c5f1d030d0e408e"), value: common.Hex2Bytes("0000000000000016")}, // step 22 - {op: 5, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 23 - {op: 1, key: common.Hex2Bytes("980c393656413a15c8da01978ed9f89feb80b502f58f2d640e3a2f5f7a99a7018f1b573befd92053ac6f78fca4a87268"), value: common.Hex2Bytes("")}, // step 24 - {op: 1, key: common.Hex2Bytes("fd"), value: common.Hex2Bytes("")}, // step 25 - } - if err := runRandTest(rt); err != nil { - t.Fatal(err) - } -} - -// randTest performs random trie operations. -// Instances of this test are created by Generate. -type randTest []randTestStep - -// compile-time interface check -var _ quick.Generator = (randTest)(nil) - -type randTestStep struct { - op int - key []byte // for opUpdate, opDelete, opGet - value []byte // for opUpdate - err error // for debugging -} - -const ( - opUpdate = iota - opDelete - opGet - opHash - opCommit - opItercheckhash - opNodeDiff - opProve - opMax // boundary value, not an actual op -) - -func (randTest) Generate(r *rand.Rand, size int) reflect.Value { - var finishedFn = func() bool { - size-- - return size == 0 - } - return reflect.ValueOf(generateSteps(finishedFn, r)) -} - -func generateSteps(finished func() bool, r io.Reader) randTest { - var allKeys [][]byte - var one = []byte{0} - genKey := func() []byte { - r.Read(one) - if len(allKeys) < 2 || one[0]%100 > 90 { - // new key - size := one[0] % 50 - key := make([]byte, size) - r.Read(key) - allKeys = append(allKeys, key) - return key - } - // use existing key - idx := int(one[0]) % len(allKeys) - return allKeys[idx] - } - var steps randTest - for !finished() { - r.Read(one) - step := randTestStep{op: int(one[0]) % opMax} - switch step.op { - case opUpdate: - step.key = genKey() - step.value = make([]byte, 8) - binary.BigEndian.PutUint64(step.value, uint64(len(steps))) - case opGet, opDelete, opProve: - step.key = genKey() - } - steps = append(steps, step) - } - return steps -} - -func verifyAccessList(old *Trie, new *Trie, set *trienode.NodeSet) error { - deletes, inserts, updates := diffTries(old, new) - - // Check insertion set - for path := range inserts { - n, ok := set.Nodes[path] - if !ok || n.IsDeleted() { - return errors.New("expect new node") - } - //if len(n.Prev) > 0 { - // return errors.New("unexpected origin value") - //} - } - // Check deletion set - for path := range deletes { - n, ok := set.Nodes[path] - if !ok || !n.IsDeleted() { - return errors.New("expect deleted node") - } - //if len(n.Prev) == 0 { - // return errors.New("expect origin value") - //} - //if !bytes.Equal(n.Prev, blob) { - // return errors.New("invalid origin value") - //} - } - // Check update set - for path := range updates { - n, ok := set.Nodes[path] - if !ok || n.IsDeleted() { - return errors.New("expect updated node") - } - //if len(n.Prev) == 0 { - // return errors.New("expect origin value") - //} - //if !bytes.Equal(n.Prev, blob) { - // return errors.New("invalid origin value") - //} - } - return nil -} - -// runRandTestBool coerces error to boolean, for use in quick.Check -func runRandTestBool(rt randTest) bool { - return runRandTest(rt) == nil -} - -func runRandTest(rt randTest) error { - var scheme = rawdb.HashScheme - if rand.Intn(2) == 0 { - scheme = rawdb.PathScheme - } - var ( - origin = types.EmptyRootHash - triedb = newTestDatabase(rawdb.NewMemoryDatabase(), scheme) - tr = NewEmpty(triedb) - values = make(map[string]string) // tracks content of the trie - origTrie = NewEmpty(triedb) - ) - for i, step := range rt { - // fmt.Printf("{op: %d, key: common.Hex2Bytes(\"%x\"), value: common.Hex2Bytes(\"%x\")}, // step %d\n", - // step.op, step.key, step.value, i) - switch step.op { - case opUpdate: - tr.MustUpdate(step.key, step.value) - values[string(step.key)] = string(step.value) - case opDelete: - tr.MustDelete(step.key) - delete(values, string(step.key)) - case opGet: - v := tr.MustGet(step.key) - want := values[string(step.key)] - if string(v) != want { - rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) - } - case opProve: - hash := tr.Hash() - if hash == types.EmptyRootHash { - continue - } - proofDb := rawdb.NewMemoryDatabase() - err := tr.Prove(step.key, proofDb) - if err != nil { - rt[i].err = fmt.Errorf("failed for proving key %#x, %v", step.key, err) - } - _, err = VerifyProof(hash, step.key, proofDb) - if err != nil { - rt[i].err = fmt.Errorf("failed for verifying key %#x, %v", step.key, err) - } - case opHash: - tr.Hash() - case opCommit: - root, nodes, _ := tr.Commit(true) - if nodes != nil { - triedb.Update(root, origin, trienode.NewWithNodeSet(nodes)) - } - newtr, err := New(TrieID(root), triedb) - if err != nil { - rt[i].err = err - return err - } - if nodes != nil { - if err := verifyAccessList(origTrie, newtr, nodes); err != nil { - rt[i].err = err - return err - } - } - tr = newtr - origTrie = tr.Copy() - origin = root - case opItercheckhash: - checktr := NewEmpty(triedb) - it := NewIterator(tr.MustNodeIterator(nil)) - for it.Next() { - checktr.MustUpdate(it.Key, it.Value) - } - if tr.Hash() != checktr.Hash() { - rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") - } - case opNodeDiff: - var ( - origIter = origTrie.MustNodeIterator(nil) - curIter = tr.MustNodeIterator(nil) - origSeen = make(map[string]struct{}) - curSeen = make(map[string]struct{}) - ) - for origIter.Next(true) { - if origIter.Leaf() { - continue - } - origSeen[string(origIter.Path())] = struct{}{} - } - for curIter.Next(true) { - if curIter.Leaf() { - continue - } - curSeen[string(curIter.Path())] = struct{}{} - } - var ( - insertExp = make(map[string]struct{}) - deleteExp = make(map[string]struct{}) - ) - for path := range curSeen { - _, present := origSeen[path] - if !present { - insertExp[path] = struct{}{} - } - } - for path := range origSeen { - _, present := curSeen[path] - if !present { - deleteExp[path] = struct{}{} - } - } - if len(insertExp) != len(tr.tracer.inserts) { - rt[i].err = fmt.Errorf("insert set mismatch") - } - if len(deleteExp) != len(tr.tracer.deletes) { - rt[i].err = fmt.Errorf("delete set mismatch") - } - for insert := range tr.tracer.inserts { - if _, present := insertExp[insert]; !present { - rt[i].err = fmt.Errorf("missing inserted node") - } - } - for del := range tr.tracer.deletes { - if _, present := deleteExp[del]; !present { - rt[i].err = fmt.Errorf("missing deleted node") - } - } - } - // Abort the test on error. - if rt[i].err != nil { - return rt[i].err - } - } - return nil -} - -func TestRandom(t *testing.T) { - if err := quick.Check(runRandTestBool, nil); err != nil { - if cerr, ok := err.(*quick.CheckError); ok { - t.Fatalf("random test iteration %d failed: %s", cerr.Count, spew.Sdump(cerr.In)) - } - t.Fatal(err) - } -} - -func BenchmarkGet(b *testing.B) { benchGet(b) } -func BenchmarkUpdateBE(b *testing.B) { benchUpdate(b, binary.BigEndian) } -func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) } - -const benchElemCount = 20000 - -func benchGet(b *testing.B) { - triedb := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - trie := NewEmpty(triedb) - k := make([]byte, 32) - for i := 0; i < benchElemCount; i++ { - binary.LittleEndian.PutUint64(k, uint64(i)) - v := make([]byte, 32) - binary.LittleEndian.PutUint64(v, uint64(i)) - trie.MustUpdate(k, v) - } - binary.LittleEndian.PutUint64(k, benchElemCount/2) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - trie.MustGet(k) - } - b.StopTimer() -} - -func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - k := make([]byte, 32) - b.ReportAllocs() - for i := 0; i < b.N; i++ { - v := make([]byte, 32) - e.PutUint64(k, uint64(i)) - e.PutUint64(v, uint64(i)) - trie.MustUpdate(k, v) - } - return trie -} - -// Benchmarks the trie hashing. Since the trie caches the result of any operation, -// we cannot use b.N as the number of hashing rounds, since all rounds apart from -// the first one will be NOOP. As such, we'll use b.N as the number of account to -// insert into the trie before measuring the hashing. -// BenchmarkHash-6 288680 4561 ns/op 682 B/op 9 allocs/op -// BenchmarkHash-6 275095 4800 ns/op 685 B/op 9 allocs/op -// pure hasher: -// BenchmarkHash-6 319362 4230 ns/op 675 B/op 9 allocs/op -// BenchmarkHash-6 257460 4674 ns/op 689 B/op 9 allocs/op -// With hashing in-between and pure hasher: -// BenchmarkHash-6 225417 7150 ns/op 982 B/op 12 allocs/op -// BenchmarkHash-6 220378 6197 ns/op 983 B/op 12 allocs/op -// same with old hasher -// BenchmarkHash-6 229758 6437 ns/op 981 B/op 12 allocs/op -// BenchmarkHash-6 212610 7137 ns/op 986 B/op 12 allocs/op -func BenchmarkHash(b *testing.B) { - // Create a realistic account trie to hash. We're first adding and hashing N - // entries, then adding N more. - addresses, accounts := makeAccounts(2 * b.N) - // Insert the accounts into the trie and hash it - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - i := 0 - for ; i < len(addresses)/2; i++ { - trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) - } - trie.Hash() - for ; i < len(addresses); i++ { - trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) - } - b.ResetTimer() - b.ReportAllocs() - //trie.hashRoot(nil, nil) - trie.Hash() -} - -// Benchmarks the trie Commit following a Hash. Since the trie caches the result of any operation, -// we cannot use b.N as the number of hashing rounds, since all rounds apart from -// the first one will be NOOP. As such, we'll use b.N as the number of account to -// insert into the trie before measuring the hashing. -func BenchmarkCommitAfterHash(b *testing.B) { - b.Run("no-onleaf", func(b *testing.B) { - benchmarkCommitAfterHash(b, false) - }) - b.Run("with-onleaf", func(b *testing.B) { - benchmarkCommitAfterHash(b, true) - }) -} - -func benchmarkCommitAfterHash(b *testing.B, collectLeaf bool) { - // Make the random benchmark deterministic - addresses, accounts := makeAccounts(b.N) - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - for i := 0; i < len(addresses); i++ { - trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) - } - // Insert the accounts into the trie and hash it - trie.Hash() - b.ResetTimer() - b.ReportAllocs() - trie.Commit(collectLeaf) -} - -func TestTinyTrie(t *testing.T) { - // Create a realistic account trie to hash - _, accounts := makeAccounts(5) - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001337"), accounts[3]) - if exp, root := common.HexToHash("8c6a85a4d9fda98feff88450299e574e5378e32391f75a055d470ac0653f1005"), trie.Hash(); exp != root { - t.Errorf("1: got %x, exp %x", root, exp) - } - trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001338"), accounts[4]) - if exp, root := common.HexToHash("ec63b967e98a5720e7f720482151963982890d82c9093c0d486b7eb8883a66b1"), trie.Hash(); exp != root { - t.Errorf("2: got %x, exp %x", root, exp) - } - trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001339"), accounts[4]) - if exp, root := common.HexToHash("0608c1d1dc3905fa22204c7a0e43644831c3b6d3def0f274be623a948197e64a"), trie.Hash(); exp != root { - t.Errorf("3: got %x, exp %x", root, exp) - } - checktr := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - it := NewIterator(trie.MustNodeIterator(nil)) - for it.Next() { - checktr.MustUpdate(it.Key, it.Value) - } - if troot, itroot := trie.Hash(), checktr.Hash(); troot != itroot { - t.Fatalf("hash mismatch in opItercheckhash, trie: %x, check: %x", troot, itroot) - } -} - -func TestCommitAfterHash(t *testing.T) { - // Create a realistic account trie to hash - addresses, accounts := makeAccounts(1000) - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - for i := 0; i < len(addresses); i++ { - trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) - } - // Insert the accounts into the trie and hash it - trie.Hash() - trie.Commit(false) - root := trie.Hash() - exp := common.HexToHash("72f9d3f3fe1e1dd7b8936442e7642aef76371472d94319900790053c493f3fe6") - if exp != root { - t.Errorf("got %x, exp %x", root, exp) - } - root, _, _ = trie.Commit(false) - if exp != root { - t.Errorf("got %x, exp %x", root, exp) - } -} - -func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) { - // Make the random benchmark deterministic - random := rand.New(rand.NewSource(0)) - // Create a realistic account trie to hash - addresses = make([][20]byte, size) - for i := 0; i < len(addresses); i++ { - data := make([]byte, 20) - random.Read(data) - copy(addresses[i][:], data) - } - accounts = make([][]byte, len(addresses)) - for i := 0; i < len(accounts); i++ { - var ( - nonce = uint64(random.Int63()) - root = types.EmptyRootHash - code = crypto.Keccak256(nil) - ) - // The big.Rand function is not deterministic with regards to 64 vs 32 bit systems, - // and will consume different amount of data from the rand source. - //balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil)) - // Therefore, we instead just read via byte buffer - numBytes := random.Uint32() % 33 // [0, 32] bytes - balanceBytes := make([]byte, numBytes) - random.Read(balanceBytes) - balance := new(uint256.Int).SetBytes(balanceBytes) - data, _ := rlp.EncodeToBytes(&types.StateAccount{Nonce: nonce, Balance: balance, Root: root, CodeHash: code}) - accounts[i] = data - } - return addresses, accounts -} - -// spongeDb is a dummy db backend which accumulates writes in a sponge -type spongeDb struct { - sponge hash.Hash - id string - journal []string - keys []string - values map[string]string -} - -func (s *spongeDb) Has(key []byte) (bool, error) { panic("implement me") } -func (s *spongeDb) Get(key []byte) ([]byte, error) { return nil, errors.New("no such elem") } -func (s *spongeDb) Delete(key []byte) error { panic("implement me") } -func (s *spongeDb) NewBatch() ethdb.Batch { return &spongeBatch{s} } -func (s *spongeDb) NewBatchWithSize(size int) ethdb.Batch { return &spongeBatch{s} } -func (s *spongeDb) NewSnapshot() (ethdb.Snapshot, error) { panic("implement me") } -func (s *spongeDb) Stat(property string) (string, error) { panic("implement me") } -func (s *spongeDb) Compact(start []byte, limit []byte) error { panic("implement me") } -func (s *spongeDb) Close() error { return nil } -func (s *spongeDb) Put(key []byte, value []byte) error { - var ( - keybrief = key - valbrief = value - ) - if len(keybrief) > 8 { - keybrief = keybrief[:8] - } - if len(valbrief) > 8 { - valbrief = valbrief[:8] - } - s.journal = append(s.journal, fmt.Sprintf("%v: PUT([%x...], [%d bytes] %x...)\n", s.id, keybrief, len(value), valbrief)) - - if s.values == nil { - s.sponge.Write(key) - s.sponge.Write(value) - } else { - s.keys = append(s.keys, string(key)) - s.values[string(key)] = string(value) - } - return nil -} -func (s *spongeDb) NewIterator(prefix []byte, start []byte) ethdb.Iterator { panic("implement me") } - -func (s *spongeDb) Flush() { - // Bottom-up, the longest path first - sort.Sort(sort.Reverse(sort.StringSlice(s.keys))) - for _, key := range s.keys { - s.sponge.Write([]byte(key)) - s.sponge.Write([]byte(s.values[key])) - } -} - -// spongeBatch is a dummy batch which immediately writes to the underlying spongedb -type spongeBatch struct { - db *spongeDb -} - -func (b *spongeBatch) Put(key, value []byte) error { - b.db.Put(key, value) - return nil -} -func (b *spongeBatch) Delete(key []byte) error { panic("implement me") } -func (b *spongeBatch) ValueSize() int { return 100 } -func (b *spongeBatch) Write() error { return nil } -func (b *spongeBatch) Reset() {} -func (b *spongeBatch) Replay(w ethdb.KeyValueWriter) error { return nil } - -// TestCommitSequence tests that the trie.Commit operation writes the elements of the trie -// in the expected order. -// The test data was based on the 'master' code, and is basically random. It can be used -// to check whether changes to the trie modifies the write order or data in any way. -func TestCommitSequence(t *testing.T) { - for i, tc := range []struct { - count int - expWriteSeqHash []byte - }{ - {20, common.FromHex("330b0afae2853d96b9f015791fbe0fb7f239bf65f335f16dfc04b76c7536276d")}, - {200, common.FromHex("5162b3735c06b5d606b043a3ee8adbdbbb408543f4966bca9dcc63da82684eeb")}, - {2000, common.FromHex("4574cd8e6b17f3fe8ad89140d1d0bf4f1bd7a87a8ac3fb623b33550544c77635")}, - } { - addresses, accounts := makeAccounts(tc.count) - // This spongeDb is used to check the sequence of disk-db-writes - s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} - db := newTestDatabase(rawdb.NewDatabase(s), rawdb.HashScheme) - trie := NewEmpty(db) - // Fill the trie with elements - for i := 0; i < tc.count; i++ { - trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) - } - // Flush trie -> database - root, nodes, _ := trie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - // Flush memdb -> disk (sponge) - db.Commit(root) - if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) { - t.Errorf("test %d, disk write sequence wrong:\ngot %x exp %x\n", i, got, exp) - } - } -} - -// TestCommitSequenceRandomBlobs is identical to TestCommitSequence -// but uses random blobs instead of 'accounts' -func TestCommitSequenceRandomBlobs(t *testing.T) { - for i, tc := range []struct { - count int - expWriteSeqHash []byte - }{ - {20, common.FromHex("8016650c7a50cf88485fd06cde52d634a89711051107f00d21fae98234f2f13d")}, - {200, common.FromHex("dde92ca9812e068e6982d04b40846dc65a61a9fd4996fc0f55f2fde172a8e13c")}, - {2000, common.FromHex("ab553a7f9aff82e3929c382908e30ef7dd17a332933e92ba3fe873fc661ef382")}, - } { - prng := rand.New(rand.NewSource(int64(i))) - // This spongeDb is used to check the sequence of disk-db-writes - s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} - db := newTestDatabase(rawdb.NewDatabase(s), rawdb.HashScheme) - trie := NewEmpty(db) - // Fill the trie with elements - for i := 0; i < tc.count; i++ { - key := make([]byte, 32) - var val []byte - // 50% short elements, 50% large elements - if prng.Intn(2) == 0 { - val = make([]byte, 1+prng.Intn(32)) - } else { - val = make([]byte, 1+prng.Intn(4096)) - } - prng.Read(key) - prng.Read(val) - trie.MustUpdate(key, val) - } - // Flush trie -> database - root, nodes, _ := trie.Commit(false) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - // Flush memdb -> disk (sponge) - db.Commit(root) - if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) { - t.Fatalf("test %d, disk write sequence wrong:\ngot %x exp %x\n", i, got, exp) - } - } -} - -func TestCommitSequenceStackTrie(t *testing.T) { - for count := 1; count < 200; count++ { - prng := rand.New(rand.NewSource(int64(count))) - // This spongeDb is used to check the sequence of disk-db-writes - s := &spongeDb{ - sponge: sha3.NewLegacyKeccak256(), - id: "a", - values: make(map[string]string), - } - db := newTestDatabase(rawdb.NewDatabase(s), rawdb.HashScheme) - trie := NewEmpty(db) - - // Another sponge is used for the stacktrie commits - stackTrieSponge := &spongeDb{ - sponge: sha3.NewLegacyKeccak256(), - id: "b", - values: make(map[string]string), - } - options := NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - rawdb.WriteTrieNode(stackTrieSponge, common.Hash{}, path, hash, blob, db.Scheme()) - }) - stTrie := NewStackTrie(options) - - // Fill the trie with elements - for i := 0; i < count; i++ { - // For the stack trie, we need to do inserts in proper order - key := make([]byte, 32) - binary.BigEndian.PutUint64(key, uint64(i)) - var val []byte - // 50% short elements, 50% large elements - if prng.Intn(2) == 0 { - val = make([]byte, 1+prng.Intn(32)) - } else { - val = make([]byte, 1+prng.Intn(1024)) - } - prng.Read(val) - trie.Update(key, val) - stTrie.Update(key, val) - } - // Flush trie -> database - root, nodes, _ := trie.Commit(false) - // Flush memdb -> disk (sponge) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - db.Commit(root) - s.Flush() - - // And flush stacktrie -> disk - stRoot := stTrie.Commit() - if stRoot != root { - t.Fatalf("root wrong, got %x exp %x", stRoot, root) - } - stackTrieSponge.Flush() - if got, exp := stackTrieSponge.sponge.Sum(nil), s.sponge.Sum(nil); !bytes.Equal(got, exp) { - // Show the journal - t.Logf("Expected:") - for i, v := range s.journal { - t.Logf("op %d: %v", i, v) - } - t.Logf("Stacktrie:") - for i, v := range stackTrieSponge.journal { - t.Logf("op %d: %v", i, v) - } - t.Fatalf("test %d, disk write sequence wrong:\ngot %x exp %x\n", count, got, exp) - } - } -} - -// TestCommitSequenceSmallRoot tests that a trie which is essentially only a -// small (<32 byte) shortnode with an included value is properly committed to a -// database. -// This case might not matter, since in practice, all keys are 32 bytes, which means -// that even a small trie which contains a leaf will have an extension making it -// not fit into 32 bytes, rlp-encoded. However, it's still the correct thing to do. -func TestCommitSequenceSmallRoot(t *testing.T) { - s := &spongeDb{ - sponge: sha3.NewLegacyKeccak256(), - id: "a", - values: make(map[string]string), - } - db := newTestDatabase(rawdb.NewDatabase(s), rawdb.HashScheme) - trie := NewEmpty(db) - - // Another sponge is used for the stacktrie commits - stackTrieSponge := &spongeDb{ - sponge: sha3.NewLegacyKeccak256(), - id: "b", - values: make(map[string]string), - } - options := NewStackTrieOptions() - options = options.WithWriter(func(path []byte, hash common.Hash, blob []byte) { - rawdb.WriteTrieNode(stackTrieSponge, common.Hash{}, path, hash, blob, db.Scheme()) - }) - stTrie := NewStackTrie(options) - - // Add a single small-element to the trie(s) - key := make([]byte, 5) - key[0] = 1 - trie.Update(key, []byte{0x1}) - stTrie.Update(key, []byte{0x1}) - - // Flush trie -> database - root, nodes, _ := trie.Commit(false) - // Flush memdb -> disk (sponge) - db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) - db.Commit(root) - - // And flush stacktrie -> disk - stRoot := stTrie.Commit() - if stRoot != root { - t.Fatalf("root wrong, got %x exp %x", stRoot, root) - } - t.Logf("root: %x\n", stRoot) - - s.Flush() - stackTrieSponge.Flush() - if got, exp := stackTrieSponge.sponge.Sum(nil), s.sponge.Sum(nil); !bytes.Equal(got, exp) { - t.Fatalf("test, disk write sequence wrong:\ngot %x exp %x\n", got, exp) - } -} - -// BenchmarkCommitAfterHashFixedSize benchmarks the Commit (after Hash) of a fixed number of updates to a trie. -// This benchmark is meant to capture the difference on efficiency of small versus large changes. Typically, -// storage tries are small (a couple of entries), whereas the full post-block account trie update is large (a couple -// of thousand entries) -func BenchmarkHashFixedSize(b *testing.B) { - b.Run("10", func(b *testing.B) { - b.StopTimer() - acc, add := makeAccounts(20) - for i := 0; i < b.N; i++ { - benchmarkHashFixedSize(b, acc, add) - } - }) - b.Run("100", func(b *testing.B) { - b.StopTimer() - acc, add := makeAccounts(100) - for i := 0; i < b.N; i++ { - benchmarkHashFixedSize(b, acc, add) - } - }) - - b.Run("1K", func(b *testing.B) { - b.StopTimer() - acc, add := makeAccounts(1000) - for i := 0; i < b.N; i++ { - benchmarkHashFixedSize(b, acc, add) - } - }) - b.Run("10K", func(b *testing.B) { - b.StopTimer() - acc, add := makeAccounts(10000) - for i := 0; i < b.N; i++ { - benchmarkHashFixedSize(b, acc, add) - } - }) - b.Run("100K", func(b *testing.B) { - b.StopTimer() - acc, add := makeAccounts(100000) - for i := 0; i < b.N; i++ { - benchmarkHashFixedSize(b, acc, add) - } - }) -} - -func benchmarkHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { - b.ReportAllocs() - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - for i := 0; i < len(addresses); i++ { - trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) - } - // Insert the accounts into the trie and hash it - b.StartTimer() - trie.Hash() - b.StopTimer() -} - -func BenchmarkCommitAfterHashFixedSize(b *testing.B) { - b.Run("10", func(b *testing.B) { - b.StopTimer() - acc, add := makeAccounts(20) - for i := 0; i < b.N; i++ { - benchmarkCommitAfterHashFixedSize(b, acc, add) - } - }) - b.Run("100", func(b *testing.B) { - b.StopTimer() - acc, add := makeAccounts(100) - for i := 0; i < b.N; i++ { - benchmarkCommitAfterHashFixedSize(b, acc, add) - } - }) - - b.Run("1K", func(b *testing.B) { - b.StopTimer() - acc, add := makeAccounts(1000) - for i := 0; i < b.N; i++ { - benchmarkCommitAfterHashFixedSize(b, acc, add) - } - }) - b.Run("10K", func(b *testing.B) { - b.StopTimer() - acc, add := makeAccounts(10000) - for i := 0; i < b.N; i++ { - benchmarkCommitAfterHashFixedSize(b, acc, add) - } - }) - b.Run("100K", func(b *testing.B) { - b.StopTimer() - acc, add := makeAccounts(100000) - for i := 0; i < b.N; i++ { - benchmarkCommitAfterHashFixedSize(b, acc, add) - } - }) -} - -func benchmarkCommitAfterHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { - b.ReportAllocs() - trie := NewEmpty(newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme)) - for i := 0; i < len(addresses); i++ { - trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) - } - // Insert the accounts into the trie and hash it - trie.Hash() - b.StartTimer() - trie.Commit(false) - b.StopTimer() -} - -func getString(trie *Trie, k string) []byte { - return trie.MustGet([]byte(k)) -} - -func updateString(trie *Trie, k, v string) { - trie.MustUpdate([]byte(k), []byte(v)) -} - -func deleteString(trie *Trie, k string) { - trie.MustDelete([]byte(k)) -} - -func TestDecodeNode(t *testing.T) { - t.Parallel() - - var ( - hash = make([]byte, 20) - elems = make([]byte, 20) - ) - for i := 0; i < 5000000; i++ { - prng.Read(hash) - prng.Read(elems) - decodeNode(hash, elems) - } -} - -func FuzzTrie(f *testing.F) { - f.Fuzz(func(t *testing.T, data []byte) { - var steps = 500 - var input = bytes.NewReader(data) - var finishedFn = func() bool { - steps-- - return steps < 0 || input.Len() == 0 - } - if err := runRandTest(generateSteps(finishedFn, input)); err != nil { - t.Fatal(err) - } - }) -} diff --git a/trie/trienode/node.go b/trie/trienode/node.go deleted file mode 100644 index 95315c2e9a..0000000000 --- a/trie/trienode/node.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2023 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trienode - -import ( - "fmt" - "sort" - "strings" - - "github.com/ethereum/go-ethereum/common" -) - -// Node is a wrapper which contains the encoded blob of the trie node and its -// node hash. It is general enough that can be used to represent trie node -// corresponding to different trie implementations. -type Node struct { - Hash common.Hash // Node hash, empty for deleted node - Blob []byte // Encoded node blob, nil for the deleted node -} - -// Size returns the total memory size used by this node. -func (n *Node) Size() int { - return len(n.Blob) + common.HashLength -} - -// IsDeleted returns the indicator if the node is marked as deleted. -func (n *Node) IsDeleted() bool { - return len(n.Blob) == 0 -} - -// New constructs a node with provided node information. -func New(hash common.Hash, blob []byte) *Node { - return &Node{Hash: hash, Blob: blob} -} - -// NewDeleted constructs a node which is deleted. -func NewDeleted() *Node { return New(common.Hash{}, nil) } - -// leaf represents a trie leaf node -type leaf struct { - Blob []byte // raw blob of leaf - Parent common.Hash // the hash of parent node -} - -// NodeSet contains a set of nodes collected during the commit operation. -// Each node is keyed by path. It's not thread-safe to use. -type NodeSet struct { - Owner common.Hash - Leaves []*leaf - Nodes map[string]*Node - updates int // the count of updated and inserted nodes - deletes int // the count of deleted nodes -} - -// NewNodeSet initializes a node set. The owner is zero for the account trie and -// the owning account address hash for storage tries. -func NewNodeSet(owner common.Hash) *NodeSet { - return &NodeSet{ - Owner: owner, - Nodes: make(map[string]*Node), - } -} - -// ForEachWithOrder iterates the nodes with the order from bottom to top, -// right to left, nodes with the longest path will be iterated first. -func (set *NodeSet) ForEachWithOrder(callback func(path string, n *Node)) { - var paths []string - for path := range set.Nodes { - paths = append(paths, path) - } - // Bottom-up, the longest path first - sort.Sort(sort.Reverse(sort.StringSlice(paths))) - for _, path := range paths { - callback(path, set.Nodes[path]) - } -} - -// AddNode adds the provided node into set. -func (set *NodeSet) AddNode(path []byte, n *Node) { - if n.IsDeleted() { - set.deletes += 1 - } else { - set.updates += 1 - } - set.Nodes[string(path)] = n -} - -// Merge adds a set of nodes into the set. -func (set *NodeSet) Merge(owner common.Hash, nodes map[string]*Node) error { - if set.Owner != owner { - return fmt.Errorf("nodesets belong to different owner are not mergeable %x-%x", set.Owner, owner) - } - for path, node := range nodes { - prev, ok := set.Nodes[path] - if ok { - // overwrite happens, revoke the counter - if prev.IsDeleted() { - set.deletes -= 1 - } else { - set.updates -= 1 - } - } - set.AddNode([]byte(path), node) - } - return nil -} - -// AddLeaf adds the provided leaf node into set. TODO(rjl493456442) how can -// we get rid of it? -func (set *NodeSet) AddLeaf(parent common.Hash, blob []byte) { - set.Leaves = append(set.Leaves, &leaf{Blob: blob, Parent: parent}) -} - -// Size returns the number of dirty nodes in set. -func (set *NodeSet) Size() (int, int) { - return set.updates, set.deletes -} - -// Hashes returns the hashes of all updated nodes. TODO(rjl493456442) how can -// we get rid of it? -func (set *NodeSet) Hashes() []common.Hash { - var ret []common.Hash - for _, node := range set.Nodes { - ret = append(ret, node.Hash) - } - return ret -} - -// Summary returns a string-representation of the NodeSet. -func (set *NodeSet) Summary() string { - var out = new(strings.Builder) - fmt.Fprintf(out, "nodeset owner: %v\n", set.Owner) - if set.Nodes != nil { - for path, n := range set.Nodes { - // Deletion - if n.IsDeleted() { - fmt.Fprintf(out, " [-]: %x\n", path) - continue - } - // Insertion or update - fmt.Fprintf(out, " [+/*]: %x -> %v \n", path, n.Hash) - } - } - for _, n := range set.Leaves { - fmt.Fprintf(out, "[leaf]: %v\n", n) - } - return out.String() -} - -// MergedNodeSet represents a merged node set for a group of tries. -type MergedNodeSet struct { - Sets map[common.Hash]*NodeSet -} - -// NewMergedNodeSet initializes an empty merged set. -func NewMergedNodeSet() *MergedNodeSet { - return &MergedNodeSet{Sets: make(map[common.Hash]*NodeSet)} -} - -// NewWithNodeSet constructs a merged nodeset with the provided single set. -func NewWithNodeSet(set *NodeSet) *MergedNodeSet { - merged := NewMergedNodeSet() - merged.Merge(set) - return merged -} - -// Merge merges the provided dirty nodes of a trie into the set. The assumption -// is held that no duplicated set belonging to the same trie will be merged twice. -func (set *MergedNodeSet) Merge(other *NodeSet) error { - subset, present := set.Sets[other.Owner] - if present { - return subset.Merge(other.Owner, other.Nodes) - } - set.Sets[other.Owner] = other - return nil -} - -// Flatten returns a two-dimensional map for internal nodes. -func (set *MergedNodeSet) Flatten() map[common.Hash]map[string]*Node { - nodes := make(map[common.Hash]map[string]*Node) - for owner, set := range set.Sets { - nodes[owner] = set.Nodes - } - return nodes -} diff --git a/trie/triestate/state.go b/trie/triestate/state.go deleted file mode 100644 index aa282a8e30..0000000000 --- a/trie/triestate/state.go +++ /dev/null @@ -1,286 +0,0 @@ -// (c) 2024, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2023 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 triestate - -import ( - "errors" - "fmt" - "sync" - - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/crypto/sha3" -) - -// Trie is an Ethereum state trie, can be implemented by Ethereum Merkle Patricia -// tree or Verkle tree. -type Trie interface { - // Get returns the value for key stored in the trie. - Get(key []byte) ([]byte, error) - - // Update associates key with value in the trie. - Update(key, value []byte) error - - // Delete removes any existing value for key from the trie. - Delete(key []byte) error - - // Commit the trie and returns a set of dirty nodes generated along with - // the new root hash. - Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) -} - -// TrieLoader wraps functions to load tries. -type TrieLoader interface { - // OpenTrie opens the main account trie. - OpenTrie(root common.Hash) (Trie, error) - - // OpenStorageTrie opens the storage trie of an account. - OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) -} - -// Set represents a collection of mutated states during a state transition. -// The value refers to the original content of state before the transition -// is made. Nil means that the state was not present previously. -type Set struct { - Accounts map[common.Address][]byte // Mutated account set, nil means the account was not present - Storages map[common.Address]map[common.Hash][]byte // Mutated storage set, nil means the slot was not present - Incomplete map[common.Address]struct{} // Indicator whether the storage is incomplete due to large deletion - size common.StorageSize // Approximate size of set -} - -// New constructs the state set with provided data. -func New(accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, incomplete map[common.Address]struct{}) *Set { - return &Set{ - Accounts: accounts, - Storages: storages, - Incomplete: incomplete, - } -} - -// Size returns the approximate memory size occupied by the set. -func (s *Set) Size() common.StorageSize { - if s.size != 0 { - return s.size - } - for _, account := range s.Accounts { - s.size += common.StorageSize(common.AddressLength + len(account)) - } - for _, slots := range s.Storages { - for _, val := range slots { - s.size += common.StorageSize(common.HashLength + len(val)) - } - s.size += common.StorageSize(common.AddressLength) - } - s.size += common.StorageSize(common.AddressLength * len(s.Incomplete)) - return s.size -} - -// context wraps all fields for executing state diffs. -type context struct { - prevRoot common.Hash - postRoot common.Hash - accounts map[common.Address][]byte - storages map[common.Address]map[common.Hash][]byte - accountTrie Trie - nodes *trienode.MergedNodeSet -} - -// Apply traverses the provided state diffs, apply them in the associated -// post-state and return the generated dirty trie nodes. The state can be -// loaded via the provided trie loader. -func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, loader TrieLoader) (map[common.Hash]map[string]*trienode.Node, error) { - tr, err := loader.OpenTrie(postRoot) - if err != nil { - return nil, err - } - ctx := &context{ - prevRoot: prevRoot, - postRoot: postRoot, - accounts: accounts, - storages: storages, - accountTrie: tr, - nodes: trienode.NewMergedNodeSet(), - } - for addr, account := range accounts { - var err error - if len(account) == 0 { - err = deleteAccount(ctx, loader, addr) - } else { - err = updateAccount(ctx, loader, addr) - } - if err != nil { - return nil, fmt.Errorf("failed to revert state, err: %w", err) - } - } - root, result, err := tr.Commit(false) - if err != nil { - return nil, err - } - if root != prevRoot { - return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) - } - if err := ctx.nodes.Merge(result); err != nil { - return nil, err - } - return ctx.nodes.Flatten(), nil -} - -// updateAccount the account was present in prev-state, and may or may not -// existent in post-state. Apply the reverse diff and verify if the storage -// root matches the one in prev-state account. -func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error { - // The account was present in prev-state, decode it from the - // 'slim-rlp' format bytes. - h := newHasher() - defer h.release() - - addrHash := h.hash(addr.Bytes()) - prev, err := types.FullAccount(ctx.accounts[addr]) - if err != nil { - return err - } - // The account may or may not existent in post-state, try to - // load it and decode if it's found. - blob, err := ctx.accountTrie.Get(addrHash.Bytes()) - if err != nil { - return err - } - post := types.NewEmptyStateAccount() - if len(blob) != 0 { - if err := rlp.DecodeBytes(blob, &post); err != nil { - return err - } - } - // Apply all storage changes into the post-state storage trie. - st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root) - if err != nil { - return err - } - for key, val := range ctx.storages[addr] { - var err error - if len(val) == 0 { - err = st.Delete(key.Bytes()) - } else { - err = st.Update(key.Bytes(), val) - } - if err != nil { - return err - } - } - root, result, err := st.Commit(false) - if err != nil { - return err - } - if root != prev.Root { - return errors.New("failed to reset storage trie") - } - // The returned set can be nil if storage trie is not changed - // at all. - if result != nil { - if err := ctx.nodes.Merge(result); err != nil { - return err - } - } - // Write the prev-state account into the main trie - full, err := rlp.EncodeToBytes(prev) - if err != nil { - return err - } - return ctx.accountTrie.Update(addrHash.Bytes(), full) -} - -// deleteAccount the account was not present in prev-state, and is expected -// to be existent in post-state. Apply the reverse diff and verify if the -// account and storage is wiped out correctly. -func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error { - // The account must be existent in post-state, load the account. - h := newHasher() - defer h.release() - - addrHash := h.hash(addr.Bytes()) - blob, err := ctx.accountTrie.Get(addrHash.Bytes()) - if err != nil { - return err - } - if len(blob) == 0 { - return fmt.Errorf("account is non-existent %#x", addrHash) - } - var post types.StateAccount - if err := rlp.DecodeBytes(blob, &post); err != nil { - return err - } - st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root) - if err != nil { - return err - } - for key, val := range ctx.storages[addr] { - if len(val) != 0 { - return errors.New("expect storage deletion") - } - if err := st.Delete(key.Bytes()); err != nil { - return err - } - } - root, result, err := st.Commit(false) - if err != nil { - return err - } - if root != types.EmptyRootHash { - return errors.New("failed to clear storage trie") - } - // The returned set can be nil if storage trie is not changed - // at all. - if result != nil { - if err := ctx.nodes.Merge(result); err != nil { - return err - } - } - // Delete the post-state account from the main trie. - return ctx.accountTrie.Delete(addrHash.Bytes()) -} - -// hasher is used to compute the sha256 hash of the provided data. -type hasher struct{ sha crypto.KeccakState } - -var hasherPool = sync.Pool{ - New: func() interface{} { return &hasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} }, -} - -func newHasher() *hasher { - return hasherPool.Get().(*hasher) -} - -func (h *hasher) hash(data []byte) common.Hash { - return crypto.HashData(h.sha, data) -} - -func (h *hasher) release() { - hasherPool.Put(h) -} diff --git a/trie/utils/verkle.go b/trie/utils/verkle.go deleted file mode 100644 index d6546186cc..0000000000 --- a/trie/utils/verkle.go +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright 2023 go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 utils - -import ( - "encoding/binary" - "sync" - - "github.com/ava-labs/subnet-evm/metrics" - "github.com/crate-crypto/go-ipa/bandersnatch/fr" - "github.com/ethereum/go-ethereum/common/lru" - "github.com/gballet/go-verkle" - "github.com/holiman/uint256" -) - -const ( - // The spec of verkle key encoding can be found here. - // https://notes.ethereum.org/@vbuterin/verkle_tree_eip#Tree-embedding - VersionLeafKey = 0 - BalanceLeafKey = 1 - NonceLeafKey = 2 - CodeKeccakLeafKey = 3 - CodeSizeLeafKey = 4 -) - -var ( - zero = uint256.NewInt(0) - verkleNodeWidthLog2 = 8 - headerStorageOffset = uint256.NewInt(64) - mainStorageOffsetLshVerkleNodeWidth = new(uint256.Int).Lsh(uint256.NewInt(256), 31-uint(verkleNodeWidthLog2)) - codeOffset = uint256.NewInt(128) - verkleNodeWidth = uint256.NewInt(256) - codeStorageDelta = uint256.NewInt(0).Sub(codeOffset, headerStorageOffset) - - index0Point *verkle.Point // pre-computed commitment of polynomial [2+256*64] - - // cacheHitGauge is the metric to track how many cache hit occurred. - cacheHitGauge = metrics.NewRegisteredGauge("trie/verkle/cache/hit", nil) - - // cacheMissGauge is the metric to track how many cache miss occurred. - cacheMissGauge = metrics.NewRegisteredGauge("trie/verkle/cache/miss", nil) -) - -func init() { - // The byte array is the Marshalled output of the point computed as such: - // - // var ( - // config = verkle.GetConfig() - // fr verkle.Fr - // ) - // verkle.FromLEBytes(&fr, []byte{2, 64}) - // point := config.CommitToPoly([]verkle.Fr{fr}, 1) - index0Point = new(verkle.Point) - err := index0Point.SetBytes([]byte{34, 25, 109, 242, 193, 5, 144, 224, 76, 52, 189, 92, 197, 126, 9, 145, 27, 152, 199, 130, 165, 3, 210, 27, 193, 131, 142, 28, 110, 26, 16, 191}) - if err != nil { - panic(err) - } -} - -// PointCache is the LRU cache for storing evaluated address commitment. -type PointCache struct { - lru lru.BasicLRU[string, *verkle.Point] - lock sync.RWMutex -} - -// NewPointCache returns the cache with specified size. -func NewPointCache(maxItems int) *PointCache { - return &PointCache{ - lru: lru.NewBasicLRU[string, *verkle.Point](maxItems), - } -} - -// Get returns the cached commitment for the specified address, or computing -// it on the flight. -func (c *PointCache) Get(addr []byte) *verkle.Point { - c.lock.Lock() - defer c.lock.Unlock() - - p, ok := c.lru.Get(string(addr)) - if ok { - cacheHitGauge.Inc(1) - return p - } - cacheMissGauge.Inc(1) - p = evaluateAddressPoint(addr) - c.lru.Add(string(addr), p) - return p -} - -// GetStem returns the first 31 bytes of the tree key as the tree stem. It only -// works for the account metadata whose treeIndex is 0. -func (c *PointCache) GetStem(addr []byte) []byte { - p := c.Get(addr) - return pointToHash(p, 0)[:31] -} - -// GetTreeKey performs both the work of the spec's get_tree_key function, and that -// of pedersen_hash: it builds the polynomial in pedersen_hash without having to -// create a mostly zero-filled buffer and "type cast" it to a 128-long 16-byte -// array. Since at most the first 5 coefficients of the polynomial will be non-zero, -// these 5 coefficients are created directly. -func GetTreeKey(address []byte, treeIndex *uint256.Int, subIndex byte) []byte { - if len(address) < 32 { - var aligned [32]byte - address = append(aligned[:32-len(address)], address...) - } - // poly = [2+256*64, address_le_low, address_le_high, tree_index_le_low, tree_index_le_high] - var poly [5]fr.Element - - // 32-byte address, interpreted as two little endian - // 16-byte numbers. - verkle.FromLEBytes(&poly[1], address[:16]) - verkle.FromLEBytes(&poly[2], address[16:]) - - // treeIndex must be interpreted as a 32-byte aligned little-endian integer. - // e.g: if treeIndex is 0xAABBCC, we need the byte representation to be 0xCCBBAA00...00. - // poly[3] = LE({CC,BB,AA,00...0}) (16 bytes), poly[4]=LE({00,00,...}) (16 bytes). - // - // To avoid unnecessary endianness conversions for go-ipa, we do some trick: - // - poly[3]'s byte representation is the same as the *top* 16 bytes (trieIndexBytes[16:]) of - // 32-byte aligned big-endian representation (BE({00,...,AA,BB,CC})). - // - poly[4]'s byte representation is the same as the *low* 16 bytes (trieIndexBytes[:16]) of - // the 32-byte aligned big-endian representation (BE({00,00,...}). - trieIndexBytes := treeIndex.Bytes32() - verkle.FromBytes(&poly[3], trieIndexBytes[16:]) - verkle.FromBytes(&poly[4], trieIndexBytes[:16]) - - cfg := verkle.GetConfig() - ret := cfg.CommitToPoly(poly[:], 0) - - // add a constant point corresponding to poly[0]=[2+256*64]. - ret.Add(ret, index0Point) - - return pointToHash(ret, subIndex) -} - -// GetTreeKeyWithEvaluatedAddress is basically identical to GetTreeKey, the only -// difference is a part of polynomial is already evaluated. -// -// Specifically, poly = [2+256*64, address_le_low, address_le_high] is already -// evaluated. -func GetTreeKeyWithEvaluatedAddress(evaluated *verkle.Point, treeIndex *uint256.Int, subIndex byte) []byte { - var poly [5]fr.Element - - poly[0].SetZero() - poly[1].SetZero() - poly[2].SetZero() - - // little-endian, 32-byte aligned treeIndex - var index [32]byte - for i := 0; i < len(treeIndex); i++ { - binary.LittleEndian.PutUint64(index[i*8:(i+1)*8], treeIndex[i]) - } - verkle.FromLEBytes(&poly[3], index[:16]) - verkle.FromLEBytes(&poly[4], index[16:]) - - cfg := verkle.GetConfig() - ret := cfg.CommitToPoly(poly[:], 0) - - // add the pre-evaluated address - ret.Add(ret, evaluated) - - return pointToHash(ret, subIndex) -} - -// VersionKey returns the verkle tree key of the version field for the specified account. -func VersionKey(address []byte) []byte { - return GetTreeKey(address, zero, VersionLeafKey) -} - -// BalanceKey returns the verkle tree key of the balance field for the specified account. -func BalanceKey(address []byte) []byte { - return GetTreeKey(address, zero, BalanceLeafKey) -} - -// NonceKey returns the verkle tree key of the nonce field for the specified account. -func NonceKey(address []byte) []byte { - return GetTreeKey(address, zero, NonceLeafKey) -} - -// CodeKeccakKey returns the verkle tree key of the code keccak field for -// the specified account. -func CodeKeccakKey(address []byte) []byte { - return GetTreeKey(address, zero, CodeKeccakLeafKey) -} - -// CodeSizeKey returns the verkle tree key of the code size field for the -// specified account. -func CodeSizeKey(address []byte) []byte { - return GetTreeKey(address, zero, CodeSizeLeafKey) -} - -func codeChunkIndex(chunk *uint256.Int) (*uint256.Int, byte) { - var ( - chunkOffset = new(uint256.Int).Add(codeOffset, chunk) - treeIndex = new(uint256.Int).Div(chunkOffset, verkleNodeWidth) - subIndexMod = new(uint256.Int).Mod(chunkOffset, verkleNodeWidth) - ) - var subIndex byte - if len(subIndexMod) != 0 { - subIndex = byte(subIndexMod[0]) - } - return treeIndex, subIndex -} - -// CodeChunkKey returns the verkle tree key of the code chunk for the -// specified account. -func CodeChunkKey(address []byte, chunk *uint256.Int) []byte { - treeIndex, subIndex := codeChunkIndex(chunk) - return GetTreeKey(address, treeIndex, subIndex) -} - -func storageIndex(bytes []byte) (*uint256.Int, byte) { - // If the storage slot is in the header, we need to add the header offset. - var key uint256.Int - key.SetBytes(bytes) - if key.Cmp(codeStorageDelta) < 0 { - // This addition is always safe; it can't ever overflow since pos - -package utils - -import ( - "bytes" - "testing" - - "github.com/gballet/go-verkle" - "github.com/holiman/uint256" -) - -func TestTreeKey(t *testing.T) { - var ( - address = []byte{0x01} - addressEval = evaluateAddressPoint(address) - smallIndex = uint256.NewInt(1) - largeIndex = uint256.NewInt(10000) - smallStorage = []byte{0x1} - largeStorage = bytes.Repeat([]byte{0xff}, 16) - ) - if !bytes.Equal(VersionKey(address), VersionKeyWithEvaluatedAddress(addressEval)) { - t.Fatal("Unmatched version key") - } - if !bytes.Equal(BalanceKey(address), BalanceKeyWithEvaluatedAddress(addressEval)) { - t.Fatal("Unmatched balance key") - } - if !bytes.Equal(NonceKey(address), NonceKeyWithEvaluatedAddress(addressEval)) { - t.Fatal("Unmatched nonce key") - } - if !bytes.Equal(CodeKeccakKey(address), CodeKeccakKeyWithEvaluatedAddress(addressEval)) { - t.Fatal("Unmatched code keccak key") - } - if !bytes.Equal(CodeSizeKey(address), CodeSizeKeyWithEvaluatedAddress(addressEval)) { - t.Fatal("Unmatched code size key") - } - if !bytes.Equal(CodeChunkKey(address, smallIndex), CodeChunkKeyWithEvaluatedAddress(addressEval, smallIndex)) { - t.Fatal("Unmatched code chunk key") - } - if !bytes.Equal(CodeChunkKey(address, largeIndex), CodeChunkKeyWithEvaluatedAddress(addressEval, largeIndex)) { - t.Fatal("Unmatched code chunk key") - } - if !bytes.Equal(StorageSlotKey(address, smallStorage), StorageSlotKeyWithEvaluatedAddress(addressEval, smallStorage)) { - t.Fatal("Unmatched storage slot key") - } - if !bytes.Equal(StorageSlotKey(address, largeStorage), StorageSlotKeyWithEvaluatedAddress(addressEval, largeStorage)) { - t.Fatal("Unmatched storage slot key") - } -} - -// goos: darwin -// goarch: amd64 -// pkg: github.com/ava-labs/subnet-evm/trie/utils -// cpu: VirtualApple @ 2.50GHz -// BenchmarkTreeKey -// BenchmarkTreeKey-8 398731 2961 ns/op 32 B/op 1 allocs/op -func BenchmarkTreeKey(b *testing.B) { - // Initialize the IPA settings which can be pretty expensive. - verkle.GetConfig() - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - BalanceKey([]byte{0x01}) - } -} - -// goos: darwin -// goarch: amd64 -// pkg: github.com/ava-labs/subnet-evm/trie/utils -// cpu: VirtualApple @ 2.50GHz -// BenchmarkTreeKeyWithEvaluation -// BenchmarkTreeKeyWithEvaluation-8 513855 2324 ns/op 32 B/op 1 allocs/op -func BenchmarkTreeKeyWithEvaluation(b *testing.B) { - // Initialize the IPA settings which can be pretty expensive. - verkle.GetConfig() - - addr := []byte{0x01} - eval := evaluateAddressPoint(addr) - - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - BalanceKeyWithEvaluatedAddress(eval) - } -} - -// goos: darwin -// goarch: amd64 -// pkg: github.com/ava-labs/subnet-evm/trie/utils -// cpu: VirtualApple @ 2.50GHz -// BenchmarkStorageKey -// BenchmarkStorageKey-8 230516 4584 ns/op 96 B/op 3 allocs/op -func BenchmarkStorageKey(b *testing.B) { - // Initialize the IPA settings which can be pretty expensive. - verkle.GetConfig() - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - StorageSlotKey([]byte{0x01}, bytes.Repeat([]byte{0xff}, 32)) - } -} - -// goos: darwin -// goarch: amd64 -// pkg: github.com/ava-labs/subnet-evm/trie/utils -// cpu: VirtualApple @ 2.50GHz -// BenchmarkStorageKeyWithEvaluation -// BenchmarkStorageKeyWithEvaluation-8 320125 3753 ns/op 96 B/op 3 allocs/op -func BenchmarkStorageKeyWithEvaluation(b *testing.B) { - // Initialize the IPA settings which can be pretty expensive. - verkle.GetConfig() - - addr := []byte{0x01} - eval := evaluateAddressPoint(addr) - - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - StorageSlotKeyWithEvaluatedAddress(eval, bytes.Repeat([]byte{0xff}, 32)) - } -} diff --git a/trie/verkle.go b/trie/verkle.go deleted file mode 100644 index e6f60a8e85..0000000000 --- a/trie/verkle.go +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright 2023 go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "encoding/binary" - "errors" - "fmt" - - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/utils" - "github.com/ava-labs/subnet-evm/triedb/database" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/gballet/go-verkle" - "github.com/holiman/uint256" -) - -var ( - zero [32]byte - errInvalidRootType = errors.New("invalid node type for root") -) - -// VerkleTrie is a wrapper around VerkleNode that implements the trie.Trie -// interface so that Verkle trees can be reused verbatim. -type VerkleTrie struct { - root verkle.VerkleNode - cache *utils.PointCache - reader *trieReader -} - -// NewVerkleTrie constructs a verkle tree based on the specified root hash. -func NewVerkleTrie(root common.Hash, db database.Database, cache *utils.PointCache) (*VerkleTrie, error) { - reader, err := newTrieReader(root, common.Hash{}, db) - if err != nil { - return nil, err - } - // Parse the root verkle node if it's not empty. - node := verkle.New() - if root != types.EmptyVerkleHash && root != types.EmptyRootHash { - blob, err := reader.node(nil, common.Hash{}) - if err != nil { - return nil, err - } - node, err = verkle.ParseNode(blob, 0) - if err != nil { - return nil, err - } - } - return &VerkleTrie{ - root: node, - cache: cache, - reader: reader, - }, nil -} - -// GetKey returns the sha3 preimage of a hashed key that was previously used -// to store a value. -func (t *VerkleTrie) GetKey(key []byte) []byte { - return key -} - -// GetAccount implements state.Trie, retrieving the account with the specified -// account address. If the specified account is not in the verkle tree, nil will -// be returned. If the tree is corrupted, an error will be returned. -func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error) { - var ( - acc = &types.StateAccount{} - values [][]byte - err error - ) - switch n := t.root.(type) { - case *verkle.InternalNode: - values, err = n.GetValuesAtStem(t.cache.GetStem(addr[:]), t.nodeResolver) - if err != nil { - return nil, fmt.Errorf("GetAccount (%x) error: %v", addr, err) - } - default: - return nil, errInvalidRootType - } - if values == nil { - return nil, nil - } - // Decode nonce in little-endian - if len(values[utils.NonceLeafKey]) > 0 { - acc.Nonce = binary.LittleEndian.Uint64(values[utils.NonceLeafKey]) - } - // Decode balance in little-endian - var balance [32]byte - copy(balance[:], values[utils.BalanceLeafKey]) - for i := 0; i < len(balance)/2; i++ { - balance[len(balance)-i-1], balance[i] = balance[i], balance[len(balance)-i-1] - } - acc.Balance = new(uint256.Int).SetBytes32(balance[:]) - - // Decode codehash - acc.CodeHash = values[utils.CodeKeccakLeafKey] - - // TODO account.Root is leave as empty. How should we handle the legacy account? - return acc, nil -} - -// GetStorage implements state.Trie, retrieving the storage slot with the specified -// account address and storage key. If the specified slot is not in the verkle tree, -// nil will be returned. If the tree is corrupted, an error will be returned. -func (t *VerkleTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) { - k := utils.StorageSlotKeyWithEvaluatedAddress(t.cache.Get(addr.Bytes()), key) - val, err := t.root.Get(k, t.nodeResolver) - if err != nil { - return nil, err - } - return common.TrimLeftZeroes(val), nil -} - -// UpdateAccount implements state.Trie, writing the provided account into the tree. -// If the tree is corrupted, an error will be returned. -func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount) error { - var ( - err error - nonce, balance [32]byte - values = make([][]byte, verkle.NodeWidth) - ) - values[utils.VersionLeafKey] = zero[:] - values[utils.CodeKeccakLeafKey] = acc.CodeHash[:] - - // Encode nonce in little-endian - binary.LittleEndian.PutUint64(nonce[:], acc.Nonce) - values[utils.NonceLeafKey] = nonce[:] - - // Encode balance in little-endian - bytes := acc.Balance.Bytes() - if len(bytes) > 0 { - for i, b := range bytes { - balance[len(bytes)-i-1] = b - } - } - values[utils.BalanceLeafKey] = balance[:] - - switch n := t.root.(type) { - case *verkle.InternalNode: - err = n.InsertValuesAtStem(t.cache.GetStem(addr[:]), values, t.nodeResolver) - if err != nil { - return fmt.Errorf("UpdateAccount (%x) error: %v", addr, err) - } - default: - return errInvalidRootType - } - // TODO figure out if the code size needs to be updated, too - return nil -} - -// UpdateStorage implements state.Trie, writing the provided storage slot into -// the tree. If the tree is corrupted, an error will be returned. -func (t *VerkleTrie) UpdateStorage(address common.Address, key, value []byte) error { - // Left padding the slot value to 32 bytes. - var v [32]byte - if len(value) >= 32 { - copy(v[:], value[:32]) - } else { - copy(v[32-len(value):], value[:]) - } - k := utils.StorageSlotKeyWithEvaluatedAddress(t.cache.Get(address.Bytes()), key) - return t.root.Insert(k, v[:], t.nodeResolver) -} - -// DeleteAccount implements state.Trie, deleting the specified account from the -// trie. If the account was not existent in the trie, no error will be returned. -// If the trie is corrupted, an error will be returned. -func (t *VerkleTrie) DeleteAccount(addr common.Address) error { - var ( - err error - values = make([][]byte, verkle.NodeWidth) - ) - for i := 0; i < verkle.NodeWidth; i++ { - values[i] = zero[:] - } - switch n := t.root.(type) { - case *verkle.InternalNode: - err = n.InsertValuesAtStem(t.cache.GetStem(addr.Bytes()), values, t.nodeResolver) - if err != nil { - return fmt.Errorf("DeleteAccount (%x) error: %v", addr, err) - } - default: - return errInvalidRootType - } - return nil -} - -// DeleteStorage implements state.Trie, deleting the specified storage slot from -// the trie. If the storage slot was not existent in the trie, no error will be -// returned. If the trie is corrupted, an error will be returned. -func (t *VerkleTrie) DeleteStorage(addr common.Address, key []byte) error { - var zero [32]byte - k := utils.StorageSlotKeyWithEvaluatedAddress(t.cache.Get(addr.Bytes()), key) - return t.root.Insert(k, zero[:], t.nodeResolver) -} - -// Hash returns the root hash of the tree. It does not write to the database and -// can be used even if the tree doesn't have one. -func (t *VerkleTrie) Hash() common.Hash { - return t.root.Commit().Bytes() -} - -// Commit writes all nodes to the tree's memory database. -func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) { - root, ok := t.root.(*verkle.InternalNode) - if !ok { - return common.Hash{}, nil, errors.New("unexpected root node type") - } - nodes, err := root.BatchSerialize() - if err != nil { - return common.Hash{}, nil, fmt.Errorf("serializing tree nodes: %s", err) - } - nodeset := trienode.NewNodeSet(common.Hash{}) - for _, node := range nodes { - // hash parameter is not used in pathdb - nodeset.AddNode(node.Path, trienode.New(common.Hash{}, node.SerializedBytes)) - } - // Serialize root commitment form - return t.Hash(), nodeset, nil -} - -// NodeIterator implements state.Trie, returning an iterator that returns -// nodes of the trie. Iteration starts at the key after the given start key. -// -// TODO(gballet, rjl493456442) implement it. -func (t *VerkleTrie) NodeIterator(startKey []byte) (NodeIterator, error) { - panic("not implemented") -} - -// Prove implements state.Trie, constructing a Merkle proof for key. The result -// contains all encoded nodes on the path to the value at key. The value itself -// is also included in the last node and can be retrieved by verifying the proof. -// -// If the trie does not contain a value for key, the returned proof contains all -// nodes of the longest existing prefix of the key (at least the root), ending -// with the node that proves the absence of the key. -// -// TODO(gballet, rjl493456442) implement it. -func (t *VerkleTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error { - panic("not implemented") -} - -// Copy returns a deep-copied verkle tree. -func (t *VerkleTrie) Copy() *VerkleTrie { - return &VerkleTrie{ - root: t.root.Copy(), - cache: t.cache, - reader: t.reader, - } -} - -// IsVerkle indicates if the trie is a Verkle trie. -func (t *VerkleTrie) IsVerkle() bool { - return true -} - -// ChunkedCode represents a sequence of 32-bytes chunks of code (31 bytes of which -// are actual code, and 1 byte is the pushdata offset). -type ChunkedCode []byte - -// Copy the values here so as to avoid an import cycle -const ( - PUSH1 = byte(0x60) - PUSH32 = byte(0x7f) -) - -// ChunkifyCode generates the chunked version of an array representing EVM bytecode -func ChunkifyCode(code []byte) ChunkedCode { - var ( - chunkOffset = 0 // offset in the chunk - chunkCount = len(code) / 31 - codeOffset = 0 // offset in the code - ) - if len(code)%31 != 0 { - chunkCount++ - } - chunks := make([]byte, chunkCount*32) - for i := 0; i < chunkCount; i++ { - // number of bytes to copy, 31 unless the end of the code has been reached. - end := 31 * (i + 1) - if len(code) < end { - end = len(code) - } - copy(chunks[i*32+1:], code[31*i:end]) // copy the code itself - - // chunk offset = taken from the last chunk. - if chunkOffset > 31 { - // skip offset calculation if push data covers the whole chunk - chunks[i*32] = 31 - chunkOffset = 1 - continue - } - chunks[32*i] = byte(chunkOffset) - chunkOffset = 0 - - // Check each instruction and update the offset it should be 0 unless - // a PUSH-N overflows. - for ; codeOffset < end; codeOffset++ { - if code[codeOffset] >= PUSH1 && code[codeOffset] <= PUSH32 { - codeOffset += int(code[codeOffset] - PUSH1 + 1) - if codeOffset+1 >= 31*(i+1) { - codeOffset++ - chunkOffset = codeOffset - 31*(i+1) - break - } - } - } - } - return chunks -} - -// UpdateContractCode implements state.Trie, writing the provided contract code -// into the trie. -func (t *VerkleTrie) UpdateContractCode(addr common.Address, codeHash common.Hash, code []byte) error { - var ( - chunks = ChunkifyCode(code) - values [][]byte - key []byte - err error - ) - for i, chunknr := 0, uint64(0); i < len(chunks); i, chunknr = i+32, chunknr+1 { - groupOffset := (chunknr + 128) % 256 - if groupOffset == 0 /* start of new group */ || chunknr == 0 /* first chunk in header group */ { - values = make([][]byte, verkle.NodeWidth) - key = utils.CodeChunkKeyWithEvaluatedAddress(t.cache.Get(addr.Bytes()), uint256.NewInt(chunknr)) - } - values[groupOffset] = chunks[i : i+32] - - // Reuse the calculated key to also update the code size. - if i == 0 { - cs := make([]byte, 32) - binary.LittleEndian.PutUint64(cs, uint64(len(code))) - values[utils.CodeSizeLeafKey] = cs - } - if groupOffset == 255 || len(chunks)-i <= 32 { - switch root := t.root.(type) { - case *verkle.InternalNode: - err = root.InsertValuesAtStem(key[:31], values, t.nodeResolver) - if err != nil { - return fmt.Errorf("UpdateContractCode (addr=%x) error: %w", addr[:], err) - } - default: - return errInvalidRootType - } - } - } - return nil -} - -func (t *VerkleTrie) ToDot() string { - return verkle.ToDot(t.root) -} - -func (t *VerkleTrie) nodeResolver(path []byte) ([]byte, error) { - return t.reader.node(path, common.Hash{}) -} diff --git a/trie/verkle_test.go b/trie/verkle_test.go deleted file mode 100644 index e491a4bbb3..0000000000 --- a/trie/verkle_test.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2023 go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 trie - -import ( - "bytes" - "reflect" - "testing" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/holiman/uint256" -) - -var ( - accounts = map[common.Address]*types.StateAccount{ - {1}: { - Nonce: 100, - Balance: uint256.NewInt(100), - CodeHash: common.Hash{0x1}.Bytes(), - }, - {2}: { - Nonce: 200, - Balance: uint256.NewInt(200), - CodeHash: common.Hash{0x2}.Bytes(), - }, - } - storages = map[common.Address]map[common.Hash][]byte{ - {1}: { - common.Hash{10}: []byte{10}, - common.Hash{11}: []byte{11}, - common.MaxHash: []byte{0xff}, - }, - {2}: { - common.Hash{20}: []byte{20}, - common.Hash{21}: []byte{21}, - common.MaxHash: []byte{0xff}, - }, - } -) - -func TestVerkleTreeReadWrite(t *testing.T) { - db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.PathScheme) - tr, _ := NewVerkleTrie(types.EmptyVerkleHash, db, utils.NewPointCache(100)) - - for addr, acct := range accounts { - if err := tr.UpdateAccount(addr, acct); err != nil { - t.Fatalf("Failed to update account, %v", err) - } - for key, val := range storages[addr] { - if err := tr.UpdateStorage(addr, key.Bytes(), val); err != nil { - t.Fatalf("Failed to update account, %v", err) - } - } - } - - for addr, acct := range accounts { - stored, err := tr.GetAccount(addr) - if err != nil { - t.Fatalf("Failed to get account, %v", err) - } - if !reflect.DeepEqual(stored, acct) { - t.Fatal("account is not matched") - } - for key, val := range storages[addr] { - stored, err := tr.GetStorage(addr, key.Bytes()) - if err != nil { - t.Fatalf("Failed to get storage, %v", err) - } - if !bytes.Equal(stored, val) { - t.Fatal("storage is not matched") - } - } - } -} diff --git a/triedb/database.go b/triedb/database.go deleted file mode 100644 index 8042110275..0000000000 --- a/triedb/database.go +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 triedb - -import ( - "errors" - - "github.com/ava-labs/subnet-evm/trie" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ava-labs/subnet-evm/triedb/database" - "github.com/ava-labs/subnet-evm/triedb/hashdb" - "github.com/ava-labs/subnet-evm/triedb/pathdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" -) - -// Config defines all necessary options for database. -type Config struct { - Preimages bool // Flag whether the preimage of node key is recorded - IsVerkle bool // Flag whether the db is holding a verkle tree - HashDB *hashdb.Config // Configs for hash-based scheme - PathDB *pathdb.Config // Configs for experimental path-based scheme -} - -// HashDefaults represents a config for using hash-based scheme with -// default settings. -var HashDefaults = &Config{ - Preimages: false, - HashDB: hashdb.Defaults, -} - -// backend defines the methods needed to access/update trie nodes in different -// state scheme. -type backend interface { - // Scheme returns the identifier of used storage scheme. - Scheme() string - - // Initialized returns an indicator if the state data is already initialized - // according to the state scheme. - Initialized(genesisRoot common.Hash) bool - - // Size returns the current storage size of the diff layers on top of the - // disk layer and the storage size of the nodes cached in the disk layer. - // - // For hash scheme, there is no differentiation between diff layer nodes - // and dirty disk layer nodes, so both are merged into the second return. - Size() (common.StorageSize, common.StorageSize) - - // Update performs a state transition by committing dirty nodes contained - // in the given set in order to update state from the specified parent to - // the specified root. - // - // The passed in maps(nodes, states) will be retained to avoid copying - // everything. Therefore, these maps must not be changed afterwards. - Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error - - // Commit writes all relevant trie nodes belonging to the specified state - // to disk. Report specifies whether logs will be displayed in info level. - Commit(root common.Hash, report bool) error - - // Close closes the trie database backend and releases all held resources. - Close() error -} - -// Database is the wrapper of the underlying backend which is shared by different -// types of node backend as an entrypoint. It's responsible for all interactions -// relevant with trie nodes and node preimages. -type Database struct { - config *Config // Configuration for trie database - diskdb ethdb.Database // Persistent database to store the snapshot - preimages *preimageStore // The store for caching preimages - backend backend // The backend for managing trie nodes -} - -// NewDatabase initializes the trie database with default settings, note -// the legacy hash-based scheme is used by default. -func NewDatabase(diskdb ethdb.Database, config *Config) *Database { - // Sanitize the config and use the default one if it's not specified. - if config == nil { - config = HashDefaults - } - var preimages *preimageStore - if config.Preimages { - preimages = newPreimageStore(diskdb) - } - db := &Database{ - config: config, - diskdb: diskdb, - preimages: preimages, - } - if config.HashDB != nil && config.PathDB != nil { - log.Crit("Both 'hash' and 'path' mode are configured") - } - if config.PathDB != nil { - db.backend = pathdb.New(diskdb, config.PathDB) - } else { - var resolver hashdb.ChildResolver - if config.IsVerkle { - // TODO define verkle resolver - log.Crit("Verkle node resolver is not defined") - } else { - resolver = trie.MerkleResolver{} - } - db.backend = hashdb.New(diskdb, config.HashDB, resolver) - } - return db -} - -// Reader returns a reader for accessing all trie nodes with provided state root. -// An error will be returned if the requested state is not available. -func (db *Database) Reader(blockRoot common.Hash) (database.Reader, error) { - switch b := db.backend.(type) { - case *hashdb.Database: - return b.Reader(blockRoot) - case *pathdb.Database: - return b.Reader(blockRoot) - } - return nil, errors.New("unknown backend") -} - -// Update performs a state transition by committing dirty nodes contained in the -// given set in order to update state from the specified parent to the specified -// root. The held pre-images accumulated up to this point will be flushed in case -// the size exceeds the threshold. -// -// The passed in maps(nodes, states) will be retained to avoid copying everything. -// Therefore, these maps must not be changed afterwards. -func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error { - if db.preimages != nil { - db.preimages.commit(false) - } - return db.backend.Update(root, parent, block, nodes, states) -} - -// Commit iterates over all the children of a particular node, writes them out -// to disk. As a side effect, all pre-images accumulated up to this point are -// also written. -func (db *Database) Commit(root common.Hash, report bool) error { - if db.preimages != nil { - db.preimages.commit(true) - } - return db.backend.Commit(root, report) -} - -// Size returns the storage size of diff layer nodes above the persistent disk -// layer, the dirty nodes buffered within the disk layer, and the size of cached -// preimages. -func (db *Database) Size() (common.StorageSize, common.StorageSize, common.StorageSize) { - var ( - diffs, nodes common.StorageSize - preimages common.StorageSize - ) - diffs, nodes = db.backend.Size() - if db.preimages != nil { - preimages = db.preimages.size() - } - return diffs, nodes, preimages -} - -// Initialized returns an indicator if the state data is already initialized -// according to the state scheme. -func (db *Database) Initialized(genesisRoot common.Hash) bool { - return db.backend.Initialized(genesisRoot) -} - -// Scheme returns the node scheme used in the database. -func (db *Database) Scheme() string { - return db.backend.Scheme() -} - -// Close flushes the dangling preimages to disk and closes the trie database. -// It is meant to be called when closing the blockchain object, so that all -// resources held can be released correctly. -func (db *Database) Close() error { - db.WritePreimages() - return db.backend.Close() -} - -// WritePreimages flushes all accumulated preimages to disk forcibly. -func (db *Database) WritePreimages() { - if db.preimages != nil { - db.preimages.commit(true) - } -} - -// Preimage retrieves a cached trie node pre-image from preimage store. -func (db *Database) Preimage(hash common.Hash) []byte { - if db.preimages == nil { - return nil - } - return db.preimages.preimage(hash) -} - -// InsertPreimage writes pre-images of trie node to the preimage store. -func (db *Database) InsertPreimage(preimages map[common.Hash][]byte) { - if db.preimages == nil { - return - } - db.preimages.insertPreimage(preimages) -} - -// Cap iteratively flushes old but still referenced trie nodes until the total -// memory usage goes below the given threshold. The held pre-images accumulated -// up to this point will be flushed in case the size exceeds the threshold. -// -// It's only supported by hash-based database and will return an error for others. -func (db *Database) Cap(limit common.StorageSize) error { - hdb, ok := db.backend.(*hashdb.Database) - if !ok { - return errors.New("not supported") - } - if db.preimages != nil { - db.preimages.commit(false) - } - return hdb.Cap(limit) -} - -// Reference adds a new reference from a parent node to a child node. This function -// is used to add reference between internal trie node and external node(e.g. storage -// trie root), all internal trie nodes are referenced together by database itself. -// -// It's only supported by hash-based database and will return an error for others. -func (db *Database) Reference(root common.Hash, parent common.Hash) error { - hdb, ok := db.backend.(*hashdb.Database) - if !ok { - return errors.New("not supported") - } - hdb.Reference(root, parent) - return nil -} - -// Dereference removes an existing reference from a root node. It's only -// supported by hash-based database and will return an error for others. -func (db *Database) Dereference(root common.Hash) error { - hdb, ok := db.backend.(*hashdb.Database) - if !ok { - return errors.New("not supported") - } - hdb.Dereference(root) - return nil -} - -// Recover rollbacks the database to a specified historical point. The state is -// supported as the rollback destination only if it's canonical state and the -// corresponding trie histories are existent. It's only supported by path-based -// database and will return an error for others. -func (db *Database) Recover(target common.Hash) error { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return errors.New("not supported") - } - var loader triestate.TrieLoader - if db.config.IsVerkle { - // TODO define verkle loader - log.Crit("Verkle loader is not defined") - } else { - loader = trie.NewMerkleLoader(db) - } - return pdb.Recover(target, loader) -} - -// Recoverable returns the indicator if the specified state is enabled to be -// recovered. It's only supported by path-based database and will return an -// error for others. -func (db *Database) Recoverable(root common.Hash) (bool, error) { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return false, errors.New("not supported") - } - return pdb.Recoverable(root), nil -} - -// Disable deactivates the database and invalidates all available state layers -// as stale to prevent access to the persistent state, which is in the syncing -// stage. -// -// It's only supported by path-based database and will return an error for others. -func (db *Database) Disable() error { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return errors.New("not supported") - } - return pdb.Disable() -} - -// Enable activates database and resets the state tree with the provided persistent -// state root once the state sync is finished. -func (db *Database) Enable(root common.Hash) error { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return errors.New("not supported") - } - return pdb.Enable(root) -} - -// Journal commits an entire diff hierarchy to disk into a single journal entry. -// This is meant to be used during shutdown to persist the snapshot without -// flattening everything down (bad for reorgs). It's only supported by path-based -// database and will return an error for others. -func (db *Database) Journal(root common.Hash) error { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return errors.New("not supported") - } - return pdb.Journal(root) -} - -// SetBufferSize sets the node buffer size to the provided value(in bytes). -// It's only supported by path-based database and will return an error for -// others. -func (db *Database) SetBufferSize(size int) error { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return errors.New("not supported") - } - return pdb.SetBufferSize(size) -} - -// IsVerkle returns the indicator if the database is holding a verkle tree. -func (db *Database) IsVerkle() bool { - return db.config.IsVerkle -} diff --git a/triedb/database/database.go b/triedb/database/database.go deleted file mode 100644 index 18a8f454e2..0000000000 --- a/triedb/database/database.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2024 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 database - -import ( - "github.com/ethereum/go-ethereum/common" -) - -// Reader wraps the Node method of a backing trie reader. -type Reader interface { - // Node retrieves the trie node blob with the provided trie identifier, - // node path and the corresponding node hash. No error will be returned - // if the node is not found. - Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) -} - -// PreimageStore wraps the methods of a backing store for reading and writing -// trie node preimages. -type PreimageStore interface { - // Preimage retrieves the preimage of the specified hash. - Preimage(hash common.Hash) []byte - - // InsertPreimage commits a set of preimages along with their hashes. - InsertPreimage(preimages map[common.Hash][]byte) -} - -// Database wraps the methods of a backing trie store. -type Database interface { - PreimageStore - - // Reader returns a node reader associated with the specific state. - // An error will be returned if the specified state is not available. - Reader(stateRoot common.Hash) (Reader, error) -} diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index fc513c0c50..5da8fec829 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -33,16 +33,19 @@ import ( "sync" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/libevm/trie/trienode" + "github.com/ava-labs/libevm/trie/triestate" + "github.com/ava-labs/libevm/triedb" + "github.com/ava-labs/libevm/triedb/database" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/metrics" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/triestate" "github.com/ava-labs/subnet-evm/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) const ( @@ -102,6 +105,17 @@ type Config struct { ReferenceRootAtomicallyOnUpdate bool // Whether to reference the root node on update } +func (c Config) BackendConstructor(diskdb ethdb.Database, config *triedb.Config) triedb.DBOverride { + var resolver ChildResolver + if config.IsVerkle { + // TODO define verkle resolver + log.Crit("Verkle node resolver is not defined") + } else { + resolver = trie.MerkleResolver{} + } + return New(diskdb, &c, resolver) +} + // Defaults is the default setting for database if it's not specified. // Notably, clean cache is disabled explicitly, var Defaults = &Config{ @@ -726,7 +740,7 @@ func (db *Database) Scheme() string { // Reader retrieves a node reader belonging to the given state root. // An error will be returned if the requested state is not available. -func (db *Database) Reader(root common.Hash) (*reader, error) { +func (db *Database) Reader(root common.Hash) (database.Reader, error) { if _, err := db.node(root); err != nil { return nil, fmt.Errorf("state %#x is not available, %v", root, err) } diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index a4f3a81f0b..49ecc677f7 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -32,14 +32,16 @@ import ( "io" "sync" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/trie/trienode" + "github.com/ava-labs/libevm/trie/triestate" + "github.com/ava-labs/libevm/triedb" + "github.com/ava-labs/libevm/triedb/database" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" ) const ( @@ -101,6 +103,10 @@ type Config struct { ReadOnly bool // Flag whether the database is opened in read only mode. } +func (c Config) BackendConstructor(diskdb ethdb.Database, _ *triedb.Config) triedb.DBOverride { + return New(diskdb, &c) +} + // sanitize checks the provided user configurations and changes anything that's // unreasonable or unworkable. func (c *Config) sanitize() *Config { @@ -220,7 +226,7 @@ func New(diskdb ethdb.Database, config *Config) *Database { } // Reader retrieves a layer belonging to the given state root. -func (db *Database) Reader(root common.Hash) (layer, error) { +func (db *Database) Reader(root common.Hash) (database.Reader, error) { l := db.tree.get(root) if l == nil { return nil, fmt.Errorf("state %#x is not available", root) diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index b452ac2a44..c34cb44fc9 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -33,14 +33,14 @@ import ( "math/rand" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie/testutil" + "github.com/ava-labs/libevm/trie/trienode" + "github.com/ava-labs/libevm/trie/triestate" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/testutil" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" "github.com/stretchr/testify/require" ) @@ -228,7 +228,11 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode dirties = make(map[common.Hash]struct{}) ) for i := 0; i < 20; i++ { - switch rand.Intn(opLen) { + op := createAccountOp + if i > 0 { + op = rand.Intn(opLen) + } + switch op { case createAccountOp: // account creation addr := testutil.RandomAddress() diff --git a/triedb/pathdb/difflayer.go b/triedb/pathdb/difflayer.go index 997b3b636b..eea8dc4126 100644 --- a/triedb/pathdb/difflayer.go +++ b/triedb/pathdb/difflayer.go @@ -30,10 +30,10 @@ import ( "fmt" "sync" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/trie/trienode" + "github.com/ava-labs/libevm/trie/triestate" ) // diffLayer represents a collection of modifications made to the in-memory tries diff --git a/triedb/pathdb/difflayer_test.go b/triedb/pathdb/difflayer_test.go index 7b7570f6b1..d0c8d51728 100644 --- a/triedb/pathdb/difflayer_test.go +++ b/triedb/pathdb/difflayer_test.go @@ -30,10 +30,10 @@ import ( "bytes" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/trie/testutil" + "github.com/ava-labs/libevm/trie/trienode" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/trie/testutil" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" ) func emptyLayer() *diskLayer { diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index 0380a0121a..0bddd25165 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -32,12 +32,12 @@ import ( "sync" "github.com/VictoriaMetrics/fastcache" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/trie/trienode" + "github.com/ava-labs/libevm/trie/triestate" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" "golang.org/x/crypto/sha3" ) diff --git a/triedb/pathdb/errors.go b/triedb/pathdb/errors.go index af6e3464d2..6186091e30 100644 --- a/triedb/pathdb/errors.go +++ b/triedb/pathdb/errors.go @@ -30,8 +30,8 @@ import ( "errors" "fmt" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/common/hexutil" ) var ( diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 83fc385185..14e53383a3 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -32,8 +32,8 @@ import ( "errors" "fmt" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/trie/triestate" "golang.org/x/exp/slices" ) diff --git a/triedb/pathdb/history_test.go b/triedb/pathdb/history_test.go index abf40c2838..d001e4e894 100644 --- a/triedb/pathdb/history_test.go +++ b/triedb/pathdb/history_test.go @@ -31,11 +31,11 @@ import ( "reflect" "testing" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie/testutil" + "github.com/ava-labs/libevm/trie/triestate" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/testutil" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" ) // randomStateSet generates a random state change set. diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go index 6a9edccaee..678354aba5 100644 --- a/triedb/pathdb/journal.go +++ b/triedb/pathdb/journal.go @@ -33,14 +33,14 @@ import ( "io" "time" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/libevm/trie/trienode" + "github.com/ava-labs/libevm/trie/triestate" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" ) var ( diff --git a/triedb/pathdb/layertree.go b/triedb/pathdb/layertree.go index bc052da711..71eff3dba5 100644 --- a/triedb/pathdb/layertree.go +++ b/triedb/pathdb/layertree.go @@ -31,10 +31,10 @@ import ( "fmt" "sync" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/trie/trienode" + "github.com/ava-labs/libevm/trie/triestate" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ethereum/go-ethereum/common" ) // layerTree is a group of state layers identified by the state root. diff --git a/triedb/pathdb/nodebuffer.go b/triedb/pathdb/nodebuffer.go index ad0c45a4ef..80617916fc 100644 --- a/triedb/pathdb/nodebuffer.go +++ b/triedb/pathdb/nodebuffer.go @@ -31,12 +31,12 @@ import ( "time" "github.com/VictoriaMetrics/fastcache" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/ethdb" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/libevm/trie/trienode" "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" ) // nodebuffer is a collection of modified trie nodes to aggregate the disk diff --git a/triedb/pathdb/testutils.go b/triedb/pathdb/testutils.go index cf09e18609..bdf1e6374a 100644 --- a/triedb/pathdb/testutils.go +++ b/triedb/pathdb/testutils.go @@ -30,11 +30,11 @@ import ( "bytes" "fmt" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" + "github.com/ava-labs/libevm/trie/trienode" + "github.com/ava-labs/libevm/trie/triestate" "github.com/ava-labs/subnet-evm/core/types" - "github.com/ava-labs/subnet-evm/trie/trienode" - "github.com/ava-labs/subnet-evm/trie/triestate" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "golang.org/x/exp/slices" ) diff --git a/triedb/preimages.go b/triedb/preimages.go deleted file mode 100644 index be337a1fc5..0000000000 --- a/triedb/preimages.go +++ /dev/null @@ -1,107 +0,0 @@ -// (c) 2022, Ava Labs, Inc. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2022 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it 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 go-ethereum library is distributed in the hope that it 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 triedb - -import ( - "sync" - - "github.com/ava-labs/subnet-evm/core/rawdb" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethdb" -) - -const defaultPreimagesLimit = 4 * 1024 * 1024 // 4 MB - -// preimageStore is the store for caching preimages of node key. -type preimageStore struct { - lock sync.RWMutex - disk ethdb.KeyValueStore - preimages map[common.Hash][]byte // Preimages of nodes from the secure trie - preimagesSize common.StorageSize // Storage size of the preimages cache -} - -// newPreimageStore initializes the store for caching preimages. -func newPreimageStore(disk ethdb.KeyValueStore) *preimageStore { - return &preimageStore{ - disk: disk, - preimages: make(map[common.Hash][]byte), - } -} - -// insertPreimage writes a new trie node pre-image to the memory database if it's -// yet unknown. The method will NOT make a copy of the slice, only use if the -// preimage will NOT be changed later on. -func (store *preimageStore) insertPreimage(preimages map[common.Hash][]byte) { - store.lock.Lock() - defer store.lock.Unlock() - - for hash, preimage := range preimages { - if _, ok := store.preimages[hash]; ok { - continue - } - store.preimages[hash] = preimage - store.preimagesSize += common.StorageSize(common.HashLength + len(preimage)) - } -} - -// preimage retrieves a cached trie node pre-image from memory. If it cannot be -// found cached, the method queries the persistent database for the content. -func (store *preimageStore) preimage(hash common.Hash) []byte { - store.lock.RLock() - preimage := store.preimages[hash] - store.lock.RUnlock() - - if preimage != nil { - return preimage - } - return rawdb.ReadPreimage(store.disk, hash) -} - -// commit flushes the cached preimages into the disk. -func (store *preimageStore) commit(force bool) error { - store.lock.Lock() - defer store.lock.Unlock() - - if store.preimagesSize <= defaultPreimagesLimit && !force { - return nil - } - batch := store.disk.NewBatch() - rawdb.WritePreimages(batch, store.preimages) - if err := batch.Write(); err != nil { - return err - } - store.preimages, store.preimagesSize = make(map[common.Hash][]byte), 0 - return nil -} - -// size returns the current storage size of accumulated preimages. -func (store *preimageStore) size() common.StorageSize { - store.lock.RLock() - defer store.lock.RUnlock() - - return store.preimagesSize -} diff --git a/utils/address_range.go b/utils/address_range.go index 940c39e8a1..a10794f03d 100644 --- a/utils/address_range.go +++ b/utils/address_range.go @@ -6,7 +6,7 @@ package utils import ( "bytes" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" ) // AddressRange represents a continuous range of addresses diff --git a/utils/bytes.go b/utils/bytes.go index 54258b20f4..86382cf156 100644 --- a/utils/bytes.go +++ b/utils/bytes.go @@ -3,7 +3,7 @@ package utils -import "github.com/ethereum/go-ethereum/common" +import "github.com/ava-labs/libevm/common" // IncrOne increments bytes value by one func IncrOne(bytes []byte) { diff --git a/utils/bytes_test.go b/utils/bytes_test.go index b1bbc8fa6b..7b4fc9d05c 100644 --- a/utils/bytes_test.go +++ b/utils/bytes_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/ava-labs/avalanchego/utils" - "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/libevm/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/utils/key.go b/utils/key.go index a6515af062..ab4db85b94 100644 --- a/utils/key.go +++ b/utils/key.go @@ -7,8 +7,8 @@ import ( "crypto/ecdsa" "io" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/crypto" ) type Key struct { diff --git a/utils/snow.go b/utils/snow.go index 67c40ee293..fe33a56512 100644 --- a/utils/snow.go +++ b/utils/snow.go @@ -4,33 +4,83 @@ package utils import ( + "context" + "errors" + "github.com/ava-labs/avalanchego/api/metrics" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/avalanchego/snow/validators" "github.com/ava-labs/avalanchego/snow/validators/validatorstest" "github.com/ava-labs/avalanchego/upgrade/upgradetest" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/vms/platformvm/warp" +) + +var ( + testCChainID = ids.ID{'c', 'c', 'h', 'a', 'i', 'n', 't', 'e', 's', 't'} + testXChainID = ids.ID{'t', 'e', 's', 't', 'x'} + testChainID = ids.ID{'t', 'e', 's', 't', 'c', 'h', 'a', 'i', 'n'} ) func TestSnowContext() *snow.Context { - sk, err := bls.NewSecretKey() + sk, err := bls.NewSigner() if err != nil { panic(err) } - pk := bls.PublicFromSecretKey(sk) - return &snow.Context{ - NetworkID: constants.UnitTestID, + pk := sk.PublicKey() + networkID := constants.UnitTestID + chainID := testChainID + + ctx := &snow.Context{ + NetworkID: networkID, SubnetID: ids.Empty, - ChainID: ids.Empty, - NodeID: ids.EmptyNodeID, + ChainID: chainID, + NodeID: ids.GenerateTestNodeID(), + XChainID: testXChainID, + CChainID: testCChainID, NetworkUpgrades: upgradetest.GetConfig(upgradetest.Latest), PublicKey: pk, + WarpSigner: warp.NewSigner(sk, networkID, chainID), Log: logging.NoLog{}, BCLookup: ids.NewAliaser(), Metrics: metrics.NewPrefixGatherer(), ChainDataDir: "", - ValidatorState: &validatorstest.State{}, + ValidatorState: NewTestValidatorState(), + } + + aliaser := ctx.BCLookup.(ids.Aliaser) + _ = aliaser.Alias(testCChainID, "C") + _ = aliaser.Alias(testCChainID, testCChainID.String()) + _ = aliaser.Alias(testXChainID, "X") + _ = aliaser.Alias(testXChainID, testXChainID.String()) + + return ctx +} + +func NewTestValidatorState() *validatorstest.State { + return &validatorstest.State{ + GetCurrentHeightF: func(context.Context) (uint64, error) { + return 0, nil + }, + GetSubnetIDF: func(_ context.Context, chainID ids.ID) (ids.ID, error) { + subnetID, ok := map[ids.ID]ids.ID{ + constants.PlatformChainID: constants.PrimaryNetworkID, + testXChainID: constants.PrimaryNetworkID, + testCChainID: constants.PrimaryNetworkID, + }[chainID] + if !ok { + return ids.Empty, errors.New("unknown chain") + } + return subnetID, nil + }, + GetValidatorSetF: func(context.Context, uint64, ids.ID) (map[ids.NodeID]*validators.GetValidatorOutput, error) { + return map[ids.NodeID]*validators.GetValidatorOutput{}, nil + }, + GetCurrentValidatorSetF: func(context.Context, ids.ID) (map[ids.ID]*validators.GetCurrentValidatorOutput, uint64, error) { + return map[ids.ID]*validators.GetCurrentValidatorOutput{}, 0, nil + }, } } diff --git a/vmerrs/vmerrs.go b/vmerrs/vmerrs.go index 7d32413ccd..77d9c0b56f 100644 --- a/vmerrs/vmerrs.go +++ b/vmerrs/vmerrs.go @@ -29,7 +29,7 @@ package vmerrs import ( "errors" - "github.com/ethereum/go-ethereum/core/vm" + "github.com/ava-labs/libevm/core/vm" ) // List evm execution errors diff --git a/warp/aggregator/aggregator.go b/warp/aggregator/aggregator.go index 7c76f74820..4fb743f698 100644 --- a/warp/aggregator/aggregator.go +++ b/warp/aggregator/aggregator.go @@ -7,7 +7,7 @@ import ( "context" "fmt" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/set" diff --git a/warp/aggregator/aggregator_test.go b/warp/aggregator/aggregator_test.go index a423f75b25..055d3edfa8 100644 --- a/warp/aggregator/aggregator_test.go +++ b/warp/aggregator/aggregator_test.go @@ -17,10 +17,10 @@ import ( avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" ) -func newValidator(t testing.TB, weight uint64) (*bls.SecretKey, *avalancheWarp.Validator) { - sk, err := bls.NewSecretKey() +func newValidator(t testing.TB, weight uint64) (bls.Signer, *avalancheWarp.Validator) { + sk, err := bls.NewSigner() require.NoError(t, err) - pk := bls.PublicFromSecretKey(sk) + pk := sk.PublicKey() return sk, &avalancheWarp.Validator{ PublicKey: pk, PublicKeyBytes: bls.PublicKeyToCompressedBytes(pk), @@ -43,17 +43,17 @@ func TestAggregateSignatures(t *testing.T) { vdr1sk, vdr1 := newValidator(t, vdrWeight) vdr2sk, vdr2 := newValidator(t, vdrWeight+1) vdr3sk, vdr3 := newValidator(t, vdrWeight-1) - sig1 := bls.Sign(vdr1sk, unsignedMsg.Bytes()) - sig2 := bls.Sign(vdr2sk, unsignedMsg.Bytes()) - sig3 := bls.Sign(vdr3sk, unsignedMsg.Bytes()) + sig1 := vdr1sk.Sign(unsignedMsg.Bytes()) + sig2 := vdr2sk.Sign(unsignedMsg.Bytes()) + sig3 := vdr3sk.Sign(unsignedMsg.Bytes()) vdrToSig := map[*avalancheWarp.Validator]*bls.Signature{ vdr1: sig1, vdr2: sig2, vdr3: sig3, } - nonVdrSk, err := bls.NewSecretKey() + nonVdrSk, err := bls.NewSigner() require.NoError(t, err) - nonVdrSig := bls.Sign(nonVdrSk, unsignedMsg.Bytes()) + nonVdrSig := nonVdrSk.Sign(unsignedMsg.Bytes()) vdrs := []*avalancheWarp.Validator{ { PublicKey: vdr1.PublicKey, @@ -230,7 +230,7 @@ func TestAggregateSignatures(t *testing.T) { expectedErr: nil, }, { - name: "early termination of signature fetching on parent context cancelation", + name: "early termination of signature fetching on parent context cancellation", contextWithCancelFunc: func() (context.Context, context.CancelFunc) { ctx, cancel := context.WithCancel(context.Background()) cancel() diff --git a/warp/aggregator/mock_signature_getter.go b/warp/aggregator/mock_signature_getter.go index 537e3ae2e1..c42f858ae8 100644 --- a/warp/aggregator/mock_signature_getter.go +++ b/warp/aggregator/mock_signature_getter.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ava-labs/subnet-evm/warp/aggregator (interfaces: SignatureGetter) +// Source: signature_getter.go +// +// Generated by this command: +// +// mockgen -package=aggregator -source=signature_getter.go -destination=mock_signature_getter.go -exclude_interfaces=NetworkClient +// // Package aggregator is a generated GoMock package. package aggregator @@ -18,6 +23,7 @@ import ( type MockSignatureGetter struct { ctrl *gomock.Controller recorder *MockSignatureGetterMockRecorder + isgomock struct{} } // MockSignatureGetterMockRecorder is the mock recorder for MockSignatureGetter. @@ -38,16 +44,16 @@ func (m *MockSignatureGetter) EXPECT() *MockSignatureGetterMockRecorder { } // GetSignature mocks base method. -func (m *MockSignatureGetter) GetSignature(arg0 context.Context, arg1 ids.NodeID, arg2 *warp.UnsignedMessage) (*bls.Signature, error) { +func (m *MockSignatureGetter) GetSignature(ctx context.Context, nodeID ids.NodeID, unsignedWarpMessage *warp.UnsignedMessage) (*bls.Signature, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSignature", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetSignature", ctx, nodeID, unsignedWarpMessage) ret0, _ := ret[0].(*bls.Signature) ret1, _ := ret[1].(error) return ret0, ret1 } // GetSignature indicates an expected call of GetSignature. -func (mr *MockSignatureGetterMockRecorder) GetSignature(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSignatureGetterMockRecorder) GetSignature(ctx, nodeID, unsignedWarpMessage any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSignature", reflect.TypeOf((*MockSignatureGetter)(nil).GetSignature), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSignature", reflect.TypeOf((*MockSignatureGetter)(nil).GetSignature), ctx, nodeID, unsignedWarpMessage) } diff --git a/warp/aggregator/mocks_generate_test.go b/warp/aggregator/mocks_generate_test.go new file mode 100644 index 0000000000..de176f9074 --- /dev/null +++ b/warp/aggregator/mocks_generate_test.go @@ -0,0 +1,3 @@ +package aggregator + +//go:generate go run go.uber.org/mock/mockgen -package=$GOPACKAGE -source=signature_getter.go -destination=mock_signature_getter.go -exclude_interfaces=NetworkClient diff --git a/warp/backend.go b/warp/backend.go index 6e1f6a9553..50cc6d6393 100644 --- a/warp/backend.go +++ b/warp/backend.go @@ -15,7 +15,8 @@ import ( "github.com/ava-labs/avalanchego/snow/consensus/snowman" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" - "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/libevm/log" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/interfaces" ) var ( @@ -56,6 +57,7 @@ type backend struct { db database.Database warpSigner avalancheWarp.Signer blockClient BlockClient + validatorReader interfaces.ValidatorReader signatureCache cache.Cacher[ids.ID, []byte] messageCache *cache.LRU[ids.ID, *avalancheWarp.UnsignedMessage] offchainAddressedCallMsgs map[ids.ID]*avalancheWarp.UnsignedMessage @@ -68,6 +70,7 @@ func NewBackend( sourceChainID ids.ID, warpSigner avalancheWarp.Signer, blockClient BlockClient, + validatorReader interfaces.ValidatorReader, db database.Database, signatureCache cache.Cacher[ids.ID, []byte], offchainMessages [][]byte, @@ -79,6 +82,7 @@ func NewBackend( warpSigner: warpSigner, blockClient: blockClient, signatureCache: signatureCache, + validatorReader: validatorReader, messageCache: &cache.LRU[ids.ID, *avalancheWarp.UnsignedMessage]{Size: messageCacheSize}, stats: newVerifierStats(), offchainAddressedCallMsgs: make(map[ids.ID]*avalancheWarp.UnsignedMessage), @@ -180,7 +184,7 @@ func (b *backend) GetMessage(messageID ids.ID) (*avalancheWarp.UnsignedMessage, unsignedMessageBytes, err := b.db.Get(messageID[:]) if err != nil { - return nil, fmt.Errorf("failed to get warp message %s from db: %w", messageID.String(), err) + return nil, err } unsignedMessage, err := avalancheWarp.ParseUnsignedMessage(unsignedMessageBytes) diff --git a/warp/backend_test.go b/warp/backend_test.go index cae9c14bc6..764957882c 100644 --- a/warp/backend_test.go +++ b/warp/backend_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/ava-labs/avalanchego/cache" + "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/database/memdb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils" @@ -40,11 +41,11 @@ func init() { func TestAddAndGetValidMessage(t *testing.T) { db := memdb.New() - sk, err := bls.NewSecretKey() + sk, err := bls.NewSigner() require.NoError(t, err) warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 500} - backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, messageSignatureCache, nil) + backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, warptest.NoOpValidatorReader{}, db, messageSignatureCache, nil) require.NoError(t, err) // Add testUnsignedMessage to the warp backend @@ -63,11 +64,11 @@ func TestAddAndGetValidMessage(t *testing.T) { func TestAddAndGetUnknownMessage(t *testing.T) { db := memdb.New() - sk, err := bls.NewSecretKey() + sk, err := bls.NewSigner() require.NoError(t, err) warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 500} - backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, messageSignatureCache, nil) + backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, warptest.NoOpValidatorReader{}, db, messageSignatureCache, nil) require.NoError(t, err) // Try getting a signature for a message that was not added. @@ -82,11 +83,11 @@ func TestGetBlockSignature(t *testing.T) { blockClient := warptest.MakeBlockClient(blkID) db := memdb.New() - sk, err := bls.NewSecretKey() + sk, err := bls.NewSigner() require.NoError(err) warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 500} - backend, err := NewBackend(networkID, sourceChainID, warpSigner, blockClient, db, messageSignatureCache, nil) + backend, err := NewBackend(networkID, sourceChainID, warpSigner, blockClient, warptest.NoOpValidatorReader{}, db, messageSignatureCache, nil) require.NoError(err) blockHashPayload, err := payload.NewHash(blkID) @@ -107,13 +108,13 @@ func TestGetBlockSignature(t *testing.T) { func TestZeroSizedCache(t *testing.T) { db := memdb.New() - sk, err := bls.NewSecretKey() + sk, err := bls.NewSigner() require.NoError(t, err) warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) // Verify zero sized cache works normally, because the lru cache will be initialized to size 1 for any size parameter <= 0. messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 0} - backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, messageSignatureCache, nil) + backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, warptest.NoOpValidatorReader{}, db, messageSignatureCache, nil) require.NoError(t, err) // Add testUnsignedMessage to the warp backend @@ -135,7 +136,7 @@ func TestOffChainMessages(t *testing.T) { check func(require *require.Assertions, b Backend) err error } - sk, err := bls.NewSecretKey() + sk, err := bls.NewSigner() require.NoError(t, err) warpSigner := avalancheWarp.NewSigner(sk, networkID, sourceChainID) @@ -157,6 +158,12 @@ func TestOffChainMessages(t *testing.T) { require.Equal(expectedSignatureBytes, signature[:]) }, }, + "unknown message": { + check: func(require *require.Assertions, b Backend) { + _, err := b.GetMessage(testUnsignedMessage.ID()) + require.ErrorIs(err, database.ErrNotFound) + }, + }, "invalid message": { offchainMessages: [][]byte{{1, 2, 3}}, err: errParsingOffChainMessage, @@ -167,7 +174,7 @@ func TestOffChainMessages(t *testing.T) { db := memdb.New() messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 0} - backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, db, messageSignatureCache, test.offchainMessages) + backend, err := NewBackend(networkID, sourceChainID, warpSigner, nil, warptest.NoOpValidatorReader{}, db, messageSignatureCache, test.offchainMessages) require.ErrorIs(err, test.err) if test.check != nil { test.check(require, backend) diff --git a/warp/client.go b/warp/client.go index 3554536482..b533b4c453 100644 --- a/warp/client.go +++ b/warp/client.go @@ -8,8 +8,8 @@ import ( "fmt" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/subnet-evm/rpc" - "github.com/ethereum/go-ethereum/common/hexutil" ) var _ Client = (*client)(nil) diff --git a/warp/handlers/signature_request.go b/warp/handlers/signature_request.go index 4b8b76c565..a8bc53b7b8 100644 --- a/warp/handlers/signature_request.go +++ b/warp/handlers/signature_request.go @@ -10,9 +10,9 @@ import ( "github.com/ava-labs/avalanchego/codec" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/warp" - "github.com/ethereum/go-ethereum/log" ) // SignatureRequestHandler serves warp signature requests. It is a peer.RequestHandler for message.MessageSignatureRequest. diff --git a/warp/handlers/signature_request_test.go b/warp/handlers/signature_request_test.go index 3189478106..ac2a364a78 100644 --- a/warp/handlers/signature_request_test.go +++ b/warp/handlers/signature_request_test.go @@ -23,7 +23,7 @@ import ( func TestMessageSignatureHandler(t *testing.T) { database := memdb.New() snowCtx := utils.TestSnowContext() - blsSecretKey, err := bls.NewSecretKey() + blsSecretKey, err := bls.NewSigner() require.NoError(t, err) warpSigner := avalancheWarp.NewSigner(blsSecretKey, snowCtx.NetworkID, snowCtx.ChainID) @@ -33,7 +33,7 @@ func TestMessageSignatureHandler(t *testing.T) { require.NoError(t, err) messageSignatureCache := &cache.LRU[ids.ID, []byte]{Size: 100} - backend, err := warp.NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, database, messageSignatureCache, [][]byte{offchainMessage.Bytes()}) + backend, err := warp.NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, warptest.NoOpValidatorReader{}, database, messageSignatureCache, [][]byte{offchainMessage.Bytes()}) require.NoError(t, err) msg, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, []byte("test")) @@ -127,7 +127,7 @@ func TestMessageSignatureHandler(t *testing.T) { func TestBlockSignatureHandler(t *testing.T) { database := memdb.New() snowCtx := utils.TestSnowContext() - blsSecretKey, err := bls.NewSecretKey() + blsSecretKey, err := bls.NewSigner() require.NoError(t, err) warpSigner := avalancheWarp.NewSigner(blsSecretKey, snowCtx.NetworkID, snowCtx.ChainID) @@ -139,6 +139,7 @@ func TestBlockSignatureHandler(t *testing.T) { snowCtx.ChainID, warpSigner, blockClient, + warptest.NoOpValidatorReader{}, database, messageSignatureCache, nil, diff --git a/warp/messages/payload.go b/warp/messages/payload.go index 3776a1356d..facf54524d 100644 --- a/warp/messages/payload.go +++ b/warp/messages/payload.go @@ -20,12 +20,6 @@ type Payload interface { initialize(b []byte) } -// Signable is an optional interface that payloads can implement to allow -// on-the-fly signing of incoming messages by the warp backend. -type Signable interface { - VerifyMesssage(sourceAddress []byte) error -} - func Parse(bytes []byte) (Payload, error) { var payload Payload if _, err := Codec.Unmarshal(bytes, &payload); err != nil { diff --git a/warp/messages/validator_uptime.go b/warp/messages/validator_uptime.go index 3d3e4dd5dd..cd14b39538 100644 --- a/warp/messages/validator_uptime.go +++ b/warp/messages/validator_uptime.go @@ -13,7 +13,7 @@ import ( // has been up for TotalUptime seconds. type ValidatorUptime struct { ValidationID ids.ID `serialize:"true"` - TotalUptime uint64 `serialize:"true"` + TotalUptime uint64 `serialize:"true"` // in seconds bytes []byte } diff --git a/warp/service.go b/warp/service.go index bcb54ccbbc..f26a0171b5 100644 --- a/warp/service.go +++ b/warp/service.go @@ -12,11 +12,11 @@ import ( "github.com/ava-labs/avalanchego/snow/validators" "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/libevm/common/hexutil" + "github.com/ava-labs/libevm/log" "github.com/ava-labs/subnet-evm/peer" "github.com/ava-labs/subnet-evm/warp/aggregator" warpValidators "github.com/ava-labs/subnet-evm/warp/validators" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/log" ) var errNoValidators = errors.New("cannot aggregate signatures from subnet with no validators") diff --git a/warp/verifier_backend.go b/warp/verifier_backend.go index c70563c585..255851d601 100644 --- a/warp/verifier_backend.go +++ b/warp/verifier_backend.go @@ -7,6 +7,9 @@ import ( "context" "fmt" + "github.com/ava-labs/subnet-evm/warp/messages" + + "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/snow/engine/common" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" @@ -24,6 +27,11 @@ func (b *backend) Verify(ctx context.Context, unsignedMessage *avalancheWarp.Uns // Known on-chain messages should be signed if _, err := b.GetMessage(messageID); err == nil { return nil + } else if err != database.ErrNotFound { + return &common.AppError{ + Code: ParseErrCode, + Message: fmt.Sprintf("failed to get message %s: %s", messageID, err.Error()), + } } parsed, err := payload.Parse(unsignedMessage.Payload) @@ -36,6 +44,8 @@ func (b *backend) Verify(ctx context.Context, unsignedMessage *avalancheWarp.Uns } switch p := parsed.(type) { + case *payload.AddressedCall: + return b.verifyOffchainAddressedCall(p) case *payload.Hash: return b.verifyBlockMessage(ctx, p) default: @@ -53,7 +63,7 @@ func (b *backend) verifyBlockMessage(ctx context.Context, blockHashPayload *payl blockID := blockHashPayload.Hash _, err := b.blockClient.GetAcceptedBlock(ctx, blockID) if err != nil { - b.stats.IncBlockSignatureValidationFail() + b.stats.IncBlockValidationFail() return &common.AppError{ Code: VerifyErrCode, Message: fmt.Sprintf("failed to get block %s: %s", blockID, err.Error()), @@ -62,3 +72,60 @@ func (b *backend) verifyBlockMessage(ctx context.Context, blockHashPayload *payl return nil } + +// verifyOffchainAddressedCall verifies the addressed call message +func (b *backend) verifyOffchainAddressedCall(addressedCall *payload.AddressedCall) *common.AppError { + // Further, parse the payload to see if it is a known type. + parsed, err := messages.Parse(addressedCall.Payload) + if err != nil { + b.stats.IncMessageParseFail() + return &common.AppError{ + Code: ParseErrCode, + Message: "failed to parse addressed call message: " + err.Error(), + } + } + + if len(addressedCall.SourceAddress) != 0 { + return &common.AppError{ + Code: VerifyErrCode, + Message: "source address should be empty for offchain addressed messages", + } + } + + switch p := parsed.(type) { + case *messages.ValidatorUptime: + if err := b.verifyUptimeMessage(p); err != nil { + b.stats.IncUptimeValidationFail() + return err + } + default: + b.stats.IncMessageParseFail() + return &common.AppError{ + Code: ParseErrCode, + Message: fmt.Sprintf("unknown message type: %T", p), + } + } + + return nil +} + +func (b *backend) verifyUptimeMessage(uptimeMsg *messages.ValidatorUptime) *common.AppError { + vdr, currentUptime, _, err := b.validatorReader.GetValidatorAndUptime(uptimeMsg.ValidationID) + if err != nil { + return &common.AppError{ + Code: VerifyErrCode, + Message: fmt.Sprintf("failed to get uptime for validationID %s: %s", uptimeMsg.ValidationID, err.Error()), + } + } + + currentUptimeSeconds := uint64(currentUptime.Seconds()) + // verify the current uptime against the total uptime in the message + if currentUptimeSeconds < uptimeMsg.TotalUptime { + return &common.AppError{ + Code: VerifyErrCode, + Message: fmt.Sprintf("current uptime %d is less than queried uptime %d for nodeID %s", currentUptimeSeconds, uptimeMsg.TotalUptime, vdr.NodeID), + } + } + + return nil +} diff --git a/warp/verifier_backend_test.go b/warp/verifier_backend_test.go index 54fd8dbf19..d58e9e6c90 100644 --- a/warp/verifier_backend_test.go +++ b/warp/verifier_backend_test.go @@ -15,9 +15,13 @@ import ( "github.com/ava-labs/avalanchego/proto/pb/sdk" "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/avalanchego/utils/timer/mockable" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/subnet-evm/plugin/evm/validators" + stateinterfaces "github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces" "github.com/ava-labs/subnet-evm/utils" + "github.com/ava-labs/subnet-evm/warp/messages" "github.com/ava-labs/subnet-evm/warp/warptest" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" @@ -26,7 +30,7 @@ import ( func TestAddressedCallSignatures(t *testing.T) { database := memdb.New() snowCtx := utils.TestSnowContext() - blsSecretKey, err := bls.NewSecretKey() + blsSecretKey, err := bls.NewSigner() require.NoError(t, err) warpSigner := avalancheWarp.NewSigner(blsSecretKey, snowCtx.NetworkID, snowCtx.ChainID) @@ -56,7 +60,7 @@ func TestAddressedCallSignatures(t *testing.T) { }, verifyStats: func(t *testing.T, stats *verifierStats) { require.EqualValues(t, 0, stats.messageParseFail.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockValidationFail.Snapshot().Count()) }, }, "offchain message": { @@ -65,7 +69,7 @@ func TestAddressedCallSignatures(t *testing.T) { }, verifyStats: func(t *testing.T, stats *verifierStats) { require.EqualValues(t, 0, stats.messageParseFail.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockValidationFail.Snapshot().Count()) }, }, "unknown message": { @@ -78,7 +82,7 @@ func TestAddressedCallSignatures(t *testing.T) { }, verifyStats: func(t *testing.T, stats *verifierStats) { require.EqualValues(t, 1, stats.messageParseFail.Snapshot().Count()) - require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockValidationFail.Snapshot().Count()) }, err: &common.AppError{Code: ParseErrCode}, }, @@ -98,7 +102,7 @@ func TestAddressedCallSignatures(t *testing.T) { } else { sigCache = &cache.Empty[ids.ID, []byte]{} } - warpBackend, err := NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, database, sigCache, [][]byte{offchainMessage.Bytes()}) + warpBackend, err := NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, warptest.NoOpValidatorReader{}, database, sigCache, [][]byte{offchainMessage.Bytes()}) require.NoError(t, err) handler := acp118.NewCachedHandler(sigCache, warpBackend, warpSigner) @@ -140,7 +144,7 @@ func TestAddressedCallSignatures(t *testing.T) { func TestBlockSignatures(t *testing.T) { database := memdb.New() snowCtx := utils.TestSnowContext() - blsSecretKey, err := bls.NewSecretKey() + blsSecretKey, err := bls.NewSigner() require.NoError(t, err) warpSigner := avalancheWarp.NewSigner(blsSecretKey, snowCtx.NetworkID, snowCtx.ChainID) @@ -177,7 +181,7 @@ func TestBlockSignatures(t *testing.T) { return toMessageBytes(knownBlkID), signature[:] }, verifyStats: func(t *testing.T, stats *verifierStats) { - require.EqualValues(t, 0, stats.blockSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 0, stats.blockValidationFail.Snapshot().Count()) require.EqualValues(t, 0, stats.messageParseFail.Snapshot().Count()) }, }, @@ -187,7 +191,7 @@ func TestBlockSignatures(t *testing.T) { return toMessageBytes(unknownBlockID), nil }, verifyStats: func(t *testing.T, stats *verifierStats) { - require.EqualValues(t, 1, stats.blockSignatureValidationFail.Snapshot().Count()) + require.EqualValues(t, 1, stats.blockValidationFail.Snapshot().Count()) require.EqualValues(t, 0, stats.messageParseFail.Snapshot().Count()) }, err: &common.AppError{Code: VerifyErrCode}, @@ -213,6 +217,7 @@ func TestBlockSignatures(t *testing.T) { snowCtx.ChainID, warpSigner, blockClient, + warptest.NoOpValidatorReader{}, database, sigCache, nil, @@ -253,3 +258,90 @@ func TestBlockSignatures(t *testing.T) { } } } + +func TestUptimeSignatures(t *testing.T) { + database := memdb.New() + snowCtx := utils.TestSnowContext() + blsSecretKey, err := bls.NewSigner() + require.NoError(t, err) + warpSigner := avalancheWarp.NewSigner(blsSecretKey, snowCtx.NetworkID, snowCtx.ChainID) + + getUptimeMessageBytes := func(sourceAddress []byte, vID ids.ID, totalUptime uint64) ([]byte, *avalancheWarp.UnsignedMessage) { + uptimePayload, err := messages.NewValidatorUptime(vID, 80) + require.NoError(t, err) + addressedCall, err := payload.NewAddressedCall(sourceAddress, uptimePayload.Bytes()) + require.NoError(t, err) + unsignedMessage, err := avalancheWarp.NewUnsignedMessage(snowCtx.NetworkID, snowCtx.ChainID, addressedCall.Bytes()) + require.NoError(t, err) + + protoMsg := &sdk.SignatureRequest{Message: unsignedMessage.Bytes()} + protoBytes, err := proto.Marshal(protoMsg) + require.NoError(t, err) + return protoBytes, unsignedMessage + } + + for _, withCache := range []bool{true, false} { + var sigCache cache.Cacher[ids.ID, []byte] + if withCache { + sigCache = &cache.LRU[ids.ID, []byte]{Size: 100} + } else { + sigCache = &cache.Empty[ids.ID, []byte]{} + } + chainCtx := utils.TestSnowContext() + clk := &mockable.Clock{} + validatorsManager, err := validators.NewManager(chainCtx, memdb.New(), clk) + require.NoError(t, err) + validatorsManager.StartTracking([]ids.NodeID{}) + warpBackend, err := NewBackend(snowCtx.NetworkID, snowCtx.ChainID, warpSigner, warptest.EmptyBlockClient, validatorsManager, database, sigCache, nil) + require.NoError(t, err) + handler := acp118.NewCachedHandler(sigCache, warpBackend, warpSigner) + + // sourceAddress nonZero + protoBytes, _ := getUptimeMessageBytes([]byte{1, 2, 3}, ids.GenerateTestID(), 80) + _, appErr := handler.AppRequest(context.Background(), ids.GenerateTestNodeID(), time.Time{}, protoBytes) + require.ErrorIs(t, appErr, &common.AppError{Code: VerifyErrCode}) + require.Contains(t, appErr.Error(), "source address should be empty") + + // not existing validationID + vID := ids.GenerateTestID() + protoBytes, _ = getUptimeMessageBytes([]byte{}, vID, 80) + _, appErr = handler.AppRequest(context.Background(), ids.GenerateTestNodeID(), time.Time{}, protoBytes) + require.ErrorIs(t, appErr, &common.AppError{Code: VerifyErrCode}) + require.Contains(t, appErr.Error(), "failed to get validator") + + // uptime is less than requested (not connected) + validationID := ids.GenerateTestID() + nodeID := ids.GenerateTestNodeID() + require.NoError(t, validatorsManager.AddValidator(stateinterfaces.Validator{ + ValidationID: validationID, + NodeID: nodeID, + Weight: 1, + StartTimestamp: clk.Unix(), + IsActive: true, + IsL1Validator: true, + })) + protoBytes, _ = getUptimeMessageBytes([]byte{}, validationID, 80) + _, appErr = handler.AppRequest(context.Background(), nodeID, time.Time{}, protoBytes) + require.ErrorIs(t, appErr, &common.AppError{Code: VerifyErrCode}) + require.Contains(t, appErr.Error(), "current uptime 0 is less than queried uptime 80") + + // uptime is less than requested (not enough) + require.NoError(t, validatorsManager.Connect(nodeID)) + clk.Set(clk.Time().Add(40 * time.Second)) + protoBytes, _ = getUptimeMessageBytes([]byte{}, validationID, 80) + _, appErr = handler.AppRequest(context.Background(), nodeID, time.Time{}, protoBytes) + require.ErrorIs(t, appErr, &common.AppError{Code: VerifyErrCode}) + require.Contains(t, appErr.Error(), "current uptime 40 is less than queried uptime 80") + + // valid uptime + clk.Set(clk.Time().Add(40 * time.Second)) + protoBytes, msg := getUptimeMessageBytes([]byte{}, validationID, 80) + responseBytes, appErr := handler.AppRequest(context.Background(), nodeID, time.Time{}, protoBytes) + require.Nil(t, appErr) + expectedSignature, err := warpSigner.Sign(msg) + require.NoError(t, err) + response := &sdk.SignatureResponse{} + require.NoError(t, proto.Unmarshal(responseBytes, response)) + require.Equal(t, expectedSignature[:], response.Signature) + } +} diff --git a/warp/verifier_stats.go b/warp/verifier_stats.go index bc56d725a5..d1ef62a50f 100644 --- a/warp/verifier_stats.go +++ b/warp/verifier_stats.go @@ -9,21 +9,35 @@ import ( type verifierStats struct { messageParseFail metrics.Counter + // AddressedCall metrics + addressedCallValidationFail metrics.Counter // BlockRequest metrics - blockSignatureValidationFail metrics.Counter + blockValidationFail metrics.Counter + // Uptime metrics + uptimeValidationFail metrics.Counter } func newVerifierStats() *verifierStats { return &verifierStats{ - messageParseFail: metrics.NewRegisteredCounter("message_parse_fail", nil), - blockSignatureValidationFail: metrics.NewRegisteredCounter("block_signature_validation_fail", nil), + messageParseFail: metrics.NewRegisteredCounter("warp_backend_message_parse_fail", nil), + addressedCallValidationFail: metrics.NewRegisteredCounter("warp_backend_addressed_call_validation_fail", nil), + blockValidationFail: metrics.NewRegisteredCounter("warp_backend_block_validation_fail", nil), + uptimeValidationFail: metrics.NewRegisteredCounter("warp_backend_uptime_validation_fail", nil), } } -func (h *verifierStats) IncBlockSignatureValidationFail() { - h.blockSignatureValidationFail.Inc(1) +func (h *verifierStats) IncAddressedCallValidationFail() { + h.addressedCallValidationFail.Inc(1) +} + +func (h *verifierStats) IncBlockValidationFail() { + h.blockValidationFail.Inc(1) } func (h *verifierStats) IncMessageParseFail() { h.messageParseFail.Inc(1) } + +func (h *verifierStats) IncUptimeValidationFail() { + h.uptimeValidationFail.Inc(1) +} diff --git a/warp/warptest/noop_validator_reader.go b/warp/warptest/noop_validator_reader.go new file mode 100644 index 0000000000..03171f84f5 --- /dev/null +++ b/warp/warptest/noop_validator_reader.go @@ -0,0 +1,21 @@ +// (c) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// warptest exposes common functionality for testing the warp package. +package warptest + +import ( + "time" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/subnet-evm/plugin/evm/validators/interfaces" + stateinterfaces "github.com/ava-labs/subnet-evm/plugin/evm/validators/state/interfaces" +) + +var _ interfaces.ValidatorReader = &NoOpValidatorReader{} + +type NoOpValidatorReader struct{} + +func (NoOpValidatorReader) GetValidatorAndUptime(ids.ID) (stateinterfaces.Validator, time.Duration, time.Time, error) { + return stateinterfaces.Validator{}, 0, time.Time{}, nil +}