diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 70fb9d3b24..951ebebb5e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -97,7 +97,7 @@ jobs: - name: Setup Contracts run: ./scripts/run_task.sh setup-contracts - name: Run Warp E2E Tests - uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@84e9aebcfbc04602865f4c0a3e8b46a27409a3f5 + uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@fff1df9564d3fa86899780d73e887d9ee5b9b54e with: run: ./scripts/run_task.sh test-e2e-warp-ci artifact_prefix: warp @@ -122,7 +122,7 @@ jobs: with: go-version-file: "go.mod" - name: Run E2E Load Tests - uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@84e9aebcfbc04602865f4c0a3e8b46a27409a3f5 + uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@fff1df9564d3fa86899780d73e887d9ee5b9b54e with: run: ./scripts/run_task.sh test-e2e-load-ci artifact_prefix: load diff --git a/Dockerfile b/Dockerfile index 81e752a248..d711000028 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,23 +4,35 @@ ARG AVALANCHEGO_NODE_IMAGE="invalid-image" # ============= Compilation Stage ================ -FROM --platform=$BUILDPLATFORM golang:1.24.7-bookworm AS builder +FROM --platform=$BUILDPLATFORM golang:1.24.8-bookworm AS builder WORKDIR /build -# Copy avalanche dependencies first (intermediate docker image caching) -# Copy avalanchego directory if present (for manual CI case, which uses local dependency) -COPY go.mod go.sum avalanchego* ./ -# Download avalanche dependencies using go mod -RUN go mod download && go mod tidy +# Copy module files first (improves Docker layer caching) +COPY go.mod go.sum ./ +# Download module dependencies +RUN go mod download # Copy the code into the container COPY . . +# Ensure we never keep a stale local replace when no local module is present +RUN go mod edit -dropreplace github.com/ava-labs/avalanchego || true + +# If a local avalanchego source dir is present, move it outside the module tree. +# Only add a replace if the moved directory is a standalone module with go.mod, +# otherwise drop any existing replace so upstream is used. +RUN if [ -d ./avalanchego ]; then \ + mkdir -p /third_party && mv ./avalanchego /third_party/avalanchego; \ + if [ -f /third_party/avalanchego/go.mod ]; then \ + go mod edit -replace github.com/ava-labs/avalanchego=/third_party/avalanchego; \ + go mod tidy; \ + fi; \ +fi + # Ensure pre-existing builds are not available for inclusion in the final image RUN [ -d ./build ] && rm -rf ./build/* || true - ARG TARGETPLATFORM ARG BUILDPLATFORM diff --git a/compatibility.json b/compatibility.json index d62309fe03..43077e7bd3 100644 --- a/compatibility.json +++ b/compatibility.json @@ -1,15 +1,15 @@ { "rpcChainVMProtocolVersion": { + "v0.7.0": 38, + "v0.7.1": 39, "v0.7.10": 43, - "v0.7.9": 43, - "v0.7.8": 43, - "v0.7.7": 42, - "v0.7.6": 42, - "v0.7.5": 41, - "v0.7.4": 40, - "v0.7.3": 39, "v0.7.2": 39, - "v0.7.1": 39, - "v0.7.0": 38 + "v0.7.3": 39, + "v0.7.4": 40, + "v0.7.5": 41, + "v0.7.6": 42, + "v0.7.7": 42, + "v0.7.8": 43, + "v0.7.9": 43 } -} \ No newline at end of file +} diff --git a/core/bench_test.go b/core/bench_test.go index f4e8b0e5a6..4d2a858072 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -32,6 +32,7 @@ import ( "math/big" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/math" "github.com/ava-labs/libevm/core/rawdb" @@ -42,7 +43,6 @@ import ( ethparams "github.com/ava-labs/libevm/params" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" ) func BenchmarkInsertChain_empty_memdb(b *testing.B) { @@ -253,7 +253,8 @@ func makeChainForBench(db ethdb.Database, genesis *Genesis, full bool, count uin rawdb.WriteCanonicalHash(db, hash, n) if n == 0 { - customrawdb.WriteChainConfig(db, hash, genesis.Config) + extra := params.GetExtra(genesis.Config) + customrawdb.WriteChainConfig(db, hash, genesis.Config, *extra) } rawdb.WriteHeadHeaderHash(db, hash) diff --git a/core/blockchain.go b/core/blockchain.go index 6793640e60..057614e3e3 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -41,6 +41,7 @@ import ( "sync/atomic" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/lru" "github.com/ava-labs/libevm/consensus/misc/eip4844" @@ -61,7 +62,6 @@ import ( "github.com/ava-labs/subnet-evm/internal/version" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/plugin/evm/customlogs" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" "github.com/ava-labs/subnet-evm/triedb/firewood" "github.com/ava-labs/subnet-evm/triedb/hashdb" diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 244dc9d4e6..5a1496325a 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -35,6 +35,7 @@ import ( "math/big" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" @@ -44,7 +45,6 @@ import ( "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/stretchr/testify/require" ) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 12d55c8c81..0c44c0abfc 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/ava-labs/avalanchego/upgrade" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" @@ -22,7 +23,6 @@ import ( "github.com/ava-labs/subnet-evm/core/state/pruner" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/params/extras" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/upgrade/legacy" ethparams "github.com/ava-labs/libevm/params" diff --git a/core/genesis.go b/core/genesis.go index 00d9763ba6..93f4a43563 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -32,8 +32,10 @@ import ( "errors" "fmt" "math/big" + "strings" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/libevm/common/math" @@ -49,7 +51,6 @@ import ( "github.com/ava-labs/libevm/triedb" "github.com/ava-labs/subnet-evm/core/extstate" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" "github.com/ava-labs/subnet-evm/plugin/evm/upgrade/legacy" "github.com/ava-labs/subnet-evm/triedb/pathdb" @@ -177,17 +178,23 @@ func SetupGenesisBlock( return genesis.Config, common.Hash{}, &GenesisMismatchError{stored, hash} } // Get the existing chain configuration. - newcfg := genesis.Config - if err := newcfg.CheckConfigForkOrder(); err != nil { - return newcfg, common.Hash{}, err + newCfg := genesis.Config + if err := newCfg.CheckConfigForkOrder(); err != nil { + return newCfg, common.Hash{}, err } - storedcfg := customrawdb.ReadChainConfig(db, stored) + + // Read stored config into a local extras copy to avoid mutating the + // caller's attached extras (which may be concurrently accessed in tests). + // We'll persist the new config (including upgrade bytes) using the attached + // extras below to ensure on-disk state is up to date. + readExtra := *params.GetExtra(newCfg) + storedCfg := customrawdb.ReadChainConfig(db, stored, &readExtra) // If there is no previously stored chain config, write the chain config to disk. - if storedcfg == nil { + if storedCfg == nil { // Note: this can happen since we did not previously write the genesis block and chain config in the same batch. log.Warn("Found genesis block without chain config") - customrawdb.WriteChainConfig(db, stored, newcfg) - return newcfg, stored, nil + customrawdb.WriteChainConfig(db, stored, newCfg, *params.GetExtra(newCfg)) + return newCfg, stored, nil } // Notes on the following line: @@ -195,7 +202,7 @@ func SetupGenesisBlock( // have the Berlin or London forks initialized by block number on disk. // See https://github.com/ava-labs/coreth/pull/667/files // - this is not needed in subnet-evm but it does not impact it either - if err := params.SetEthUpgrades(storedcfg); err != nil { + if err := params.SetEthUpgrades(storedCfg); err != nil { return genesis.Config, common.Hash{}, err } // Check config compatibility and write the config. Compatibility errors @@ -208,25 +215,31 @@ func SetupGenesisBlock( // when we start syncing from scratch, the last accepted block // will be genesis block if lastBlock == nil { - return newcfg, common.Hash{}, errors.New("missing last accepted block") + return newCfg, common.Hash{}, errors.New("missing last accepted block") } height := lastBlock.NumberU64() timestamp := lastBlock.Time() - if skipChainConfigCheckCompatible { - log.Info("skipping verifying activated network upgrades on chain config") - } else { - compatErr := storedcfg.CheckCompatible(newcfg, height, timestamp) - if compatErr != nil && ((height != 0 && compatErr.RewindToBlock != 0) || (timestamp != 0 && compatErr.RewindToTime != 0)) { - storedData, _ := params.ToWithUpgradesJSON(storedcfg).MarshalJSON() - newData, _ := params.ToWithUpgradesJSON(newcfg).MarshalJSON() - log.Error("found mismatch between config on database vs. new config", "storedConfig", string(storedData), "newConfig", string(newData), "err", compatErr) - return newcfg, stored, compatErr + + // If the chain hasn't advanced past genesis (height 0), persist the new + // chain config (including upgrade bytes) before compatibility checks so + // subsequent restarts see the updated upgrades and do not flag them as + // retroactive enables. + if height == 0 { + storedCfg = persistChainConfigAndReload(db, stored, newCfg) + } + + if !skipChainConfigCheckCompatible { + if _, err := reconcileCompatibility(db, stored, storedCfg, newCfg, height, timestamp); err != nil { + logCompatibilityMismatch(storedCfg, newCfg, err) + return newCfg, stored, err } + } else { + log.Info("skipping verifying activated network upgrades on chain config") } - // Required to write the chain config to disk to ensure both the chain config and upgrade bytes are persisted to disk. - // Note: this intentionally removes an extra check from upstream. - customrawdb.WriteChainConfig(db, stored, newcfg) - return newcfg, stored, nil + + // Persist the new chain config (including upgrade bytes) now that compatibility is verified. + customrawdb.WriteChainConfig(db, stored, newCfg, *params.GetExtra(newCfg)) + return newCfg, stored, nil } // IsVerkle indicates whether the state is already stored in a verkle @@ -401,7 +414,9 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64()) rawdb.WriteHeadBlockHash(batch, block.Hash()) rawdb.WriteHeadHeaderHash(batch, block.Hash()) - customrawdb.WriteChainConfig(batch, block.Hash(), config) + + extra := params.GetExtra(config) + customrawdb.WriteChainConfig(batch, block.Hash(), config, *extra) if err := batch.Write(); err != nil { return nil, fmt.Errorf("failed to write genesis block: %w", err) } @@ -453,3 +468,54 @@ func ReadBlockByHash(db ethdb.Reader, hash common.Hash) *types.Block { } return rawdb.ReadBlock(db, hash, *blockNumber) } + +// reconcileCompatibility checks compatibility between the stored and new chain configs. +// If the only incompatibility is missing precompile upgrade metadata, it persists the +// new config (including upgrade bytes) and returns a refreshed stored config view. +// Otherwise, it returns the compatibility error. +func reconcileCompatibility( + db ethdb.Database, + genesisHash common.Hash, + storedCfg *params.ChainConfig, + newCfg *params.ChainConfig, + height uint64, + timestamp uint64, +) (*params.ChainConfig, error) { + compatErr := storedCfg.CheckCompatible(newCfg, height, timestamp) + needsRewind := compatErr != nil && ((height != 0 && compatErr.RewindToBlock != 0) || (timestamp != 0 && compatErr.RewindToTime != 0)) + if !needsRewind { + return storedCfg, nil + } + if !isPrecompileUpgradeOnlyIncompatibility(compatErr) { + return nil, compatErr + } + // Only precompile upgrade metadata differs: write upgrades and proceed. + refreshed := persistChainConfigAndReload(db, genesisHash, newCfg) + return refreshed, nil +} + +// persistChainConfigAndReload writes the provided chain config (including upgrade bytes) +// and returns a fresh view of the stored config using a separate extras copy. +func persistChainConfigAndReload(db ethdb.Database, genesisHash common.Hash, cfg *params.ChainConfig) *params.ChainConfig { + customrawdb.WriteChainConfig(db, genesisHash, cfg, *params.GetExtra(cfg)) + refreshedExtra := *params.GetExtra(cfg) + return customrawdb.ReadChainConfig(db, genesisHash, &refreshedExtra) +} + +// isPrecompileUpgradeOnlyIncompatibility returns true if the compatibility error +// pertains exclusively to precompile upgrade activation metadata being absent on disk. +// In such cases, persisting the new chain config (including upgrade bytes) resolves +// the mismatch without requiring a rewind. +func isPrecompileUpgradeOnlyIncompatibility(err *ethparams.ConfigCompatError) bool { + if err == nil { + return false + } + return strings.Contains(err.What, "PrecompileUpgrade[") +} + +// logCompatibilityMismatch emits a structured error comparing stored and new configs. +func logCompatibilityMismatch(storedCfg, newCfg *params.ChainConfig, err error) { + storedData, _ := params.ToWithUpgradesJSON(storedCfg).MarshalJSON() + newData, _ := params.ToWithUpgradesJSON(newCfg).MarshalJSON() + log.Error("found mismatch between config on database vs. new config", "storedConfig", string(storedData), "newConfig", string(newData), "err", err) +} diff --git a/core/genesis_test.go b/core/genesis_test.go index dc9d5d8cfc..a8bba522a8 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -36,6 +36,7 @@ import ( "reflect" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/state" @@ -48,7 +49,6 @@ import ( "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/params/extras" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/upgrade/legacy" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/contracts/deployerallowlist" diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 7853eb0618..7b72e38b0c 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -38,6 +38,7 @@ import ( "strings" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" @@ -47,7 +48,6 @@ import ( "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/plugin/evm/customrawdb" ) const ( diff --git a/core/state/snapshot/disklayer_test.go b/core/state/snapshot/disklayer_test.go index 7ce7d06d8c..73545d9c1b 100644 --- a/core/state/snapshot/disklayer_test.go +++ b/core/state/snapshot/disklayer_test.go @@ -31,11 +31,11 @@ import ( "bytes" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/ethdb/memorydb" "github.com/ava-labs/libevm/rlp" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" ) // reverse reverses the contents of a byte slice. It's used to update random accs diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index c28caca00b..3520649067 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -32,6 +32,7 @@ import ( "fmt" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" @@ -40,7 +41,6 @@ import ( "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/libevm/trie" "github.com/ava-labs/libevm/triedb" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/utils" ) diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index bfc987a17d..f2c3e57a3b 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -33,13 +33,13 @@ import ( "fmt" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "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/plugin/evm/customrawdb" ) // 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 148c641e16..dc66972d5a 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -35,6 +35,7 @@ import ( "sync" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" ethsnapshot "github.com/ava-labs/libevm/core/state/snapshot" @@ -43,7 +44,6 @@ import ( "github.com/ava-labs/libevm/log" "github.com/ava-labs/libevm/metrics" "github.com/ava-labs/libevm/triedb" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" ) const ( diff --git a/core/state/snapshot/wipe.go b/core/state/snapshot/wipe.go index 9f1949363b..d427231079 100644 --- a/core/state/snapshot/wipe.go +++ b/core/state/snapshot/wipe.go @@ -31,11 +31,11 @@ import ( "bytes" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/libevm/log" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" ) // 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 41bab9468f..b925303d91 100644 --- a/core/state/snapshot/wipe_test.go +++ b/core/state/snapshot/wipe_test.go @@ -31,10 +31,10 @@ import ( "math/rand" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/ethdb/memorydb" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" ) // Tests that given a database with random data content, all parts of a snapshot diff --git a/core/state_manager.go b/core/state_manager.go index 0503a39c48..d83302ffbc 100644 --- a/core/state_manager.go +++ b/core/state_manager.go @@ -30,10 +30,10 @@ package core import ( "fmt" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/types" "github.com/ava-labs/libevm/ethdb" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" ) // flushWindow is the distance to the [commitInterval] when we start diff --git a/eth/api_debug.go b/eth/api_debug.go index 65fdb6fd2a..e564094d0c 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -43,8 +43,8 @@ import ( "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/libevm/trie" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/subnet-evm/internal/ethapi" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/rpc" ) diff --git a/eth/backend.go b/eth/backend.go index 51ca8eef68..82b29bbbba 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -36,6 +36,7 @@ import ( "time" "github.com/ava-labs/avalanchego/utils/timer/mockable" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/accounts" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" @@ -59,7 +60,6 @@ import ( "github.com/ava-labs/subnet-evm/miner" "github.com/ava-labs/subnet-evm/node" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/rpc" ) diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 13941e266a..0f0eb69cec 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -38,6 +38,7 @@ import ( "testing" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" ethereum "github.com/ava-labs/libevm" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" @@ -49,7 +50,6 @@ import ( "github.com/ava-labs/subnet-evm/core/bloombits" "github.com/ava-labs/subnet-evm/internal/ethapi" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/rpc" "github.com/stretchr/testify/require" ) diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 00a4edef42..501eaf6b57 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -36,6 +36,7 @@ import ( "testing" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" @@ -46,7 +47,6 @@ import ( "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" "github.com/ava-labs/subnet-evm/rpc" "github.com/stretchr/testify/require" diff --git a/eth/state_accessor.go b/eth/state_accessor.go index f4c290cf32..d5c3605086 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -33,6 +33,7 @@ import ( "fmt" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/state" @@ -44,7 +45,6 @@ import ( "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/extstate" "github.com/ava-labs/subnet-evm/eth/tracers" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" ) // noopReleaser is returned in case there is no operation expected diff --git a/eth/tracers/api_extra_test.go b/eth/tracers/api_extra_test.go index 75884af31b..38b70b726d 100644 --- a/eth/tracers/api_extra_test.go +++ b/eth/tracers/api_extra_test.go @@ -13,6 +13,7 @@ import ( "sync/atomic" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/libevm/common/math" @@ -25,7 +26,6 @@ import ( "github.com/ava-labs/subnet-evm/internal/ethapi" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/params/extras" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" "github.com/ava-labs/subnet-evm/rpc" diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 8ba2333f54..b26f4e620d 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -38,6 +38,7 @@ import ( "sync/atomic" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/libevm/core/rawdb" @@ -53,7 +54,6 @@ import ( "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/internal/ethapi" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/rpc" "golang.org/x/exp/slices" ) diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index f28b0c0070..5268fe1554 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -31,6 +31,7 @@ import ( "math/big" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" @@ -39,7 +40,6 @@ import ( "github.com/ava-labs/libevm/eth/tracers/logger" "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/tests" ) diff --git a/go.mod b/go.mod index 91b5f572a2..6e678fa506 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ module github.com/ava-labs/subnet-evm -go 1.24.7 +go 1.24.8 require ( github.com/VictoriaMetrics/fastcache v1.12.1 github.com/antithesishq/antithesis-sdk-go v0.3.8 - github.com/ava-labs/avalanchego v1.13.6-0.20251003124629-84e9aebcfbc0 + github.com/ava-labs/avalanchego v1.13.6-0.20251008120019-fff1df9564d3 github.com/ava-labs/firewood-go-ethhash/ffi v0.0.12 github.com/ava-labs/libevm v1.13.15-0.20251002164226-35926db4d661 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc diff --git a/go.sum b/go.sum index c94134c0cc..3b245adb8e 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/antithesishq/antithesis-sdk-go v0.3.8/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 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.13.6-0.20251003124629-84e9aebcfbc0 h1:B3ti+6P0r7V6BZw5PG7nP7hZ4AJj/1tSsmOOAwnonhs= -github.com/ava-labs/avalanchego v1.13.6-0.20251003124629-84e9aebcfbc0/go.mod h1:yplWYV/FzAZeYAhy0yOj8wjJA1PCdTPxQf8Wzpwg6DY= +github.com/ava-labs/avalanchego v1.13.6-0.20251008120019-fff1df9564d3 h1:PExdlCEpGaAg75iIlWYBYFtUeqiyBityzAjRiZ5nm4M= +github.com/ava-labs/avalanchego v1.13.6-0.20251008120019-fff1df9564d3/go.mod h1:EL0MGbL2liE9jp4QtCHR2thkNl8hCkD26DJ+7cmcaqs= github.com/ava-labs/coreth v0.15.4-rc.3.0.20251002221438-a857a64c28ea h1:vrHUSx6hlQgdVufhtT9LT9i7eHZcWmBEjH9cBozDLuc= github.com/ava-labs/coreth v0.15.4-rc.3.0.20251002221438-a857a64c28ea/go.mod h1:y/14LplmA0lLwIDlKiGAZ8OlxQ7OxhaU2dfkYcviLPM= github.com/ava-labs/firewood-go-ethhash/ffi v0.0.12 h1:aMcrLbpJ/dyu2kZDf/Di/4JIWsUcYPyTDKymiHpejt0= diff --git a/plugin/evm/customrawdb/accessors_metadata_ext.go b/plugin/evm/customrawdb/accessors_metadata_ext.go deleted file mode 100644 index eb79f86bd4..0000000000 --- a/plugin/evm/customrawdb/accessors_metadata_ext.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package customrawdb - -import ( - "encoding/json" - "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/subnet-evm/params" - - ethrawdb "github.com/ava-labs/libevm/core/rawdb" -) - -// writeCurrentTimeMarker writes a marker of the current time in the db at `key`. -func writeCurrentTimeMarker(db ethdb.KeyValueStore, key []byte) error { - data, err := rlp.EncodeToBytes(uint64(time.Now().Unix())) - if err != nil { - return err - } - return db.Put(key, data) -} - -// readTimeMarker reads the timestamp stored at `key` -func readTimeMarker(db ethdb.KeyValueStore, key []byte) (time.Time, error) { - data, err := db.Get(key) - if err != nil { - return time.Time{}, err - } - - var unix uint64 - if err := rlp.DecodeBytes(data, &unix); err != nil { - return time.Time{}, err - } - - return time.Unix(int64(unix), 0), nil -} - -// WriteOfflinePruning writes a time marker of the last attempt to run offline pruning. -// The marker is written when offline pruning completes and is deleted when the node -// is started successfully with offline pruning disabled. This ensures users must -// disable offline pruning and start their node successfully between runs of offline -// pruning. -func WriteOfflinePruning(db ethdb.KeyValueStore) error { - return writeCurrentTimeMarker(db, offlinePruningKey) -} - -// ReadOfflinePruning reads the most recent timestamp of an attempt to run offline -// pruning if present. -func ReadOfflinePruning(db ethdb.KeyValueStore) (time.Time, error) { - return readTimeMarker(db, offlinePruningKey) -} - -// DeleteOfflinePruning deletes any marker of the last attempt to run offline pruning. -func DeleteOfflinePruning(db ethdb.KeyValueStore) error { - return db.Delete(offlinePruningKey) -} - -// WritePopulateMissingTries writes a marker for the current attempt to populate -// missing tries. -func WritePopulateMissingTries(db ethdb.KeyValueStore) error { - return writeCurrentTimeMarker(db, populateMissingTriesKey) -} - -// ReadPopulateMissingTries reads the most recent timestamp of an attempt to -// re-populate missing trie nodes. -func ReadPopulateMissingTries(db ethdb.KeyValueStore) (time.Time, error) { - return readTimeMarker(db, populateMissingTriesKey) -} - -// DeletePopulateMissingTries deletes any marker of the last attempt to -// re-populate missing trie nodes. -func DeletePopulateMissingTries(db ethdb.KeyValueStore) error { - return db.Delete(populateMissingTriesKey) -} - -// WritePruningDisabled writes a marker to track whether the node has ever run -// with pruning disabled. -func WritePruningDisabled(db ethdb.KeyValueStore) error { - return db.Put(pruningDisabledKey, nil) -} - -// HasPruningDisabled returns true if there is a marker present indicating that -// the node has run with pruning disabled at some point. -func HasPruningDisabled(db ethdb.KeyValueStore) (bool, error) { - return db.Has(pruningDisabledKey) -} - -// WriteAcceptorTip writes `hash` as the last accepted block that has been fully processed. -func WriteAcceptorTip(db ethdb.KeyValueWriter, hash common.Hash) error { - return db.Put(acceptorTipKey, hash[:]) -} - -// ReadAcceptorTip reads the hash of the last accepted block that was fully processed. -// If there is no value present (the index is being initialized for the first time), then the -// empty hash is returned. -func ReadAcceptorTip(db ethdb.KeyValueReader) (common.Hash, error) { - has, err := db.Has(acceptorTipKey) - if err != nil { - return common.Hash{}, err - } - if !has { - // If the index is not present on disk, the [acceptorTipKey] index has not been initialized yet. - return common.Hash{}, nil - } - h, err := db.Get(acceptorTipKey) - if err != nil { - return common.Hash{}, err - } - if len(h) != common.HashLength { - return common.Hash{}, fmt.Errorf("value has incorrect length %d", len(h)) - } - return common.BytesToHash(h), nil -} - -// ReadChainConfig retrieves the consensus settings based on the given genesis hash. -func ReadChainConfig(db ethdb.KeyValueReader, hash common.Hash) *params.ChainConfig { - config := ethrawdb.ReadChainConfig(db, hash) - - upgrade, _ := db.Get(upgradeConfigKey(hash)) - if len(upgrade) == 0 { - return config - } - - extra := params.GetExtra(config) - if err := json.Unmarshal(upgrade, &extra.UpgradeConfig); err != nil { - log.Error("Invalid upgrade config JSON", "err", err) - return nil - } - - return config -} - -// WriteChainConfig writes the chain config settings to the database. -func WriteChainConfig(db ethdb.KeyValueWriter, hash common.Hash, config *params.ChainConfig) { - ethrawdb.WriteChainConfig(db, hash, config) - if config == nil { - return - } - - extra := params.GetExtra(config) - data, err := json.Marshal(extra.UpgradeConfig) - if err != nil { - log.Crit("Failed to JSON encode upgrade config", "err", err) - } - if err := db.Put(upgradeConfigKey(hash), data); err != nil { - log.Crit("Failed to store upgrade config", "err", err) - } -} diff --git a/plugin/evm/customrawdb/accessors_snapshot_ext.go b/plugin/evm/customrawdb/accessors_snapshot_ext.go deleted file mode 100644 index 6a4e2c83cf..0000000000 --- a/plugin/evm/customrawdb/accessors_snapshot_ext.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package customrawdb - -import ( - "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/ethdb" - "github.com/ava-labs/libevm/log" - - ethrawdb "github.com/ava-labs/libevm/core/rawdb" -) - -// ReadSnapshotBlockHash retrieves the hash of the block whose state is contained in -// the persisted snapshot. -func ReadSnapshotBlockHash(db ethdb.KeyValueReader) common.Hash { - data, _ := db.Get(snapshotBlockHashKey) - if len(data) != common.HashLength { - return common.Hash{} - } - return common.BytesToHash(data) -} - -// WriteSnapshotBlockHash stores the root of the block whose state is contained in -// the persisted snapshot. -func WriteSnapshotBlockHash(db ethdb.KeyValueWriter, blockHash common.Hash) { - if err := db.Put(snapshotBlockHashKey, blockHash[:]); err != nil { - log.Crit("Failed to store snapshot block hash", "err", err) - } -} - -// DeleteSnapshotBlockHash deletes the hash of the block whose state is contained in -// the persisted snapshot. Since snapshots are not immutable, this method can -// be used during updates, so a crash or failure will mark the entire snapshot -// invalid. -func DeleteSnapshotBlockHash(db ethdb.KeyValueWriter) { - if err := db.Delete(snapshotBlockHashKey); err != nil { - log.Crit("Failed to remove snapshot block hash", "err", err) - } -} - -// IterateAccountSnapshots returns an iterator for walking all of the accounts in the snapshot -func IterateAccountSnapshots(db ethdb.Iteratee) ethdb.Iterator { - it := db.NewIterator(ethrawdb.SnapshotAccountPrefix, nil) - keyLen := len(ethrawdb.SnapshotAccountPrefix) + common.HashLength - return ethrawdb.NewKeyLengthIterator(it, keyLen) -} diff --git a/plugin/evm/customrawdb/accessors_state_sync.go b/plugin/evm/customrawdb/accessors_state_sync.go deleted file mode 100644 index 8abe4a6f75..0000000000 --- a/plugin/evm/customrawdb/accessors_state_sync.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package customrawdb - -import ( - "encoding/binary" - - "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" - - ethrawdb "github.com/ava-labs/libevm/core/rawdb" -) - -// ReadSyncRoot reads the root corresponding to the main trie of an in-progress -// sync and returns common.Hash{} if no in-progress sync was found. -func ReadSyncRoot(db ethdb.KeyValueReader) (common.Hash, error) { - has, err := db.Has(syncRootKey) - if err != nil || !has { - return common.Hash{}, err - } - root, err := db.Get(syncRootKey) - if err != nil { - return common.Hash{}, err - } - return common.BytesToHash(root), nil -} - -// WriteSyncRoot writes root as the root of the main trie of the in-progress sync. -func WriteSyncRoot(db ethdb.KeyValueWriter, root common.Hash) error { - return db.Put(syncRootKey, root[:]) -} - -// AddCodeToFetch adds a marker that we need to fetch the code for `hash`. -func AddCodeToFetch(db ethdb.KeyValueWriter, hash common.Hash) { - if err := db.Put(codeToFetchKey(hash), nil); err != nil { - log.Crit("Failed to put code to fetch", "codeHash", hash, "err", err) - } -} - -// DeleteCodeToFetch removes the marker that the code corresponding to `hash` needs to be fetched. -func DeleteCodeToFetch(db ethdb.KeyValueWriter, hash common.Hash) { - if err := db.Delete(codeToFetchKey(hash)); err != nil { - log.Crit("Failed to delete code to fetch", "codeHash", hash, "err", err) - } -} - -// NewCodeToFetchIterator returns a KeyLength iterator over all code -// hashes that are pending syncing. It is the caller's responsibility to -// unpack the key and call Release on the returned iterator. -func NewCodeToFetchIterator(db ethdb.Iteratee) ethdb.Iterator { - return ethrawdb.NewKeyLengthIterator( - db.NewIterator(CodeToFetchPrefix, nil), - codeToFetchKeyLength, - ) -} - -func codeToFetchKey(hash common.Hash) []byte { - codeToFetchKey := make([]byte, codeToFetchKeyLength) - copy(codeToFetchKey, CodeToFetchPrefix) - copy(codeToFetchKey[len(CodeToFetchPrefix):], hash[:]) - return codeToFetchKey -} - -// NewSyncSegmentsIterator returns a KeyLength iterator over all trie segments -// added for root. It is the caller's responsibility to unpack the key and call -// Release on the returned iterator. -func NewSyncSegmentsIterator(db ethdb.Iteratee, root common.Hash) ethdb.Iterator { - segmentsPrefix := make([]byte, len(syncSegmentsPrefix)+common.HashLength) - copy(segmentsPrefix, syncSegmentsPrefix) - copy(segmentsPrefix[len(syncSegmentsPrefix):], root[:]) - - return ethrawdb.NewKeyLengthIterator( - db.NewIterator(segmentsPrefix, nil), - syncSegmentsKeyLength, - ) -} - -// WriteSyncSegment adds a trie segment for root at the given start position. -func WriteSyncSegment(db ethdb.KeyValueWriter, root common.Hash, start common.Hash) error { - return db.Put(packSyncSegmentKey(root, start), []byte{0x01}) -} - -// ClearSyncSegments removes segment markers for root from db -func ClearSyncSegments(db ethdb.KeyValueStore, root common.Hash) error { - segmentsPrefix := make([]byte, len(syncSegmentsPrefix)+common.HashLength) - copy(segmentsPrefix, syncSegmentsPrefix) - copy(segmentsPrefix[len(syncSegmentsPrefix):], root[:]) - return clearPrefix(db, segmentsPrefix, syncSegmentsKeyLength) -} - -// ClearAllSyncSegments removes all segment markers from db -func ClearAllSyncSegments(db ethdb.KeyValueStore) error { - return clearPrefix(db, syncSegmentsPrefix, syncSegmentsKeyLength) -} - -// UnpackSyncSegmentKey returns the root and start position for a trie segment -// key returned from NewSyncSegmentsIterator. -func UnpackSyncSegmentKey(keyBytes []byte) (common.Hash, []byte) { - keyBytes = keyBytes[len(syncSegmentsPrefix):] // skip prefix - root := common.BytesToHash(keyBytes[:common.HashLength]) - start := keyBytes[common.HashLength:] - return root, start -} - -// packSyncSegmentKey packs root and account into a key for storage in db. -func packSyncSegmentKey(root common.Hash, start common.Hash) []byte { - bytes := make([]byte, syncSegmentsKeyLength) - copy(bytes, syncSegmentsPrefix) - copy(bytes[len(syncSegmentsPrefix):], root[:]) - copy(bytes[len(syncSegmentsPrefix)+common.HashLength:], start.Bytes()) - return bytes -} - -// NewSyncStorageTriesIterator returns a KeyLength iterator over all storage tries -// added for syncing (beginning at seek). It is the caller's responsibility to unpack -// the key and call Release on the returned iterator. -func NewSyncStorageTriesIterator(db ethdb.Iteratee, seek []byte) ethdb.Iterator { - return ethrawdb.NewKeyLengthIterator(db.NewIterator(syncStorageTriesPrefix, seek), syncStorageTriesKeyLength) -} - -// WriteSyncStorageTrie adds a storage trie for account (with the given root) to be synced. -func WriteSyncStorageTrie(db ethdb.KeyValueWriter, root common.Hash, account common.Hash) error { - return db.Put(packSyncStorageTrieKey(root, account), []byte{0x01}) -} - -// ClearSyncStorageTrie removes all storage trie accounts (with the given root) from db. -// Intended for use when the trie with root has completed syncing. -func ClearSyncStorageTrie(db ethdb.KeyValueStore, root common.Hash) error { - accountsPrefix := make([]byte, len(syncStorageTriesPrefix)+common.HashLength) - copy(accountsPrefix, syncStorageTriesPrefix) - copy(accountsPrefix[len(syncStorageTriesPrefix):], root[:]) - return clearPrefix(db, accountsPrefix, syncStorageTriesKeyLength) -} - -// ClearAllSyncStorageTries removes all storage tries added for syncing from db -func ClearAllSyncStorageTries(db ethdb.KeyValueStore) error { - return clearPrefix(db, syncStorageTriesPrefix, syncStorageTriesKeyLength) -} - -// UnpackSyncStorageTrieKey returns the root and account for a storage trie -// key returned from NewSyncStorageTriesIterator. -func UnpackSyncStorageTrieKey(keyBytes []byte) (common.Hash, common.Hash) { - keyBytes = keyBytes[len(syncStorageTriesPrefix):] // skip prefix - root := common.BytesToHash(keyBytes[:common.HashLength]) - account := common.BytesToHash(keyBytes[common.HashLength:]) - return root, account -} - -// packSyncStorageTrieKey packs root and account into a key for storage in db. -func packSyncStorageTrieKey(root common.Hash, account common.Hash) []byte { - bytes := make([]byte, 0, syncStorageTriesKeyLength) - bytes = append(bytes, syncStorageTriesPrefix...) - bytes = append(bytes, root[:]...) - bytes = append(bytes, account[:]...) - return bytes -} - -// WriteSyncPerformed logs an entry in `db` indicating the VM state synced to `blockNumber`. -func WriteSyncPerformed(db ethdb.KeyValueWriter, blockNumber uint64) error { - syncPerformedPrefixLen := len(syncPerformedPrefix) - bytes := make([]byte, syncPerformedPrefixLen+wrappers.LongLen) - copy(bytes[:syncPerformedPrefixLen], syncPerformedPrefix) - binary.BigEndian.PutUint64(bytes[syncPerformedPrefixLen:], blockNumber) - return db.Put(bytes, []byte{0x01}) -} - -// NewSyncPerformedIterator returns an iterator over all block numbers the VM -// has state synced to. -func NewSyncPerformedIterator(db ethdb.Iteratee) ethdb.Iterator { - return ethrawdb.NewKeyLengthIterator(db.NewIterator(syncPerformedPrefix, nil), syncPerformedKeyLength) -} - -// UnpackSyncPerformedKey returns the block number from keys the iterator returned -// from NewSyncPerformedIterator. -func UnpackSyncPerformedKey(key []byte) uint64 { - return binary.BigEndian.Uint64(key[len(syncPerformedPrefix):]) -} - -// GetLatestSyncPerformed returns the latest block number state synced performed to. -func GetLatestSyncPerformed(db ethdb.Iteratee) uint64 { - it := NewSyncPerformedIterator(db) - defer it.Release() - - var latestSyncPerformed uint64 - for it.Next() { - syncPerformed := UnpackSyncPerformedKey(it.Key()) - if syncPerformed > latestSyncPerformed { - latestSyncPerformed = syncPerformed - } - } - return latestSyncPerformed -} - -// clearPrefix removes all keys in db that begin with prefix and match an -// expected key length. `keyLen` must include the length of the prefix. -func clearPrefix(db ethdb.KeyValueStore, prefix []byte, keyLen int) error { - it := db.NewIterator(prefix, nil) - defer it.Release() - - batch := db.NewBatch() - for it.Next() { - key := common.CopyBytes(it.Key()) - if len(key) != keyLen { - continue - } - if err := batch.Delete(key); err != nil { - return err - } - if batch.ValueSize() > ethdb.IdealBatchSize { - if err := batch.Write(); err != nil { - return err - } - batch.Reset() - } - } - if err := it.Error(); err != nil { - return err - } - return batch.Write() -} diff --git a/plugin/evm/customrawdb/accessors_state_sync_test.go b/plugin/evm/customrawdb/accessors_state_sync_test.go deleted file mode 100644 index c9b6f66223..0000000000 --- a/plugin/evm/customrawdb/accessors_state_sync_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package customrawdb - -import ( - "testing" - - "github.com/ava-labs/libevm/common" - "github.com/stretchr/testify/require" - - ethrawdb "github.com/ava-labs/libevm/core/rawdb" -) - -func TestClearPrefix(t *testing.T) { - require := require.New(t) - db := ethrawdb.NewMemoryDatabase() - // add a key that should be cleared - require.NoError(WriteSyncSegment(db, common.Hash{1}, common.Hash{})) - - // add a key that should not be cleared - key := append(syncSegmentsPrefix, []byte("foo")...) - require.NoError(db.Put(key, []byte("bar"))) - - require.NoError(ClearAllSyncSegments(db)) - - count := 0 - it := db.NewIterator(syncSegmentsPrefix, nil) - defer it.Release() - for it.Next() { - count++ - } - require.NoError(it.Error()) - require.Equal(1, count) -} diff --git a/plugin/evm/customrawdb/database_ext.go b/plugin/evm/customrawdb/database_ext.go deleted file mode 100644 index 961b1000d6..0000000000 --- a/plugin/evm/customrawdb/database_ext.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package customrawdb - -import ( - "bytes" - "fmt" - - "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/core/rawdb" - "github.com/ava-labs/libevm/ethdb" -) - -// InspectDatabase traverses the entire database and checks the size -// of all different categories of data. -func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { - type stat = rawdb.DatabaseStat - stats := []struct { - name string - keyLen int - keyPrefix []byte - stat *stat - }{ - {"Trie segments", syncSegmentsKeyLength, syncSegmentsPrefix, &stat{}}, - {"Storage tries to fetch", syncStorageTriesKeyLength, syncStorageTriesPrefix, &stat{}}, - {"Code to fetch", codeToFetchKeyLength, CodeToFetchPrefix, &stat{}}, - {"Block numbers synced to", syncPerformedKeyLength, syncPerformedPrefix, &stat{}}, - } - - options := []rawdb.InspectDatabaseOption{ - rawdb.WithDatabaseMetadataKeys(func(key []byte) bool { - return bytes.Equal(key, snapshotBlockHashKey) || - bytes.Equal(key, syncRootKey) || - (bytes.HasPrefix(key, upgradeConfigPrefix) && len(key) == len(upgradeConfigPrefix)+common.HashLength) - }), - rawdb.WithDatabaseStatRecorder(func(key []byte, size common.StorageSize) bool { - for _, s := range stats { - if len(key) == s.keyLen && bytes.HasPrefix(key, s.keyPrefix) { - s.stat.Add(size) - return true - } - } - return false - }), - rawdb.WithDatabaseStatsTransformer(func(rows [][]string) [][]string { - newRows := make([][]string, 0, len(rows)) - for _, row := range rows { - switch db, cat := row[0], row[1]; { - // Discard rows specific to libevm (geth) but irrelevant to subnet-evm. - case db == "Key-Value store" && (cat == "Difficulties" || cat == "Beacon sync headers"): - case db == "Ancient store (Chain)": - default: - newRows = append(newRows, row) - } - } - for _, s := range stats { - newRows = append(newRows, []string{"State sync", s.name, s.stat.Size(), s.stat.Count()}) - } - return newRows - }), - } - - return rawdb.InspectDatabase(db, keyPrefix, keyStart, options...) -} - -// ParseStateSchemeExt parses the state scheme from the provided string. -func ParseStateSchemeExt(provided string, disk ethdb.Database) (string, error) { - // Check for custom scheme - if provided == FirewoodScheme { - if diskScheme := rawdb.ReadStateScheme(disk); diskScheme != "" { - // Valid scheme on disk mismatched - return "", fmt.Errorf("State scheme %s already set on disk, can't use Firewood", diskScheme) - } - // If no conflicting scheme is found, is valid. - return FirewoodScheme, nil - } - - // Check for valid eth scheme - return rawdb.ParseStateScheme(provided, disk) -} diff --git a/plugin/evm/customrawdb/database_ext_test.go b/plugin/evm/customrawdb/database_ext_test.go deleted file mode 100644 index 9fa920b784..0000000000 --- a/plugin/evm/customrawdb/database_ext_test.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package customrawdb - -import ( - "fmt" - - "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/ethdb" - - ethrawdb "github.com/ava-labs/libevm/core/rawdb" -) - -func ExampleInspectDatabase() { - db := &stubDatabase{ - iterator: &stubIterator{}, - } - - // Extra metadata keys: (17 + 32) + (12 + 32) = 93 bytes - WriteSnapshotBlockHash(db, common.Hash{}) - ethrawdb.WriteSnapshotRoot(db, common.Hash{}) - // Trie segments: (77 + 2) + 1 = 80 bytes - _ = WriteSyncSegment(db, common.Hash{}, common.Hash{}) - // Storage tries to fetch: 76 + 1 = 77 bytes - _ = WriteSyncStorageTrie(db, common.Hash{}, common.Hash{}) - // Code to fetch: 34 + 0 = 34 bytes - AddCodeToFetch(db, common.Hash{}) - // Block numbers synced to: 22 + 1 = 23 bytes - _ = WriteSyncPerformed(db, 0) - - keyPrefix := []byte(nil) - keyStart := []byte(nil) - - err := InspectDatabase(db, keyPrefix, keyStart) - if err != nil { - fmt.Println(err) - } - // Output: - // +-----------------+-------------------------+----------+-------+ - // | DATABASE | CATEGORY | SIZE | ITEMS | - // +-----------------+-------------------------+----------+-------+ - // | Key-Value store | Headers | 0.00 B | 0 | - // | Key-Value store | Bodies | 0.00 B | 0 | - // | Key-Value store | Receipt lists | 0.00 B | 0 | - // | Key-Value store | Block number->hash | 0.00 B | 0 | - // | Key-Value store | Block hash->number | 0.00 B | 0 | - // | Key-Value store | Transaction index | 0.00 B | 0 | - // | Key-Value store | Bloombit index | 0.00 B | 0 | - // | Key-Value store | Contract codes | 0.00 B | 0 | - // | Key-Value store | Hash trie nodes | 0.00 B | 0 | - // | Key-Value store | Path trie state lookups | 0.00 B | 0 | - // | Key-Value store | Path trie account nodes | 0.00 B | 0 | - // | Key-Value store | Path trie storage nodes | 0.00 B | 0 | - // | Key-Value store | Trie preimages | 0.00 B | 0 | - // | Key-Value store | Account snapshot | 0.00 B | 0 | - // | Key-Value store | Storage snapshot | 0.00 B | 0 | - // | Key-Value store | Clique snapshots | 0.00 B | 0 | - // | Key-Value store | Singleton metadata | 93.00 B | 2 | - // | Light client | CHT trie nodes | 0.00 B | 0 | - // | Light client | Bloom trie nodes | 0.00 B | 0 | - // | State sync | Trie segments | 78.00 B | 1 | - // | State sync | Storage tries to fetch | 77.00 B | 1 | - // | State sync | Code to fetch | 34.00 B | 1 | - // | State sync | Block numbers synced to | 23.00 B | 1 | - // +-----------------+-------------------------+----------+-------+ - // | TOTAL | 305.00 B | | - // +-----------------+-------------------------+----------+-------+ -} - -type stubDatabase struct { - ethdb.Database - iterator *stubIterator -} - -func (s *stubDatabase) NewIterator(_, _ []byte) ethdb.Iterator { - return s.iterator -} - -// AncientSize is used in [InspectDatabase] to determine the ancient sizes. -func (*stubDatabase) AncientSize(string) (uint64, error) { - return 0, nil -} - -func (*stubDatabase) Ancients() (uint64, error) { - return 0, nil -} - -func (*stubDatabase) Tail() (uint64, error) { - return 0, nil -} - -func (s *stubDatabase) Put(key, value []byte) error { - s.iterator.kvs = append(s.iterator.kvs, keyValue{key: key, value: value}) - return nil -} - -func (*stubDatabase) Get([]byte) ([]byte, error) { - return nil, nil -} - -func (*stubDatabase) ReadAncients(_ func(ethdb.AncientReaderOp) error) error { - return nil -} - -type stubIterator struct { - ethdb.Iterator - i int // see [stubIterator.pos] - kvs []keyValue -} - -type keyValue struct { - key []byte - value []byte -} - -// pos returns the true iterator position, which is otherwise off by one because -// Next() is called _before_ usage. -func (s *stubIterator) pos() int { - return s.i - 1 -} - -func (s *stubIterator) Next() bool { - s.i++ - return s.pos() < len(s.kvs) -} - -func (*stubIterator) Release() {} - -func (s *stubIterator) Key() []byte { - return s.kvs[s.pos()].key -} - -func (s *stubIterator) Value() []byte { - return s.kvs[s.pos()].value -} diff --git a/plugin/evm/customrawdb/schema_ext.go b/plugin/evm/customrawdb/schema_ext.go deleted file mode 100644 index 7ec9a75813..0000000000 --- a/plugin/evm/customrawdb/schema_ext.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package customrawdb - -import ( - "github.com/ava-labs/avalanchego/utils/wrappers" - "github.com/ava-labs/libevm/common" -) - -var ( - // snapshotBlockHashKey tracks the block hash of the last snapshot. - snapshotBlockHashKey = []byte("SnapshotBlockHash") - // offlinePruningKey tracks runs of offline pruning - offlinePruningKey = []byte("OfflinePruning") - // populateMissingTriesKey tracks runs of trie backfills - populateMissingTriesKey = []byte("PopulateMissingTries") - // pruningDisabledKey tracks whether the node has ever run in archival mode - // to ensure that a user does not accidentally corrupt an archival node. - pruningDisabledKey = []byte("PruningDisabled") - // acceptorTipKey tracks the tip of the last accepted block that has been fully processed. - acceptorTipKey = []byte("AcceptorTipKey") - // upgradeConfigPrefix prefixes upgrade bytes passed to the chain - upgradeConfigPrefix = []byte("upgrade-config-") -) - -// State sync progress keys and prefixes -var ( - // syncRootKey indicates the root of the main account trie currently being synced - syncRootKey = []byte("sync_root") - // syncStorageTriesPrefix is the prefix for storage tries that need to be fetched. - // syncStorageTriesPrefix + trie root + account hash: indicates a storage trie must be fetched for the account - syncStorageTriesPrefix = []byte("sync_storage") - // syncSegmentsPrefix is the prefix for segments. - // syncSegmentsPrefix + trie root + 32-byte start key: indicates the trie at root has a segment starting at the specified key - syncSegmentsPrefix = []byte("sync_segments") - // CodeToFetchPrefix is the prefix for code hashes that need to be fetched. - // CodeToFetchPrefix + code hash -> empty value tracks the outstanding code hashes we need to fetch. - CodeToFetchPrefix = []byte("CP") -) - -// State sync progress key lengths -var ( - syncStorageTriesKeyLength = len(syncStorageTriesPrefix) + 2*common.HashLength - syncSegmentsKeyLength = len(syncSegmentsPrefix) + 2*common.HashLength - codeToFetchKeyLength = len(CodeToFetchPrefix) + common.HashLength -) - -// State sync metadata -var ( - syncPerformedPrefix = []byte("sync_performed") - // syncPerformedKeyLength is the length of the key for the sync performed metadata key, - // and is equal to [syncPerformedPrefix] + block number as uint64. - syncPerformedKeyLength = len(syncPerformedPrefix) + wrappers.LongLen -) - -var FirewoodScheme = "firewood" - -// upgradeConfigKey = upgradeConfigPrefix + hash -func upgradeConfigKey(hash common.Hash) []byte { - return append(upgradeConfigPrefix, hash.Bytes()...) -} diff --git a/plugin/evm/syncervm_test.go b/plugin/evm/syncervm_test.go index 0ed52a30dd..29be49290e 100644 --- a/plugin/evm/syncervm_test.go +++ b/plugin/evm/syncervm_test.go @@ -21,6 +21,7 @@ import ( "github.com/ava-labs/avalanchego/upgrade/upgradetest" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/evm/predicate" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" @@ -37,7 +38,6 @@ import ( "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/coretest" "github.com/ava-labs/subnet-evm/params/paramstest" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/database" "github.com/ava-labs/subnet-evm/sync/statesync/statesynctest" "github.com/ava-labs/subnet-evm/utils/utilstest" diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 8267557d38..a806cb08a9 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -33,6 +33,7 @@ import ( "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/version" "github.com/ava-labs/avalanchego/vms/components/chain" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/firewood-go-ethhash/ffi" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" @@ -66,7 +67,6 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/params/extras" "github.com/ava-labs/subnet-evm/plugin/evm/config" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/gossip" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/plugin/evm/validators" diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 67d8dcdc50..dc913ecc96 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -34,6 +34,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/chain" "github.com/ava-labs/avalanchego/vms/evm/acp176" "github.com/ava-labs/avalanchego/vms/evm/predicate" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/math" @@ -56,7 +57,6 @@ import ( "github.com/ava-labs/subnet-evm/params/paramstest" "github.com/ava-labs/subnet-evm/plugin/evm/config" "github.com/ava-labs/subnet-evm/plugin/evm/customheader" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" "github.com/ava-labs/subnet-evm/plugin/evm/vmerrors" "github.com/ava-labs/subnet-evm/precompile/allowlist" diff --git a/scripts/build_test.sh b/scripts/build_test.sh index aad40d42e4..e0e4fdd101 100755 --- a/scripts/build_test.sh +++ b/scripts/build_test.sh @@ -34,7 +34,7 @@ do if [[ ${command_status:-0} == 0 ]]; then rm test.out exit 0 - else + else unset command_status # Clear the error code for the next run fi @@ -42,7 +42,7 @@ do unexpected_failures=$( # First grep pattern corresponds to test failures, second pattern corresponds to test panics due to timeouts (grep "^--- FAIL" test.out | awk '{print $3}' || grep -E '^\s+Test.+ \(' test.out | awk '{print $1}') | - sort -u | comm -23 - <(sed 's/\r$//' ./scripts/known_flakes.txt) + sort -u | comm -23 - <(sed 's/\r$//' ./scripts/known_flakes.txt | sort -u) ) if [ -n "${unexpected_failures}" ]; then echo "Unexpected test failures: ${unexpected_failures}" @@ -56,4 +56,4 @@ do done # If we reach here, we have failed all retries -exit 1 \ No newline at end of file +exit 1 diff --git a/scripts/lint_allowed_eth_imports.sh b/scripts/lint_allowed_eth_imports.sh index 50e005e7ed..4069721d70 100755 --- a/scripts/lint_allowed_eth_imports.sh +++ b/scripts/lint_allowed_eth_imports.sh @@ -15,7 +15,7 @@ extra_imports=$(find . -type f \( -name "*.go" \) ! -name "mocks.go" ! -path "si grep -v 'eth\w\+ "' | grep -v '_ "' | grep -o "${libevm_regexp}" | - sort -u | comm -23 - ./scripts/eth-allowed-packages.txt) + sort -u | comm -23 - <(sort -u ./scripts/eth-allowed-packages.txt)) if [ -n "${extra_imports}" ]; then echo "new ethereum imports should be added to ./scripts/eth-allowed-packages.txt to prevent accidental imports:" echo "${extra_imports}" diff --git a/sync/statesync/code_syncer.go b/sync/statesync/code_syncer.go index aab4b529aa..f68c0c3895 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/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/ethdb" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/message" statesyncclient "github.com/ava-labs/subnet-evm/sync/client" diff --git a/sync/statesync/code_syncer_test.go b/sync/statesync/code_syncer_test.go index 972c056095..ecb85dbe5e 100644 --- a/sync/statesync/code_syncer_test.go +++ b/sync/statesync/code_syncer_test.go @@ -9,13 +9,13 @@ import ( "testing" "github.com/ava-labs/avalanchego/utils" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/libevm/ethdb/memorydb" "github.com/stretchr/testify/assert" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/plugin/evm/message" "github.com/ava-labs/subnet-evm/sync/handlers" diff --git a/sync/statesync/statesynctest/test_sync.go b/sync/statesync/statesynctest/test_sync.go index e380ca9d60..8d5c5205fc 100644 --- a/sync/statesync/statesynctest/test_sync.go +++ b/sync/statesync/statesynctest/test_sync.go @@ -8,6 +8,7 @@ import ( "math/rand" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" @@ -17,7 +18,6 @@ import ( "github.com/ava-labs/libevm/triedb" "github.com/stretchr/testify/assert" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/utils/utilstest" ) diff --git a/sync/statesync/trie_queue.go b/sync/statesync/trie_queue.go index 92d2c76be1..95e7a6b1e0 100644 --- a/sync/statesync/trie_queue.go +++ b/sync/statesync/trie_queue.go @@ -4,10 +4,9 @@ package statesync import ( + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/ethdb" - - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" ) // trieQueue persists storage trie roots with their associated diff --git a/sync/statesync/trie_segments.go b/sync/statesync/trie_segments.go index 1a4f6dd231..02ede349df 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/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/ethdb" "github.com/ava-labs/libevm/log" "github.com/ava-labs/libevm/trie" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/utils" syncclient "github.com/ava-labs/subnet-evm/sync/client" diff --git a/tests/state_test_util.go b/tests/state_test_util.go index ad030bd3d6..4fb080d598 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -38,6 +38,7 @@ import ( "strconv" "strings" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/hexutil" "github.com/ava-labs/libevm/common/math" @@ -55,7 +56,6 @@ import ( "github.com/ava-labs/subnet-evm/core/extstate" "github.com/ava-labs/subnet-evm/core/state/snapshot" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/plugin/evm/customrawdb" "github.com/ava-labs/subnet-evm/triedb/firewood" "github.com/ava-labs/subnet-evm/triedb/hashdb" "github.com/ava-labs/subnet-evm/triedb/pathdb"