diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12a51ac14d..87400bb00a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -111,7 +111,7 @@ jobs: path: avalanchego token: ${{ secrets.AVALANCHE_PAT }} - name: Run e2e tests - uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@df4a8e531761a55d6878d6d2f16e9acb023de19d + uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@3b08d6131a00bd55349321a58ae7e6cfcff8635e with: run: ./scripts/run_task.sh test-e2e-ci prometheus_url: ${{ secrets.PROMETHEUS_URL || '' }} @@ -139,7 +139,7 @@ jobs: ref: ${{ github.event.inputs.avalanchegoBranch }} path: avalanchego - name: Run Warp E2E Tests - uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@df4a8e531761a55d6878d6d2f16e9acb023de19d + uses: ava-labs/avalanchego/.github/actions/run-monitored-tmpnet-cmd@3b08d6131a00bd55349321a58ae7e6cfcff8635e with: run: ./scripts/run_task.sh test-e2e-warp-ci artifact_prefix: warp diff --git a/core/blockchain.go b/core/blockchain.go index c8655cb339..a0ab30d05e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -40,13 +40,14 @@ import ( "sync/atomic" "time" + "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/vms/evm/acp176" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/consensus" "github.com/ava-labs/coreth/core/extstate" "github.com/ava-labs/coreth/core/state/snapshot" "github.com/ava-labs/coreth/internal/version" "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/customtypes" "github.com/ava-labs/coreth/triedb/firewood" "github.com/ava-labs/coreth/triedb/hashdb" @@ -488,7 +489,10 @@ func NewBlockChain( // if txlookup limit is 0 (uindexing disabled), we don't need to repair the tx index tail. if bc.cacheConfig.TransactionHistory != 0 { - latestStateSynced := customrawdb.GetLatestSyncPerformed(bc.db) + latestStateSynced, err := customrawdb.GetLatestSyncPerformed(bc.db) + if err != nil { + return nil, fmt.Errorf("failed to get latest state synced: %w", err) + } bc.repairTxIndexTail(latestStateSynced) } @@ -1832,7 +1836,11 @@ func (bc *BlockChain) initSnapshot(b *types.Header) { func (bc *BlockChain) reprocessState(current *types.Block, reexec uint64) error { origin := current.NumberU64() acceptorTip, err := customrawdb.ReadAcceptorTip(bc.db) - if err != nil { + // If no acceptor tip exists, treat it as empty hash (not initialized). + switch { + case errors.Is(err, database.ErrNotFound): + acceptorTip = common.Hash{} + case err != nil: return fmt.Errorf("%w: unable to get Acceptor tip", err) } log.Info("Loaded Acceptor tip", "hash", acceptorTip) @@ -2060,7 +2068,7 @@ func (bc *BlockChain) populateMissingTries() error { // Write marker to DB to indicate populate missing tries finished successfully. // Note: writing the marker here means that we do allow consecutive runs of re-populating // missing tries if it does not finish during the prior run. - if err := customrawdb.WritePopulateMissingTries(bc.db); err != nil { + if err := customrawdb.WritePopulateMissingTries(bc.db, time.Now()); err != nil { return fmt.Errorf("failed to write offline pruning success marker: %w", err) } diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index c493e367d7..0b26cce751 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -35,9 +35,9 @@ import ( "math/big" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/consensus/dummy" "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/upgrade/ap3" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 801647611e..3e6501e442 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -34,10 +34,10 @@ import ( "testing" "github.com/ava-labs/avalanchego/upgrade" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/consensus/dummy" "github.com/ava-labs/coreth/core/state/pruner" "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/upgrade/ap3" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" diff --git a/core/genesis_test.go b/core/genesis_test.go index cd806ec302..fa9a0a6029 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -35,10 +35,10 @@ import ( "reflect" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/consensus/dummy" "github.com/ava-labs/coreth/params" "github.com/ava-labs/coreth/params/extras" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/upgrade/ap3" "github.com/ava-labs/coreth/precompile/contracts/warp" "github.com/ava-labs/coreth/triedb/firewood" diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 43fc954a4f..2b277536f9 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -38,8 +38,8 @@ import ( "strings" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/core/state/snapshot" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" @@ -219,7 +219,7 @@ func prune(maindb ethdb.Database, stateBloom *stateBloom, bloomPath string, star // Write marker to DB to indicate offline pruning finished successfully. We write before calling os.RemoveAll // to guarantee that if the node dies midway through pruning, then this will run during RecoverPruning. - if err := customrawdb.WriteOfflinePruning(maindb); err != nil { + if err := customrawdb.WriteOfflinePruning(maindb, time.Now()); err != nil { return fmt.Errorf("failed to write offline pruning success marker: %w", err) } diff --git a/core/state/snapshot/disklayer_test.go b/core/state/snapshot/disklayer_test.go index bc501ed600..73545d9c1b 100644 --- a/core/state/snapshot/disklayer_test.go +++ b/core/state/snapshot/disklayer_test.go @@ -31,7 +31,7 @@ import ( "bytes" "testing" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" + "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" diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 49b02f46d2..a6264ccfa8 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -32,7 +32,7 @@ import ( "fmt" "time" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/utils" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" diff --git a/core/state/snapshot/journal.go b/core/state/snapshot/journal.go index 23c1b2aba0..aea9a11bfb 100644 --- a/core/state/snapshot/journal.go +++ b/core/state/snapshot/journal.go @@ -33,7 +33,8 @@ import ( "fmt" "time" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" + "github.com/ava-labs/avalanchego/database" + "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" @@ -42,6 +43,15 @@ import ( "github.com/ava-labs/libevm/triedb" ) +var ( + errSnapshotNotFound = errors.New("snapshot not found") + errSnapshotBlockHashEmpty = errors.New("missing or corrupted snapshot, no snapshot block hash") + errSnapshotBlockHashMismatch = errors.New("snapshot block hash mismatch") + errSnapshotRootEmpty = errors.New("missing or corrupted snapshot, no snapshot root") + errSnapshotRootMismatch = errors.New("snapshot root mismatch") + errSnapshotGeneratorMissing = errors.New("missing snapshot generator") +) + // journalGenerator is a disk layer entry containing the generator progress marker. type journalGenerator struct { // Indicator that whether the database was in progress of being wiped. @@ -59,21 +69,26 @@ type journalGenerator struct { // store. If loading the snapshot from disk is successful, this function also // returns a boolean indicating whether or not the snapshot is fully generated. func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *triedb.Database, cache int, blockHash, root common.Hash, noBuild bool) (snapshot, bool, error) { - // Retrieve the block number and hash of the snapshot, failing if no snapshot - // is present in the database (or crashed mid-update). - baseBlockHash := customrawdb.ReadSnapshotBlockHash(diskdb) - if baseBlockHash == (common.Hash{}) { - return nil, false, errors.New("missing or corrupted snapshot, no snapshot block hash") - } - if baseBlockHash != blockHash { - return nil, false, fmt.Errorf("block hash stored on disk (%#x) does not match last accepted (%#x)", baseBlockHash, blockHash) + // Retrieve the block hash of the snapshot, failing if no snapshot is present. + baseBlockHash, err := customrawdb.ReadSnapshotBlockHash(diskdb) + switch { + case errors.Is(err, database.ErrNotFound): + return nil, false, fmt.Errorf("%w: %w", errSnapshotNotFound, err) + case err != nil: + return nil, false, fmt.Errorf("failed to read snapshot block hash: %w", err) + case baseBlockHash == (common.Hash{}): + return nil, false, errSnapshotBlockHashEmpty + case baseBlockHash != blockHash: + return nil, false, fmt.Errorf("%w: stored %#x, expected %#x", errSnapshotBlockHashMismatch, baseBlockHash, blockHash) } + + // Retrieve and validate the snapshot root. baseRoot := rawdb.ReadSnapshotRoot(diskdb) - if baseRoot == (common.Hash{}) { - return nil, false, errors.New("missing or corrupted snapshot, no snapshot root") - } - if baseRoot != root { - return nil, false, fmt.Errorf("root stored on disk (%#x) does not match last accepted (%#x)", baseRoot, root) + switch { + case baseRoot == (common.Hash{}): + return nil, false, errSnapshotRootEmpty + case baseRoot != root: + return nil, false, fmt.Errorf("%w: stored %#x, expected %#x", errSnapshotRootMismatch, baseRoot, root) } // Retrieve the disk layer generator. It must exist, no matter the @@ -81,7 +96,7 @@ func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *triedb.Database, cache int // layer is invalid. generatorBlob := rawdb.ReadSnapshotGenerator(diskdb) if len(generatorBlob) == 0 { - return nil, false, errors.New("missing snapshot generator") + return nil, false, errSnapshotGeneratorMissing } var generator journalGenerator if err := rlp.DecodeBytes(generatorBlob, &generator); err != nil { diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 62e3d7b681..dc66972d5a 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -35,7 +35,7 @@ import ( "sync" "time" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" + "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" diff --git a/core/state/snapshot/wipe.go b/core/state/snapshot/wipe.go index af03b8ab43..d427231079 100644 --- a/core/state/snapshot/wipe.go +++ b/core/state/snapshot/wipe.go @@ -31,7 +31,7 @@ import ( "bytes" "time" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" + "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" diff --git a/core/state/snapshot/wipe_test.go b/core/state/snapshot/wipe_test.go index ca0b5ca6d2..fe1787840e 100644 --- a/core/state/snapshot/wipe_test.go +++ b/core/state/snapshot/wipe_test.go @@ -28,10 +28,12 @@ package snapshot import ( + "errors" "math/rand" "testing" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" + "github.com/ava-labs/avalanchego/database" + "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" @@ -40,7 +42,7 @@ import ( // Tests that given a database with random data content, all parts of a snapshot // can be crrectly wiped without touching anything else. func TestWipe(t *testing.T) { - // Create a database with some random snapshot data + // Create a database with some random snapshot data. db := memorydb.New() for i := 0; i < 128; i++ { rawdb.WriteAccountSnapshot(db, randomHash(), randomHash().Bytes()) @@ -48,9 +50,9 @@ func TestWipe(t *testing.T) { customrawdb.WriteSnapshotBlockHash(db, randomHash()) rawdb.WriteSnapshotRoot(db, randomHash()) - // Add some random non-snapshot data too to make wiping harder + // Add some random non-snapshot data too to make wiping harder. for i := 0; i < 500; i++ { - // Generate keys with wrong length for a state snapshot item + // Generate keys with wrong length for a state snapshot item. keysuffix := make([]byte, 31) rand.Read(keysuffix) db.Put(append(rawdb.SnapshotAccountPrefix, keysuffix...), randomHash().Bytes()) @@ -68,24 +70,29 @@ func TestWipe(t *testing.T) { } return items } - // Sanity check that all the keys are present + // Verify snapshot data exists before wipe. if items := count(); items != 128 { - t.Fatalf("snapshot size mismatch: have %d, want %d", items, 128) + t.Fatalf("snapshot size mismatch before wipe: have %d, want %d", items, 128) } - if hash := customrawdb.ReadSnapshotBlockHash(db); hash == (common.Hash{}) { - t.Errorf("snapshot block hash marker mismatch: have %#x, want ", hash) + blockHash, err := customrawdb.ReadSnapshotBlockHash(db) + switch { + case err != nil: + t.Fatalf("failed to read snapshot block hash before wipe: %v", err) + case blockHash == (common.Hash{}): + t.Fatalf("snapshot block hash is empty before wipe") } - if hash := rawdb.ReadSnapshotRoot(db); hash == (common.Hash{}) { - t.Errorf("snapshot block root marker mismatch: have %#x, want ", hash) + if root := rawdb.ReadSnapshotRoot(db); root == (common.Hash{}) { + t.Fatalf("snapshot root is empty before wipe") } - // Wipe all snapshot entries from the database + + // Wipe all snapshot entries from the database. <-WipeSnapshot(db, true) - // Iterate over the database end ensure no snapshot information remains + // Verify snapshot data is removed. if items := count(); items != 0 { - t.Fatalf("snapshot size mismatch: have %d, want %d", items, 0) + t.Fatalf("snapshot size mismatch after wipe: have %d, want %d", items, 0) } - // Iterate over the database and ensure miscellaneous items are present + // Verify miscellaneous items are preserved. items := 0 it := db.NewIterator(nil, nil) defer it.Release() @@ -93,13 +100,19 @@ func TestWipe(t *testing.T) { items++ } if items != 1000 { - t.Fatalf("misc item count mismatch: have %d, want %d", items, 1000) + t.Fatalf("misc item count mismatch after wipe: have %d, want %d", items, 1000) } - if hash := customrawdb.ReadSnapshotBlockHash(db); hash != (common.Hash{}) { - t.Errorf("snapshot block hash marker remained after wipe: %#x", hash) + // Verify snapshot markers are removed. + blockHash, err = customrawdb.ReadSnapshotBlockHash(db) + switch { + case errors.Is(err, database.ErrNotFound): // Expected: marker was deleted. + case err != nil: + t.Errorf("unexpected error reading snapshot block hash after wipe: %v", err) + case blockHash != (common.Hash{}): + t.Errorf("snapshot block hash marker remained after wipe: %#x", blockHash) } - if hash := rawdb.ReadSnapshotRoot(db); hash != (common.Hash{}) { - t.Errorf("snapshot block root marker remained after wipe: %#x", hash) + if root := rawdb.ReadSnapshotRoot(db); root != (common.Hash{}) { + t.Errorf("snapshot root marker remained after wipe: %#x", root) } } diff --git a/core/state_manager.go b/core/state_manager.go index 0f1b5844d0..d83302ffbc 100644 --- a/core/state_manager.go +++ b/core/state_manager.go @@ -30,7 +30,7 @@ package core import ( "fmt" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" + "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" diff --git a/eth/api_debug.go b/eth/api_debug.go index 19b88ce16b..8fcf865223 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -33,8 +33,8 @@ import ( "fmt" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/internal/ethapi" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/rpc" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/hexutil" diff --git a/eth/backend.go b/eth/backend.go index ac310b37ee..cfd9ec526a 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/coreth/consensus" "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/core/state/pruner" @@ -50,7 +51,6 @@ import ( "github.com/ava-labs/coreth/miner" "github.com/ava-labs/coreth/node" "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/rpc" "github.com/ava-labs/libevm/accounts" "github.com/ava-labs/libevm/common" @@ -151,7 +151,7 @@ func New( "snapshot clean", common.StorageSize(config.SnapshotCache)*1024*1024, ) - scheme, err := customrawdb.ParseStateSchemeExt(config.StateScheme, chainDb) + scheme, err := customrawdb.ParseStateScheme(config.StateScheme, chainDb) if err != nil { return nil, err } diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 70bf55b753..a71fe7b42b 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -39,11 +39,11 @@ import ( "testing" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/consensus/dummy" "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/internal/ethapi" "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/customtypes" "github.com/ava-labs/coreth/rpc" ethereum "github.com/ava-labs/libevm" diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 9b980722d3..3571b45c52 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -35,11 +35,11 @@ import ( "testing" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/accounts/abi" "github.com/ava-labs/coreth/consensus/dummy" "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/rpc" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 8542ff14b2..a14cb6396c 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -33,10 +33,10 @@ import ( "fmt" "time" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/core/extstate" "github.com/ava-labs/coreth/eth/tracers" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/state" diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 0618c796e5..4c68981c6f 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -961,21 +961,23 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc defer release() h := block.Header() + // Apply block number override fix before creating block context so GetHashFn + // can correctly resolve blockhash(n) when block number is overridden to n+1. + if config != nil && config.BlockOverrides != nil && config.BlockOverrides.Number.ToInt().Uint64() == h.Number.Uint64()+1 { + // Overriding the block number to n+1 is a common way for wallets to + // simulate transactions, however without the following fix, a contract + // can assert it is being simulated by checking if blockhash(n) == 0x0 and + // can behave differently during the simulation. (#32175 for more info) + // -- + // Modify the parent hash and number so that downstream, blockContext's + // GetHash function can correctly return n. + h.ParentHash = h.Hash() + h.Number.Add(h.Number, big.NewInt(1)) + } blockContext := core.NewEVMBlockContext(h, api.chainContext(ctx), nil) // Apply the customization rules if required. if config != nil { - if config.BlockOverrides != nil && config.BlockOverrides.Number.ToInt().Uint64() == h.Number.Uint64()+1 { - // Overriding the block number to n+1 is a common way for wallets to - // simulate transactions, however without the following fix, a contract - // can assert it is being simulated by checking if blockhash(n) == 0x0 and - // can behave differently during the simulation. (#32175 for more info) - // -- - // Modify the parent hash and number so that downstream, blockContext's - // GetHash function can correctly return n. - h.ParentHash = h.Hash() - h.Number.Add(h.Number, big.NewInt(1)) - } originalTime := block.Time() config.BlockOverrides.Apply(&blockContext) // Apply all relevant upgrades from [originalTime] to the block time set in the override. diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index c81f897dd8..82efb862c7 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -38,12 +38,12 @@ import ( "sync/atomic" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/consensus" "github.com/ava-labs/coreth/consensus/dummy" "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/internal/ethapi" "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/rpc" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/hexutil" diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 5bc7a203f9..85f7a0f9f5 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -32,9 +32,9 @@ import ( "os" "testing" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/customtypes" "github.com/ava-labs/coreth/tests" "github.com/ava-labs/libevm/common" diff --git a/go.mod b/go.mod index 4a320c9292..173b0db219 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ go 1.24.9 require ( github.com/VictoriaMetrics/fastcache v1.12.1 - github.com/ava-labs/avalanchego v1.14.1-0.20251120155522-df4a8e531761 + github.com/ava-labs/avalanchego v1.14.1-0.20251124165137-f64fae3ec98e github.com/ava-labs/firewood-go-ethhash/ffi v0.0.15 github.com/ava-labs/libevm v1.13.15-0.20251016142715-1bccf4f2ddb2 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc diff --git a/go.sum b/go.sum index 8f661467bf..2eb325d95c 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax 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.14.1-0.20251120155522-df4a8e531761 h1:FrsqYm5sms00jWnr8pV9Nj08v1ipYjp1x6p11NIpIBU= -github.com/ava-labs/avalanchego v1.14.1-0.20251120155522-df4a8e531761/go.mod h1:Ntq3RBvDQzNjy14NU3RC2Jf1A9pzfM5RVQ30Gwx/6IM= +github.com/ava-labs/avalanchego v1.14.1-0.20251124165137-f64fae3ec98e h1:Pdwj0HkYLyNnH7v0nALrgKmbagSLnUKJ0nZpXmkCFj8= +github.com/ava-labs/avalanchego v1.14.1-0.20251124165137-f64fae3ec98e/go.mod h1:Ntq3RBvDQzNjy14NU3RC2Jf1A9pzfM5RVQ30Gwx/6IM= github.com/ava-labs/firewood-go-ethhash/ffi v0.0.15 h1:NAVjEu508HwdgbxH/xQxMQoBUgYUn9RQf0VeCrhtYMY= github.com/ava-labs/firewood-go-ethhash/ffi v0.0.15/go.mod h1:hR/JSGXxST9B9olwu/NpLXHAykfAyNGfyKnYQqiiOeE= github.com/ava-labs/libevm v1.13.15-0.20251016142715-1bccf4f2ddb2 h1:hQ15IJxY7WOKqeJqCXawsiXh0NZTzmoQOemkWHz7rr4= diff --git a/plugin/evm/customrawdb/accessors_metadata_ext.go b/plugin/evm/customrawdb/accessors_metadata_ext.go deleted file mode 100644 index 709ea157ff..0000000000 --- a/plugin/evm/customrawdb/accessors_metadata_ext.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package customrawdb - -import ( - "fmt" - "time" - - "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/ethdb" - "github.com/ava-labs/libevm/rlp" -) - -// 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 pooint. -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 -} diff --git a/plugin/evm/customrawdb/accessors_snapshot_ext.go b/plugin/evm/customrawdb/accessors_snapshot_ext.go deleted file mode 100644 index cd1ab1a926..0000000000 --- a/plugin/evm/customrawdb/accessors_snapshot_ext.go +++ /dev/null @@ -1,46 +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/core/rawdb" - "github.com/ava-labs/libevm/ethdb" - "github.com/ava-labs/libevm/log" -) - -// 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(rawdb.SnapshotAccountPrefix, nil) - keyLen := len(rawdb.SnapshotAccountPrefix) + common.HashLength - return rawdb.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 ad9c88f093..0000000000 --- a/plugin/evm/customrawdb/accessors_state_sync.go +++ /dev/null @@ -1,222 +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/core/rawdb" - "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 -// 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 rawdb.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 rawdb.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 rawdb.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 rawdb.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 6a57572e4f..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 ( - "slices" - "testing" - - "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/core/rawdb" - "github.com/stretchr/testify/require" -) - -func TestClearPrefix(t *testing.T) { - require := require.New(t) - db := rawdb.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 := slices.Concat(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 c301a5bfff..0000000000 --- a/plugin/evm/customrawdb/database_ext.go +++ /dev/null @@ -1,80 +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) - }), - 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 coreth. - 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 2b786b7f81..0000000000 --- a/plugin/evm/customrawdb/database_ext_test.go +++ /dev/null @@ -1,135 +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/core/rawdb" - "github.com/ava-labs/libevm/ethdb" -) - -func ExampleInspectDatabase() { - db := &stubDatabase{ - iterator: &stubIterator{}, - } - - // Extra metadata keys: (17 + 32) + (12 + 32) = 93 bytes - WriteSnapshotBlockHash(db, common.Hash{}) - rawdb.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 d13f2f7e24..0000000000 --- a/plugin/evm/customrawdb/schema_ext.go +++ /dev/null @@ -1,55 +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") -) - -// 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" diff --git a/plugin/evm/customtypes/block_test.go b/plugin/evm/customtypes/block_test.go index 6c2446e9ed..8d34ec8df8 100644 --- a/plugin/evm/customtypes/block_test.go +++ b/plugin/evm/customtypes/block_test.go @@ -34,14 +34,15 @@ import ( "testing" "github.com/ava-labs/avalanchego/vms/evm/acp226" - "github.com/ava-labs/coreth/internal/blocktest" - "github.com/ava-labs/coreth/params" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/math" "github.com/ava-labs/libevm/core/types" "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/libevm/rlp" + "github.com/ava-labs/coreth/internal/blocktest" + "github.com/ava-labs/coreth/params" + // This test file has to be in package types_test to avoid a circular // dependency when importing `params`. We dot-import the package to mimic // regular same-package behaviour. diff --git a/plugin/evm/customtypes/hashing_test.go b/plugin/evm/customtypes/hashing_test.go index ca1958e043..0e6359f912 100644 --- a/plugin/evm/customtypes/hashing_test.go +++ b/plugin/evm/customtypes/hashing_test.go @@ -32,7 +32,6 @@ import ( "fmt" "io" "math/big" - mrand "math/rand" "testing" "github.com/ava-labs/libevm/common" @@ -43,6 +42,8 @@ import ( "github.com/ava-labs/libevm/rlp" "github.com/ava-labs/libevm/trie" "github.com/ava-labs/libevm/triedb" + + "math/rand" ) func TestDeriveSha(t *testing.T) { @@ -116,7 +117,7 @@ func BenchmarkDeriveSha200(b *testing.B) { func TestFuzzDeriveSha(t *testing.T) { // increase this for longer runs -- it's set to quite low for travis - rndSeed := mrand.Int() + rndSeed := rand.Int() for i := 0; i < 10; i++ { seed := rndSeed + i exp := types.DeriveSha(newDummy(i), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil))) @@ -185,7 +186,7 @@ type dummyDerivableList struct { func newDummy(seed int) *dummyDerivableList { d := &dummyDerivableList{} - src := mrand.NewSource(int64(seed)) + src := rand.NewSource(int64(seed)) // don't use lists longer than 4K items d.len = int(src.Int63() & 0x0FFF) d.seed = seed @@ -197,10 +198,10 @@ func (d *dummyDerivableList) Len() int { } func (d *dummyDerivableList) EncodeIndex(i int, w *bytes.Buffer) { - src := mrand.NewSource(int64(d.seed + i)) + src := rand.NewSource(int64(d.seed + i)) // max item size 256, at least 1 byte per item size := 1 + src.Int63()&0x00FF - io.CopyN(w, mrand.New(src), size) + io.CopyN(w, rand.New(src), size) } func printList(l types.DerivableList) { diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 5a27d49526..c9660c065c 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -35,6 +35,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/gas" "github.com/ava-labs/avalanchego/vms/evm/acp176" "github.com/ava-labs/avalanchego/vms/evm/acp226" + "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" @@ -68,7 +69,6 @@ import ( "github.com/ava-labs/coreth/params" "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/plugin/evm/config" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/extension" "github.com/ava-labs/coreth/plugin/evm/gossip" "github.com/ava-labs/coreth/plugin/evm/message" diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 50cae9cdcc..7e4ab6fbf2 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -27,6 +27,7 @@ import ( "github.com/ava-labs/avalanchego/vms/evm/acp176" "github.com/ava-labs/avalanchego/vms/evm/acp226" "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" @@ -47,7 +48,6 @@ import ( "github.com/ava-labs/coreth/params" "github.com/ava-labs/coreth/params/paramstest" "github.com/ava-labs/coreth/plugin/evm/customheader" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/customtypes" "github.com/ava-labs/coreth/plugin/evm/extension" "github.com/ava-labs/coreth/plugin/evm/message" diff --git a/plugin/evm/vmtest/test_syncervm.go b/plugin/evm/vmtest/test_syncervm.go index 78801772e8..555a480650 100644 --- a/plugin/evm/vmtest/test_syncervm.go +++ b/plugin/evm/vmtest/test_syncervm.go @@ -23,6 +23,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/chain" "github.com/ava-labs/avalanchego/vms/evm/database" "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/coreth/core" "github.com/ava-labs/coreth/core/coretest" "github.com/ava-labs/coreth/params/paramstest" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/customtypes" "github.com/ava-labs/coreth/plugin/evm/extension" "github.com/ava-labs/coreth/plugin/evm/vmsync" @@ -497,7 +497,7 @@ func testSyncerVM(t *testing.T, testSyncVMSetup *testSyncVMSetup, test SyncTestP // TODO: this avoids circular dependencies but is not ideal. ethDBPrefix := []byte("ethdb") chaindb := database.New(prefixdb.NewNested(ethDBPrefix, testSyncVMSetup.syncerVM.DB)) - requireSyncPerformedHeights(t, chaindb, map[uint64]struct{}{}) + requireSyncPerformedHeight(t, chaindb, 0) return } require.NoError(err, "state sync failed") @@ -508,7 +508,8 @@ func testSyncerVM(t *testing.T, testSyncVMSetup *testSyncVMSetup, test SyncTestP require.Equal(serverVM.LastAcceptedExtendedBlock().Height(), syncerVM.LastAcceptedExtendedBlock().Height(), "block height mismatch between syncer and server") require.Equal(serverVM.LastAcceptedExtendedBlock().ID(), syncerVM.LastAcceptedExtendedBlock().ID(), "blockID mismatch between syncer and server") require.True(syncerVM.Ethereum().BlockChain().HasState(syncerVM.Ethereum().BlockChain().LastAcceptedBlock().Root()), "unavailable state for last accepted block") - requireSyncPerformedHeights(t, syncerVM.Ethereum().ChainDb(), map[uint64]struct{}{retrievedSummary.Height(): {}}) + expectedHeight := retrievedSummary.Height() + requireSyncPerformedHeight(t, syncerVM.Ethereum().ChainDb(), expectedHeight) lastNumber := syncerVM.Ethereum().BlockChain().LastAcceptedBlock().NumberU64() // check the last block is indexed @@ -653,16 +654,11 @@ func generateAndAcceptBlocks(t *testing.T, vm extension.InnerVM, numBlocks int, vm.Ethereum().BlockChain().DrainAcceptorQueue() } -// requireSyncPerformedHeights iterates over all heights the VM has synced to and -// verifies they all match the heights present in `expected`. -func requireSyncPerformedHeights(t *testing.T, db ethdb.Iteratee, expected map[uint64]struct{}) { - it := customrawdb.NewSyncPerformedIterator(db) - defer it.Release() - - found := make(map[uint64]struct{}, len(expected)) - for it.Next() { - found[customrawdb.UnpackSyncPerformedKey(it.Key())] = struct{}{} - } - require.NoError(t, it.Error()) - require.Equal(t, expected, found) +// requireSyncPerformedHeight verifies the latest sync performed height matches expectations. +// Pass 0 to verify no sync was performed. +func requireSyncPerformedHeight(t *testing.T, db ethdb.KeyValueStore, expected uint64) { + t.Helper() + latest, err := customrawdb.GetLatestSyncPerformed(db) + require.NoError(t, err) + require.Equal(t, expected, latest, "sync performed height mismatch: expected %d, got %d", expected, latest) } diff --git a/plugin/evm/vmtest/test_vm.go b/plugin/evm/vmtest/test_vm.go index d98bb24b6d..76059752b3 100644 --- a/plugin/evm/vmtest/test_vm.go +++ b/plugin/evm/vmtest/test_vm.go @@ -15,11 +15,11 @@ import ( "github.com/ava-labs/avalanchego/snow/consensus/snowman" "github.com/ava-labs/avalanchego/snow/engine/enginetest" "github.com/ava-labs/avalanchego/upgrade/upgradetest" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" "github.com/stretchr/testify/require" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/extension" avalancheatomic "github.com/ava-labs/avalanchego/chains/atomic" diff --git a/sync/statesync/code_queue.go b/sync/statesync/code_queue.go index 7c8c4c7197..7d65a371b2 100644 --- a/sync/statesync/code_queue.go +++ b/sync/statesync/code_queue.go @@ -9,12 +9,11 @@ import ( "fmt" "sync" + "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/libevm/options" - - "github.com/ava-labs/coreth/plugin/evm/customrawdb" ) const defaultQueueCapacity = 5000 @@ -136,7 +135,9 @@ func (q *CodeQueue) AddCode(ctx context.Context, codeHashes []common.Hash) error // key rather than growing DB usage. The consumer deletes the marker after // fulfilling the request (or when it detects code is already present). for _, codeHash := range codeHashes { - customrawdb.AddCodeToFetch(batch, codeHash) + if err := customrawdb.WriteCodeToFetch(batch, codeHash); err != nil { + return fmt.Errorf("failed to write code to fetch marker: %w", err) + } } if err := batch.Write(); err != nil { @@ -202,7 +203,10 @@ func recoverUnfetchedCodeHashes(db ethdb.Database) ([]common.Hash, error) { continue } - customrawdb.DeleteCodeToFetch(batch, codeHash) + if err := customrawdb.DeleteCodeToFetch(batch, codeHash); err != nil { + return nil, fmt.Errorf("failed to delete code to fetch marker: %w", err) + } + if batch.ValueSize() < ethdb.IdealBatchSize { continue } diff --git a/sync/statesync/code_queue_test.go b/sync/statesync/code_queue_test.go index 74da3e7731..52d6edd0f7 100644 --- a/sync/statesync/code_queue_test.go +++ b/sync/statesync/code_queue_test.go @@ -10,14 +10,13 @@ import ( "time" "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/crypto" "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" "go.uber.org/goleak" - - "github.com/ava-labs/coreth/plugin/evm/customrawdb" ) func TestCodeQueue(t *testing.T) { @@ -86,7 +85,7 @@ func TestCodeQueue(t *testing.T) { rawdb.WriteCode(db, hash, code) } for hash := range tt.alreadyToFetch { - customrawdb.AddCodeToFetch(db, hash) + require.NoError(t, customrawdb.WriteCodeToFetch(db, hash)) } quit := make(chan struct{}) diff --git a/sync/statesync/code_syncer.go b/sync/statesync/code_syncer.go index 3fdda1f6c9..c031343a92 100644 --- a/sync/statesync/code_syncer.go +++ b/sync/statesync/code_syncer.go @@ -8,13 +8,13 @@ import ( "fmt" "sync" + "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/libevm/options" "golang.org/x/sync/errgroup" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/message" syncpkg "github.com/ava-labs/coreth/sync" @@ -145,7 +145,9 @@ func (c *CodeSyncer) work(ctx context.Context) error { if rawdb.HasCode(c.db, codeHash) { // Best-effort cleanup of stale marker. batch := c.db.NewBatch() - customrawdb.DeleteCodeToFetch(batch, codeHash) + if err := customrawdb.DeleteCodeToFetch(batch, codeHash); err != nil { + return fmt.Errorf("failed to delete code to fetch marker: %w", err) + } if err := batch.Write(); err != nil { return fmt.Errorf("failed to write batch for stale code marker: %w", err) @@ -182,7 +184,9 @@ func (c *CodeSyncer) fulfillCodeRequest(ctx context.Context, codeHashes []common batch := c.db.NewBatch() for i, codeHash := range codeHashes { - customrawdb.DeleteCodeToFetch(batch, codeHash) + if err := customrawdb.DeleteCodeToFetch(batch, codeHash); err != nil { + return fmt.Errorf("failed to delete code to fetch marker: %w", err) + } rawdb.WriteCode(batch, codeHash, codeByteSlices[i]) } diff --git a/sync/statesync/code_syncer_test.go b/sync/statesync/code_syncer_test.go index 4b7d3946ea..8e4d05d081 100644 --- a/sync/statesync/code_syncer_test.go +++ b/sync/statesync/code_syncer_test.go @@ -9,6 +9,7 @@ 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" @@ -16,7 +17,6 @@ import ( "github.com/ava-labs/libevm/ethdb/memorydb" "github.com/stretchr/testify/require" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/message" "github.com/ava-labs/coreth/sync/handlers" @@ -144,7 +144,7 @@ func TestCodeSyncerAddsInProgressCodeHashes(t *testing.T) { codeBytes := utils.RandomBytes(100) codeHash := crypto.Keccak256Hash(codeBytes) clientDB := rawdb.NewMemoryDatabase() - customrawdb.AddCodeToFetch(clientDB, codeHash) + require.NoError(t, customrawdb.WriteCodeToFetch(clientDB, codeHash)) testCodeSyncer(t, codeSyncerTest{ clientDB: clientDB, codeRequestHashes: nil, @@ -166,7 +166,7 @@ func TestCodeSyncerAddsMoreInProgressThanQueueSize(t *testing.T) { db := rawdb.NewMemoryDatabase() for _, codeHash := range codeHashes { - customrawdb.AddCodeToFetch(db, codeHash) + require.NoError(t, customrawdb.WriteCodeToFetch(db, codeHash)) } testCodeSyncer(t, codeSyncerTest{ diff --git a/sync/statesync/sync_test.go b/sync/statesync/sync_test.go index b227dc8766..fbf2b0ee94 100644 --- a/sync/statesync/sync_test.go +++ b/sync/statesync/sync_test.go @@ -11,6 +11,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/core/rawdb" "github.com/ava-labs/libevm/core/types" @@ -23,7 +24,6 @@ import ( "golang.org/x/sync/errgroup" "github.com/ava-labs/coreth/core/state/snapshot" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/message" "github.com/ava-labs/coreth/sync/handlers" "github.com/ava-labs/coreth/sync/statesync/statesynctest" @@ -526,7 +526,7 @@ func testSyncerSyncsToNewRoot(t *testing.T, deleteBetweenSyncs func(*testing.T, // Also verifies any code referenced by the EVM state is present in [clientTrieDB] and the hash is correct. func assertDBConsistency(t testing.TB, root common.Hash, clientDB ethdb.Database, serverTrieDB, clientTrieDB *triedb.Database) { numSnapshotAccounts := 0 - accountIt := customrawdb.IterateAccountSnapshots(clientDB) + accountIt := customrawdb.NewAccountSnapshotsIterator(clientDB) defer accountIt.Release() for accountIt.Next() { if !bytes.HasPrefix(accountIt.Key(), rawdb.SnapshotAccountPrefix) || len(accountIt.Key()) != len(rawdb.SnapshotAccountPrefix)+common.HashLength { diff --git a/sync/statesync/trie_queue.go b/sync/statesync/trie_queue.go index f95594216e..5f999d1260 100644 --- a/sync/statesync/trie_queue.go +++ b/sync/statesync/trie_queue.go @@ -4,10 +4,12 @@ package statesync import ( + "errors" + + "github.com/ava-labs/avalanchego/database" + "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/coreth/plugin/evm/customrawdb" ) // trieQueue persists storage trie roots with their associated @@ -28,9 +30,14 @@ func NewTrieQueue(db ethdb.Database) *trieQueue { // the persisted root does not match the root we are syncing to. func (t *trieQueue) clearIfRootDoesNotMatch(root common.Hash) error { persistedRoot, err := customrawdb.ReadSyncRoot(t.db) - if err != nil { + // If no sync root exists, treat it as empty hash (no previous sync). + switch { + case errors.Is(err, database.ErrNotFound): + persistedRoot = common.Hash{} + case err != nil: return err } + if persistedRoot != (common.Hash{}) && persistedRoot != root { // if not resuming, clear all progress markers if err := customrawdb.ClearAllSyncStorageTries(t.db); err != nil { @@ -76,7 +83,7 @@ func (t *trieQueue) getNextTrie() (common.Hash, []common.Hash, bool, error) { // Iterate over the keys to find the next storage trie root and all of the account hashes that contain the same storage root. for it.Next() { // Unpack the state root and account hash from the current key - nextRoot, nextAccount := customrawdb.UnpackSyncStorageTrieKey(it.Key()) + nextRoot, nextAccount := customrawdb.ParseSyncStorageTrieKey(it.Key()) // Set the root for the first pass if root == (common.Hash{}) { root = nextRoot @@ -105,7 +112,7 @@ func (t *trieQueue) countTries() (int, error) { ) for it.Next() { - nextRoot, _ := customrawdb.UnpackSyncStorageTrieKey(it.Key()) + nextRoot, _ := customrawdb.ParseSyncStorageTrieKey(it.Key()) if root == (common.Hash{}) || root != nextRoot { root = nextRoot tries++ diff --git a/sync/statesync/trie_segments.go b/sync/statesync/trie_segments.go index 9d2b443389..4738d5859b 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/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/message" "github.com/ava-labs/coreth/utils" @@ -102,7 +102,7 @@ func (t *trieToSync) loadSegments() error { // key immediately prior to the segment we found on disk. // This is because we do not persist the beginning of // the first segment. - _, segmentStart := customrawdb.UnpackSyncSegmentKey(it.Key()) + _, segmentStart := customrawdb.ParseSyncSegmentKey(it.Key()) segmentStartPos := binary.BigEndian.Uint16(segmentStart[:wrappers.ShortLen]) t.addSegment(prevSegmentStart, addPadding(segmentStartPos-1, 0xff)) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index ddc1c3b1e7..f3d842450f 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -30,9 +30,9 @@ package tests import ( "os" + "github.com/ava-labs/avalanchego/vms/evm/sync/customrawdb" "github.com/ava-labs/coreth/core/extstate" "github.com/ava-labs/coreth/core/state/snapshot" - "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/triedb/firewood" "github.com/ava-labs/coreth/triedb/hashdb" "github.com/ava-labs/coreth/triedb/pathdb"