From 82618853ba6d028e0a473ea2b05a7191132607c0 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 29 Mar 2022 13:39:04 -0700 Subject: [PATCH 01/58] refactor: abstractions for snapshot and pruning; snapshot intervals are eventually pruned; unit tests --- baseapp/abci.go | 58 +-- baseapp/abci_test.go | 32 +- baseapp/baseapp.go | 22 +- baseapp/baseapp_test.go | 544 +++++++++++++++++++++---- baseapp/options.go | 48 +-- baseapp/util_test.go | 16 +- pruning/README.md | 29 ++ pruning/manager.go | 216 ++++++++++ pruning/manager_test.go | 274 +++++++++++++ pruning/types/options.go | 135 ++++++ pruning/types/options_test.go | 29 ++ server/config/config.go | 8 +- server/config/toml.go | 4 +- server/mock/store.go | 67 +-- server/pruning.go | 15 +- server/pruning_test.go | 23 +- server/rollback.go | 2 +- server/start.go | 40 +- simapp/simd/cmd/root.go | 8 +- snapshots/README.md | 40 +- snapshots/helpers_test.go | 32 +- snapshots/manager.go | 140 +++++-- snapshots/manager_test.go | 27 +- snapshots/store.go | 25 ++ snapshots/types/options.go | 18 + snapshots/types/snapshotter.go | 12 +- store/iavl/store.go | 5 +- store/mem/store.go | 7 +- store/rootmulti/dbadapter.go | 7 +- store/rootmulti/proof_test.go | 5 +- store/rootmulti/snapshot_test.go | 9 +- store/rootmulti/store.go | 221 +++++----- store/rootmulti/store_test.go | 87 ++-- store/store.go | 3 +- store/transient/store.go | 7 +- store/transient/store_test.go | 5 +- store/types/pruning.go | 71 ---- store/types/pruning_test.go | 26 -- store/types/store.go | 47 ++- store/types/utils_test.go | 3 +- store/v2alpha1/mem/store.go | 4 +- store/v2alpha1/multi/migration_test.go | 5 +- store/v2alpha1/multi/snapshot_test.go | 2 +- store/v2alpha1/multi/store.go | 34 +- store/v2alpha1/multi/store_test.go | 29 +- store/v2alpha1/multi/view_store.go | 2 +- store/v2alpha1/transient/store.go | 4 +- store/v2alpha1/types.go | 15 +- testutil/network/network.go | 6 +- testutil/snapshots/util.go | 19 + types/store.go | 24 +- types/store_test.go | 3 +- x/upgrade/types/storeloader_test.go | 11 +- 53 files changed, 1892 insertions(+), 633 deletions(-) create mode 100644 pruning/README.md create mode 100644 pruning/manager.go create mode 100644 pruning/manager_test.go create mode 100644 pruning/types/options.go create mode 100644 pruning/types/options_test.go create mode 100644 snapshots/types/options.go delete mode 100644 store/types/pruning.go delete mode 100644 store/types/pruning_test.go create mode 100644 testutil/snapshots/util.go diff --git a/baseapp/abci.go b/baseapp/abci.go index c9b1a6fad98a..e5d008eab5fd 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -338,9 +338,7 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { app.halt() } - if app.snapshotInterval > 0 && uint64(header.Height)%app.snapshotInterval == 0 { - go app.snapshot(header.Height) - } + app.snapshotManager.SnapshotIfApplicable(header.Height) return abci.ResponseCommit{ Data: commitID.Hash, @@ -370,36 +368,6 @@ func (app *BaseApp) halt() { os.Exit(0) } -// snapshot takes a snapshot of the current state and prunes any old snapshottypes. -func (app *BaseApp) snapshot(height int64) { - if app.snapshotManager == nil { - app.logger.Info("snapshot manager not configured") - return - } - - app.logger.Info("creating state snapshot", "height", height) - - snapshot, err := app.snapshotManager.Create(uint64(height)) - if err != nil { - app.logger.Error("failed to create state snapshot", "height", height, "err", err) - return - } - - app.logger.Info("completed state snapshot", "height", height, "format", snapshot.Format) - - if app.snapshotKeepRecent > 0 { - app.logger.Debug("pruning state snapshots") - - pruned, err := app.snapshotManager.Prune(app.snapshotKeepRecent) - if err != nil { - app.logger.Error("Failed to prune state snapshots", "err", err) - return - } - - app.logger.Debug("pruned state snapshots", "pruned", pruned) - } -} - // Query implements the ABCI interface. It delegates to CommitMultiStore if it // implements Queryable. func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { @@ -718,9 +686,27 @@ func (app *BaseApp) GetBlockRetentionHeight(commitHeight int64) int64 { retentionHeight = commitHeight - cp.Evidence.MaxAgeNumBlocks } - if app.snapshotInterval > 0 && app.snapshotKeepRecent > 0 { - v := commitHeight - int64((app.snapshotInterval * uint64(app.snapshotKeepRecent))) - retentionHeight = minNonZero(retentionHeight, v) + if app.snapshotManager != nil { + // Define the state pruning offset, i.e. the block offset at which the + // underlying logical database is persisted to disk. + statePruningOffset := int64(app.snapshotManager.GetInterval()) + if statePruningOffset > 0 { + if commitHeight > statePruningOffset { + v := commitHeight - (commitHeight % statePruningOffset) + retentionHeight = minNonZero(retentionHeight, v) + } else { + // Hitting this case means we have persisting enabled but have yet to reach + // a height in which we persist state, so we return zero regardless of other + // conditions. Otherwise, we could end up pruning blocks without having + // any state committed to disk. + return 0 + } + } + + snapshotRetentionHeights := app.snapshotManager.GetSnapshotBlockRetentionHeights() + if snapshotRetentionHeights > 0 { + retentionHeight = minNonZero(retentionHeight, commitHeight-snapshotRetentionHeights) + } } v := commitHeight - int64(app.minRetainBlocks) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index eddee8b954b1..2d4f31815585 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -3,13 +3,16 @@ package baseapp_test import ( "testing" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/snapshots" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + snaphotsTestUtil "github.com/cosmos/cosmos-sdk/testutil/snapshots" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmprototypes "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/baseapp" ) func TestGetBlockRentionHeight(t *testing.T) { @@ -17,6 +20,9 @@ func TestGetBlockRentionHeight(t *testing.T) { db := dbm.NewMemDB() name := t.Name() + snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), snaphotsTestUtil.GetTempDir(t)) + require.NoError(t, err) + testCases := map[string]struct { bapp *baseapp.BaseApp maxAgeBlocks int64 @@ -38,17 +44,18 @@ func TestGetBlockRentionHeight(t *testing.T) { "pruning iavl snapshot only": { bapp: baseapp.NewBaseApp( name, logger, db, + baseapp.SetPruning(sdk.NewPruningOptions(pruningTypes.PruningNothing)), baseapp.SetMinRetainBlocks(1), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(10000, 1)), ), maxAgeBlocks: 0, commitHeight: 499000, - expected: 498999, + expected: 489000, }, "pruning state sync snapshot only": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetSnapshotInterval(50000), - baseapp.SetSnapshotKeepRecent(3), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)), baseapp.SetMinRetainBlocks(1), ), maxAgeBlocks: 0, @@ -67,8 +74,9 @@ func TestGetBlockRentionHeight(t *testing.T) { "pruning all conditions": { bapp: baseapp.NewBaseApp( name, logger, db, + baseapp.SetPruning(sdk.NewCustomPruningOptions(0, 0)), baseapp.SetMinRetainBlocks(400000), - baseapp.SetSnapshotInterval(50000), baseapp.SetSnapshotKeepRecent(3), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)), ), maxAgeBlocks: 362880, commitHeight: 499000, @@ -77,8 +85,9 @@ func TestGetBlockRentionHeight(t *testing.T) { "no pruning due to no persisted state": { bapp: baseapp.NewBaseApp( name, logger, db, + baseapp.SetPruning(sdk.NewCustomPruningOptions(0, 0)), baseapp.SetMinRetainBlocks(400000), - baseapp.SetSnapshotInterval(50000), baseapp.SetSnapshotKeepRecent(3), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)), ), maxAgeBlocks: 362880, commitHeight: 10000, @@ -87,8 +96,9 @@ func TestGetBlockRentionHeight(t *testing.T) { "disable pruning": { bapp: baseapp.NewBaseApp( name, logger, db, + baseapp.SetPruning(sdk.NewCustomPruningOptions(0, 0)), baseapp.SetMinRetainBlocks(0), - baseapp.SetSnapshotInterval(50000), baseapp.SetSnapshotKeepRecent(3), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)), ), maxAgeBlocks: 362880, commitHeight: 499000, @@ -101,8 +111,8 @@ func TestGetBlockRentionHeight(t *testing.T) { tc.bapp.SetParamStore(¶mStore{db: dbm.NewMemDB()}) tc.bapp.InitChain(abci.RequestInitChain{ - ConsensusParams: &tmprototypes.ConsensusParams{ - Evidence: &tmprototypes.EvidenceParams{ + ConsensusParams: &tmproto.ConsensusParams{ + Evidence: &tmproto.EvidenceParams{ MaxAgeNumBlocks: tc.maxAgeBlocks, }, }, diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 45c65b8030ee..62d607c9d456 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -62,9 +62,7 @@ type BaseApp struct { // nolint: maligned fauxMerkleMode bool // if true, IAVL MountStores uses MountStoresDB for simulation speed. // manages snapshots, i.e. dumps of app state at certain intervals - snapshotManager *snapshots.Manager - snapshotInterval uint64 // block interval between state sync snapshots - snapshotKeepRecent uint32 // recent state sync snapshots to keep + snapshotManager *snapshots.Manager // volatile states: // @@ -252,7 +250,7 @@ func (app *BaseApp) LoadLatestVersion() error { return fmt.Errorf("failed to load latest version: %w", err) } - return app.init() + return app.Init() } // DefaultStoreLoader will be used by default and loads the latest version @@ -284,7 +282,7 @@ func (app *BaseApp) LoadVersion(version int64) error { return fmt.Errorf("failed to load version %d: %w", version, err) } - return app.init() + return app.Init() } // LastCommitID returns the last CommitID of the multistore. @@ -297,7 +295,7 @@ func (app *BaseApp) LastBlockHeight() int64 { return app.cms.LastCommitID().Version } -func (app *BaseApp) init() error { +func (app *BaseApp) Init() error { if app.sealed { panic("cannot call initFromMainStore: baseapp already sealed") } @@ -306,13 +304,13 @@ func (app *BaseApp) init() error { app.setCheckState(tmproto.Header{}) app.Seal() - // make sure the snapshot interval is a multiple of the pruning KeepEvery interval - if app.snapshotManager != nil && app.snapshotInterval > 0 { - if _, ok := app.cms.(*rootmulti.Store); !ok { - return errors.New("state sync snapshots require a rootmulti store") - } + rms, ok := app.cms.(*rootmulti.Store) + if !ok { + return errors.New("rootmulti store is required") + } + if err := rms.GetPruning().Validate(); err != nil { + return err } - return nil } diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 5cfb616bd134..5d16ced3a02f 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -14,33 +14,34 @@ import ( "testing" "time" - "google.golang.org/protobuf/proto" - - "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" - - "github.com/gogo/protobuf/jsonpb" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/legacy" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/snapshots" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store/rootmulti" - storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/x/auth/middleware" "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + storeTypes "github.com/cosmos/cosmos-sdk/store/types" + snaphotsTestUtil "github.com/cosmos/cosmos-sdk/testutil/snapshots" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "google.golang.org/protobuf/proto" + "github.com/gogo/protobuf/jsonpb" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + dbm "github.com/tendermint/tm-db" ) var ( @@ -58,6 +59,14 @@ type paramStore struct { db *dbm.MemDB } +type setupConfig struct { + blocks uint64 + blockTxs int + snapshotInterval uint64 + snapshotKeepRecent uint32 + pruningOpts *storeTypes.PruningOptions +} + func (ps *paramStore) Set(_ sdk.Context, key []byte, value interface{}) { bz, err := json.Marshal(value) if err != nil { @@ -121,7 +130,7 @@ func aminoTxEncoder(cdc *codec.LegacyAmino) sdk.TxEncoder { } // simple one store baseapp -func setupBaseApp(t *testing.T, options ...func(*baseapp.BaseApp)) *baseapp.BaseApp { +func setupBaseApp(t *testing.T, options ...func(*baseapp.BaseApp)) (*baseapp.BaseApp, error) { app := newBaseApp(t.Name(), options...) require.Equal(t, t.Name(), app.Name()) @@ -130,8 +139,7 @@ func setupBaseApp(t *testing.T, options ...func(*baseapp.BaseApp)) *baseapp.Base // stores are mounted err := app.LoadLatestVersion() - require.Nil(t, err) - return app + return app, err } // testTxHandler is a tx.Handler used for the mock app, it does not @@ -150,7 +158,7 @@ func testTxHandler(options middleware.TxHandlerOptions, customTxHandlerMiddlewar } // simple one store baseapp with data and snapshots. Each tx is 1 MB in size (uncompressed). -func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options ...func(*baseapp.BaseApp)) (*baseapp.BaseApp, func()) { +func setupBaseAppWithSnapshots(t *testing.T, config *setupConfig) (*baseapp.BaseApp, func(), error) { codec := codec.NewLegacyAmino() registerTestCodec(codec) routerOpt := func(bapp *baseapp.BaseApp) { @@ -178,7 +186,6 @@ func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options bapp.SetTxHandler(txHandler) } - snapshotInterval := uint64(2) snapshotTimeout := 1 * time.Minute snapshotDir, err := os.MkdirTemp("", "baseapp") require.NoError(t, err) @@ -188,18 +195,18 @@ func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options _ = os.RemoveAll(snapshotDir) } - app := setupBaseApp(t, append(options, - baseapp.SetSnapshotStore(snapshotStore), - baseapp.SetSnapshotInterval(snapshotInterval), - routerOpt)...) + app, err := setupBaseApp(t, routerOpt, baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(config.snapshotInterval, uint32(config.snapshotKeepRecent))), baseapp.SetPruning(config.pruningOpts)) + if err != nil { + return nil, nil, err + } app.InitChain(abci.RequestInitChain{}) r := rand.New(rand.NewSource(3920758213583)) keyCounter := 0 - for height := int64(1); height <= int64(blocks); height++ { + for height := int64(1); height <= int64(config.blocks); height++ { app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: height}}) - for txNum := 0; txNum < blockTxs; txNum++ { + for txNum := 0; txNum < config.blockTxs; txNum++ { tx := txTest{Msgs: []sdk.Msg{}} for msgNum := 0; msgNum < 100; msgNum++ { key := []byte(fmt.Sprintf("%v", keyCounter)) @@ -218,7 +225,7 @@ func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options app.Commit() // Wait for snapshot to be taken, since it happens asynchronously. - if uint64(height)%snapshotInterval == 0 { + if config.snapshotInterval > 0 && uint64(height)%config.snapshotInterval == 0 { start := time.Now() for { if time.Since(start) > snapshotTimeout { @@ -234,11 +241,12 @@ func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options } } - return app, teardown + return app, teardown, nil } func TestMountStores(t *testing.T) { - app := setupBaseApp(t) + app, err := setupBaseApp(t) + require.NoError(t, err) // check both stores store1 := app.CMS().GetCommitKVStore(capKey1) @@ -270,7 +278,7 @@ func (th MockTxHandler) SimulateTx(goCtx context.Context, req tx.Request) (tx.Re } func TestConsensusParamsNotNil(t *testing.T) { - app := setupBaseApp(t, func(app *baseapp.BaseApp) { + app, err := setupBaseApp(t, func(app *baseapp.BaseApp) { app.SetBeginBlocker(func(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { require.NotNil(t, ctx.ConsensusParams()) return abci.ResponseBeginBlock{} @@ -283,6 +291,7 @@ func TestConsensusParamsNotNil(t *testing.T) { }, func(app *baseapp.BaseApp) { app.SetTxHandler(MockTxHandler{T: t}) }) + require.NoError(t, err) header := tmproto.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) @@ -297,7 +306,7 @@ func TestConsensusParamsNotNil(t *testing.T) { // Test that LoadLatestVersion actually does. func TestLoadVersion(t *testing.T) { logger := defaultLogger() - pruningOpt := baseapp.SetPruning(storetypes.PruneNothing) + pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -306,7 +315,7 @@ func TestLoadVersion(t *testing.T) { err := app.LoadLatestVersion() // needed to make stores non-nil require.Nil(t, err) - emptyCommitID := storetypes.CommitID{} + emptyCommitID := storeTypes.CommitID{} // fresh store has zero/empty last commit lastHeight := app.LastBlockHeight() @@ -318,13 +327,13 @@ func TestLoadVersion(t *testing.T) { header := tmproto.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res := app.Commit() - commitID1 := storetypes.CommitID{Version: 1, Hash: res.Data} + commitID1 := storeTypes.CommitID{Version: 1, Hash: res.Data} // execute a block, collect commit ID header = tmproto.Header{Height: 2} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res = app.Commit() - commitID2 := storetypes.CommitID{Version: 2, Hash: res.Data} + commitID2 := storeTypes.CommitID{Version: 2, Hash: res.Data} // reload with LoadLatestVersion app = baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -349,16 +358,16 @@ func useDefaultLoader(app *baseapp.BaseApp) { } func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { - rs := rootmulti.NewStore(db) - rs.SetPruning(storetypes.PruneNothing) + rs := rootmulti.NewStore(db, log.NewNopLogger()) + rs.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing)) key := sdk.NewKVStoreKey(storeKey) - rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) + rs.MountStoreWithDB(key, storeTypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() require.Nil(t, err) require.Equal(t, int64(0), rs.LastCommitID().Version) // write some data in substore - kv, _ := rs.GetStore(key).(storetypes.KVStore) + kv, _ := rs.GetStore(key).(storeTypes.KVStore) require.NotNil(t, kv) kv.Set(k, v) commitID := rs.Commit() @@ -366,16 +375,16 @@ func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { } func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) { - rs := rootmulti.NewStore(db) - rs.SetPruning(storetypes.PruneDefault) + rs := rootmulti.NewStore(db, log.NewNopLogger()) + rs.SetPruning(sdk.NewPruningOptions(storeTypes.PruningDefault)) key := sdk.NewKVStoreKey(storeKey) - rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) + rs.MountStoreWithDB(key, storeTypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() require.Nil(t, err) require.Equal(t, ver, rs.LastCommitID().Version) // query data in substore - kv, _ := rs.GetStore(key).(storetypes.KVStore) + kv, _ := rs.GetStore(key).(storeTypes.KVStore) require.NotNil(t, kv) require.Equal(t, v, kv.Get(k)) } @@ -410,7 +419,7 @@ func TestSetLoader(t *testing.T) { initStore(t, db, tc.origStoreKey, k, v) // load the app with the existing db - opts := []func(*baseapp.BaseApp){baseapp.SetPruning(storetypes.PruneNothing)} + opts := []func(*baseapp.BaseApp){baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing))} if tc.setLoader != nil { opts = append(opts, tc.setLoader) } @@ -433,7 +442,7 @@ func TestSetLoader(t *testing.T) { func TestVersionSetterGetter(t *testing.T) { logger := defaultLogger() - pruningOpt := baseapp.SetPruning(storetypes.PruneDefault) + pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningDefault)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -453,7 +462,7 @@ func TestVersionSetterGetter(t *testing.T) { func TestLoadVersionInvalid(t *testing.T) { logger := log.NewNopLogger() - pruningOpt := baseapp.SetPruning(storetypes.PruneNothing) + pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -468,7 +477,7 @@ func TestLoadVersionInvalid(t *testing.T) { header := tmproto.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res := app.Commit() - commitID1 := storetypes.CommitID{Version: 1, Hash: res.Data} + commitID1 := storeTypes.CommitID{Version: 1, Hash: res.Data} // create a new app with the stores mounted under the same cap key app = baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -485,23 +494,25 @@ func TestLoadVersionInvalid(t *testing.T) { func TestLoadVersionPruning(t *testing.T) { logger := log.NewNopLogger() - pruningOptions := storetypes.PruningOptions{ - KeepRecent: 2, - Interval: 1, - } + pruningOptions := sdk.NewCustomPruningOptions(10, 15) pruningOpt := baseapp.SetPruning(pruningOptions) db := dbm.NewMemDB() name := t.Name() - app := baseapp.NewBaseApp(name, logger, db, pruningOpt) + + snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), snaphotsTestUtil.GetTempDir(t)) + require.NoError(t, err) + snapshotOpt := baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(3, 1)) + + app := baseapp.NewBaseApp(name, logger, db, pruningOpt, snapshotOpt) // make a cap key and mount the store capKey := sdk.NewKVStoreKey("key1") app.MountStores(capKey) - err := app.LoadLatestVersion() // needed to make stores non-nil + err = app.LoadLatestVersion() // needed to make stores non-nil require.Nil(t, err) - emptyCommitID := storetypes.CommitID{} + emptyCommitID := storeTypes.CommitID{} // fresh store has zero/empty last commit lastHeight := app.LastBlockHeight() @@ -509,36 +520,36 @@ func TestLoadVersionPruning(t *testing.T) { require.Equal(t, int64(0), lastHeight) require.Equal(t, emptyCommitID, lastID) - var lastCommitID storetypes.CommitID + var lastCommitID storeTypes.CommitID - // Commit seven blocks, of which 7 (latest) is kept in addition to 6, 5 - // (keep recent) and 3 (keep every). - for i := int64(1); i <= 7; i++ { + // Commit 15 blocks, of which 15 (latest) is kept in addition to 5-14 inclusive + // (keep recent) and 3 (snapshot-interval). + for i := int64(1); i <= 15; i++ { app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: i}}) res := app.Commit() - lastCommitID = storetypes.CommitID{Version: i, Hash: res.Data} + lastCommitID = storeTypes.CommitID{Version: i, Hash: res.Data} } - for _, v := range []int64{1, 2, 4} { + for _, v := range []int64{1, 2, 3, 4} { _, err = app.CMS().CacheMultiStoreWithVersion(v) require.NoError(t, err) } - for _, v := range []int64{3, 5, 6, 7} { + for _, v := range []int64{3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} { _, err = app.CMS().CacheMultiStoreWithVersion(v) require.NoError(t, err) } // reload with LoadLatestVersion, check it loads last version - app = baseapp.NewBaseApp(name, logger, db, pruningOpt) + app = baseapp.NewBaseApp(name, logger, db, pruningOpt, snapshotOpt) app.MountStores(capKey) err = app.LoadLatestVersion() require.Nil(t, err) - testLoadVersionHelper(t, app, int64(7), lastCommitID) + testLoadVersionHelper(t, app, int64(15), lastCommitID) } -func testLoadVersionHelper(t *testing.T, app *baseapp.BaseApp, expectedHeight int64, expectedID storetypes.CommitID) { +func testLoadVersionHelper(t *testing.T, app *baseapp.BaseApp, expectedHeight int64, expectedID storeTypes.CommitID) { lastHeight := app.LastBlockHeight() lastID := app.LastCommitID() require.Equal(t, expectedHeight, lastHeight) @@ -577,7 +588,8 @@ func TestInfo(t *testing.T) { } func TestBaseAppOptionSeal(t *testing.T) { - app := setupBaseApp(t) + app, err := setupBaseApp(t) + require.NoError(t, err) require.Panics(t, func() { app.SetName("") @@ -890,7 +902,7 @@ func testTxDecoder(cdc *codec.LegacyAmino) sdk.TxDecoder { } } -func customHandlerTxTest(t *testing.T, capKey storetypes.StoreKey, storeKey []byte) handlerFun { +func customHandlerTxTest(t *testing.T, capKey storeTypes.StoreKey, storeKey []byte) handlerFun { return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { store := ctx.KVStore(capKey) txTest := tx.(txTest) @@ -921,7 +933,7 @@ func counterEvent(evType string, msgCount int64) sdk.Events { } } -func handlerMsgCounter(t *testing.T, capKey storetypes.StoreKey, deliverKey []byte) sdk.Handler { +func handlerMsgCounter(t *testing.T, capKey storeTypes.StoreKey, deliverKey []byte) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) store := ctx.KVStore(capKey) @@ -1018,7 +1030,8 @@ func TestCheckTx(t *testing.T) { bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) nTxs := int64(5) app.InitChain(abci.RequestInitChain{}) @@ -1075,7 +1088,9 @@ func TestDeliverTx(t *testing.T) { ) bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) + + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) app.InitChain(abci.RequestInitChain{}) nBlocks := 3 @@ -1135,7 +1150,9 @@ func TestMultiMsgDeliverTx(t *testing.T) { ) bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) + + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) // run a multi-msg tx // with all msgs the same route @@ -1220,7 +1237,8 @@ func TestSimulateTx(t *testing.T) { ) bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) app.InitChain(abci.RequestInitChain{}) @@ -1294,7 +1312,8 @@ func TestRunInvalidTransaction(t *testing.T) { ) bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) header := tmproto.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) @@ -1420,7 +1439,8 @@ func TestTxGasLimits(t *testing.T) { bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) header := tmproto.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) @@ -1507,8 +1527,8 @@ func TestMaxBlockGasLimits(t *testing.T) { ) bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) - + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) app.InitChain(abci.RequestInitChain{ ConsensusParams: &tmproto.ConsensusParams{ Block: &tmproto.BlockParams{ @@ -1593,7 +1613,8 @@ func TestBaseAppMiddleware(t *testing.T) { ) bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) app.InitChain(abci.RequestInitChain{}) @@ -1684,8 +1705,8 @@ func TestGasConsumptionBadTx(t *testing.T) { ) bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) - + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) app.InitChain(abci.RequestInitChain{ ConsensusParams: &tmproto.ConsensusParams{ Block: &tmproto.BlockParams{ @@ -1750,7 +1771,8 @@ func TestQuery(t *testing.T) { ) bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) app.InitChain(abci.RequestInitChain{}) @@ -1798,9 +1820,11 @@ func TestGRPCQuery(t *testing.T) { ) } - app := setupBaseApp(t, grpcQueryOpt) + app, err := setupBaseApp(t, grpcQueryOpt) + require.NoError(t, err) app.GRPCQueryRouter().SetInterfaceRegistry(codectypes.NewInterfaceRegistry()) + app.InitChain(abci.RequestInitChain{}) header := tmproto.Header{Height: app.LastBlockHeight() + 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) @@ -1833,7 +1857,8 @@ func TestGRPCQueryPulsar(t *testing.T) { ) } - app := setupBaseApp(t, grpcQueryOpt) + app, err := setupBaseApp(t, grpcQueryOpt) + require.NoError(t, err) app.GRPCQueryRouter().SetInterfaceRegistry(codectypes.NewInterfaceRegistry()) app.InitChain(abci.RequestInitChain{}) @@ -1876,7 +1901,8 @@ func TestP2PQuery(t *testing.T) { }) } - app := setupBaseApp(t, addrPeerFilterOpt, idPeerFilterOpt) + app, err := setupBaseApp(t, addrPeerFilterOpt, idPeerFilterOpt) + require.NoError(t, err) addrQuery := abci.RequestQuery{ Path: "/p2p/filter/addr/1.1.1.1:8000", @@ -1892,7 +1918,8 @@ func TestP2PQuery(t *testing.T) { } func TestGetMaximumBlockGas(t *testing.T) { - app := setupBaseApp(t) + app, err := setupBaseApp(t) + require.NoError(t, err) app.InitChain(abci.RequestInitChain{}) ctx := app.NewContext(true, tmproto.Header{}) @@ -1910,7 +1937,16 @@ func TestGetMaximumBlockGas(t *testing.T) { } func TestListSnapshots(t *testing.T) { - app, teardown := setupBaseAppWithSnapshots(t, 5, 4) + setupConfig := &setupConfig{ + blocks: 5, + blockTxs: 4, + snapshotInterval: 2, + snapshotKeepRecent: 2, + pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + } + + app, teardown, err := setupBaseAppWithSnapshots(t, setupConfig) + require.NoError(t, err) defer teardown() resp := app.ListSnapshots(abci.RequestListSnapshots{}) @@ -1926,8 +1962,150 @@ func TestListSnapshots(t *testing.T) { }}, resp) } +func TestSnapshotWithPruning(t *testing.T) { + testcases := map[string]struct { + config *setupConfig + expectedSnapshots []*abci.Snapshot + expectedErr error + } { + "prune nothing with snapshot": { + config: &setupConfig{ + blocks: 20, + blockTxs: 2, + snapshotInterval: 5, + snapshotKeepRecent: 1, + pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + }, + expectedSnapshots: []*abci.Snapshot{ + {Height: 20, Format: 2, Chunks: 5}, + }, + }, + "prune everything with snapshot": { + config: &setupConfig{ + blocks: 20, + blockTxs: 2, + snapshotInterval: 5, + snapshotKeepRecent: 1, + pruningOpts: sdk.NewPruningOptions(storeTypes.PruningEverything), + }, + expectedSnapshots: []*abci.Snapshot{ + {Height: 20, Format: 2, Chunks: 5}, + }, + }, + "default pruning with snapshot": { + config: &setupConfig{ + blocks: 20, + blockTxs: 2, + snapshotInterval: 5, + snapshotKeepRecent: 1, + pruningOpts: sdk.NewPruningOptions(storeTypes.PruningDefault), + }, + expectedSnapshots: []*abci.Snapshot{ + {Height: 20, Format: 2, Chunks: 5}, + }, + }, + "custom": { + config: &setupConfig{ + blocks: 25, + blockTxs: 2, + snapshotInterval: 5, + snapshotKeepRecent: 2, + pruningOpts: sdk.NewCustomPruningOptions(12, 12), + }, + expectedSnapshots: []*abci.Snapshot{ + {Height: 25, Format: 2, Chunks: 6}, + {Height: 20, Format: 2, Chunks: 5}, + }, + }, + "no snapshots": { + config: &setupConfig{ + blocks: 10, + blockTxs: 2, + snapshotInterval: 0, // 0 implies disable snapshots + pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + }, + expectedSnapshots: []*abci.Snapshot{}, + }, + "keep all snapshots": { + config: &setupConfig{ + blocks: 10, + blockTxs: 2, + snapshotInterval: 3, + snapshotKeepRecent: 0, // 0 implies keep all snapshots + pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + }, + expectedSnapshots: []*abci.Snapshot{ + {Height: 9, Format: 2, Chunks: 2}, + {Height: 6, Format: 2, Chunks: 2}, + {Height: 3, Format: 2, Chunks: 1}, + }, + }, + } + + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + app, teardown, err := setupBaseAppWithSnapshots(t, tc.config) + + if tc.expectedErr != nil { + require.Error(t, err) + require.Equal(t, tc.expectedErr.Error(), err.Error()) + return + } + require.NoError(t, err) + + defer teardown() + + resp := app.ListSnapshots(abci.RequestListSnapshots{}) + for _, s := range resp.Snapshots { + assert.NotEmpty(t, s.Hash) + assert.NotEmpty(t, s.Metadata) + s.Hash = nil + s.Metadata = nil + } + fmt.Println(resp) + assert.Equal(t, abci.ResponseListSnapshots{Snapshots: tc.expectedSnapshots}, resp) + + // Validate that heights were pruned correctly by querying the state at the last height that should be present relative to latest + // and the first height that should be pruned. + // + // Exceptions: + // * Prune nothing: should be able to query all heights (we only test first and latest) + // * Prune default: should be able to query all heights (we only test first and latest) + // * The reason for default behaving this way is that we only commit 20 heights but default has 100_000 keep-recent + var lastExistingHeight int64 + if tc.config.pruningOpts.GetPruningStrategy() == storeTypes.PruningNothing || tc.config.pruningOpts.GetPruningStrategy() == storeTypes.PruningDefault { + lastExistingHeight = 1 + } else { + // Integer division rounds down so by multiplying back we get the last height at which we pruned + lastExistingHeight = int64((tc.config.blocks / tc.config.pruningOpts.Interval) * tc.config.pruningOpts.Interval - tc.config.pruningOpts.KeepRecent) + } + + // Query 1 + res := app.Query(abci.RequestQuery{Path: fmt.Sprintf("/store/%s/key", capKey2.Name()), Data: []byte("0"), Height: lastExistingHeight}) + require.NotNil(t, res, "height: %d", lastExistingHeight) + require.NotNil(t, res.Value, "height: %d", lastExistingHeight) + + // Query 2 + res = app.Query(abci.RequestQuery{Path: fmt.Sprintf("/store/%s/key", capKey2.Name()), Data: []byte("0"), Height: lastExistingHeight - 1}) + require.NotNil(t, res, "height: %d", lastExistingHeight - 1) + if tc.config.pruningOpts.GetPruningStrategy() == storeTypes.PruningNothing || tc.config.pruningOpts.GetPruningStrategy() == storeTypes.PruningDefault { + // With prune nothing or default, we query height 0 which translates to the latest height. + require.NotNil(t, res.Value, "height: %d", lastExistingHeight - 1) + } + }) + } +} + func TestLoadSnapshotChunk(t *testing.T) { - app, teardown := setupBaseAppWithSnapshots(t, 2, 5) + setupConfig := &setupConfig{ + blocks: 2, + blockTxs: 5, + snapshotInterval: 2, + snapshotKeepRecent: 2, + pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + } + app, teardown, err := setupBaseAppWithSnapshots(t, setupConfig) + require.NoError(t, err) defer teardown() testcases := map[string]struct { @@ -1963,7 +2141,15 @@ func TestLoadSnapshotChunk(t *testing.T) { func TestOfferSnapshot_Errors(t *testing.T) { // Set up app before test cases, since it's fairly expensive. - app, teardown := setupBaseAppWithSnapshots(t, 0, 0) + setupConfig := &setupConfig{ + blocks: 0, + blockTxs: 0, + snapshotInterval: 2, + snapshotKeepRecent: 2, + pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + } + app, teardown, err := setupBaseAppWithSnapshots(t, setupConfig) + require.NoError(t, err) defer teardown() m := snapshottypes.Metadata{ChunkHashes: [][]byte{{1}, {2}, {3}}} @@ -2018,10 +2204,26 @@ func TestOfferSnapshot_Errors(t *testing.T) { } func TestApplySnapshotChunk(t *testing.T) { - source, teardown := setupBaseAppWithSnapshots(t, 4, 10) + setupConfig1 := &setupConfig{ + blocks: 4, + blockTxs: 10, + snapshotInterval: 2, + snapshotKeepRecent: 2, + pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + } + source, teardown, err := setupBaseAppWithSnapshots(t, setupConfig1) + require.NoError(t, err) defer teardown() - target, teardown := setupBaseAppWithSnapshots(t, 0, 0) + setupConfig2 := &setupConfig{ + blocks: 0, + blockTxs: 0, + snapshotInterval: 2, + snapshotKeepRecent: 2, + pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + } + target, teardown, err := setupBaseAppWithSnapshots(t, setupConfig2) + require.NoError(t, err) defer teardown() // Fetch latest snapshot to restore @@ -2102,7 +2304,8 @@ func TestWithRouter(t *testing.T) { ) bapp.SetTxHandler(txHandler) } - app := setupBaseApp(t, txHandlerOpt) + app, err := setupBaseApp(t, txHandlerOpt) + require.NoError(t, err) app.InitChain(abci.RequestInitChain{}) nBlocks := 3 @@ -2159,3 +2362,164 @@ func TestBaseApp_EndBlock(t *testing.T) { require.Equal(t, int64(100), res.GetValidatorUpdates()[0].Power) require.Equal(t, cp.Block.MaxGas, res.ConsensusParamUpdates.Block.MaxGas) } + +func TestBaseApp_Init(t *testing.T) { + db := dbm.NewMemDB() + name := t.Name() + logger := defaultLogger() + + snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), snaphotsTestUtil.GetTempDir(t)) + require.NoError(t, err) + + testCases := map[string]struct { + bapp *baseapp.BaseApp + expectedPruning *storeTypes.PruningOptions + expectedSnapshot *snapshottypes.SnapshotOptions + expectedErr error + }{ + "snapshot but no pruning": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + ), + sdk.NewPruningOptions(storeTypes.PruningNothing), + sdk.NewSnapshotOptions(1500, 2), + // if no pruning is set, the default is PruneNothing + nil, + }, + "pruning everything only": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningEverything)), + ), + sdk.NewPruningOptions(storeTypes.PruningEverything), + nil, + nil, + }, + "pruning nothing only": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing)), + ), + sdk.NewPruningOptions(storeTypes.PruningNothing), + nil, + nil, + }, + "pruning default only": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningDefault)), + ), + sdk.NewPruningOptions(storeTypes.PruningDefault), + nil, + nil, + }, + "pruning custom only": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 10)), + ), + sdk.NewCustomPruningOptions(10, 10), + nil, + nil, + }, + "pruning everything and snapshots": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningEverything)), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + ), + sdk.NewPruningOptions(storeTypes.PruningEverything), + sdk.NewSnapshotOptions(1500, 2), + nil, + }, + "pruning nothing and snapshots": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing)), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + ), + sdk.NewPruningOptions(storeTypes.PruningNothing), + sdk.NewSnapshotOptions(1500, 2), + nil, + }, + "pruning default and snapshots": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningDefault)), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + ), + sdk.NewPruningOptions(storeTypes.PruningDefault), + sdk.NewSnapshotOptions(1500, 2), + nil, + }, + "pruning custom and snapshots": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 10)), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + ), + sdk.NewCustomPruningOptions(10, 10), + sdk.NewSnapshotOptions(1500, 2), + nil, + }, + "error custom pruning 0 interval": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 0)), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + ), + sdk.NewCustomPruningOptions(10, 0), + sdk.NewSnapshotOptions(1500, 2), + pruningTypes.ErrPruningIntervalZero, + }, + "error custom pruning too small interval": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 9)), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + ), + sdk.NewCustomPruningOptions(10, 9), + sdk.NewSnapshotOptions(1500, 2), + pruningTypes.ErrPruningIntervalTooSmall, + }, + "error custom pruning too small keep recent": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewCustomPruningOptions(1, 10)), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + ), + sdk.NewCustomPruningOptions(9, 10), + sdk.NewSnapshotOptions(1500, 2), + pruningTypes.ErrPruningKeepRecentTooSmall, + }, + "snapshot zero interval - manager not set": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 10)), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(0, 2)), + ), + sdk.NewCustomPruningOptions(10, 10), + nil, // the snapshot manager is not set when interval is 0 + nil, + }, + "snapshot zero keep recent - allowed": { + baseapp.NewBaseApp(name, logger, db, + baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 10)), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 0)), + ), + sdk.NewCustomPruningOptions(10, 10), + sdk.NewSnapshotOptions(1500, 0), // 0 snapshot-keep-recent means keep all + nil, + }, + } + + for _, tc := range testCases { + // Init and validate + require.Equal(t, tc.expectedErr, tc.bapp.Init()) + if tc.expectedErr != nil { + continue + } + + // Check that settings were set correctly + actualPruning := tc.bapp.CMS().GetPruning() + require.Equal(t, tc.expectedPruning, actualPruning) + + snapshotManager := tc.bapp.GetSnapshotManager() + if tc.expectedSnapshot == nil { + require.Nil(t, snapshotManager) + continue + } + require.NotNil(t, snapshotManager) + + require.Equal(t, tc.expectedSnapshot.Interval, snapshotManager.GetInterval()) + require.Equal(t, tc.expectedSnapshot.KeepRecent, snapshotManager.GetKeepRecent()) + } +} diff --git a/baseapp/options.go b/baseapp/options.go index 4b24c108da06..8b5e54a9f31e 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -9,15 +9,17 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/snapshots" "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + snapshotTypes "github.com/cosmos/cosmos-sdk/snapshots/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) // File for storing in-package BaseApp optional functions, // for options that need access to non-exported fields of the BaseApp // SetPruning sets a pruning option on the multistore associated with the app -func SetPruning(opts sdk.PruningOptions) func(*BaseApp) { +func SetPruning(opts *pruningTypes.PruningOptions) func(*BaseApp) { return func(bapp *BaseApp) { bapp.cms.SetPruning(opts) } } @@ -69,19 +71,9 @@ func SetInterBlockCache(cache sdk.MultiStorePersistentCache) func(*BaseApp) { return func(app *BaseApp) { app.setInterBlockCache(cache) } } -// SetSnapshotInterval sets the snapshot interval. -func SetSnapshotInterval(interval uint64) func(*BaseApp) { - return func(app *BaseApp) { app.SetSnapshotInterval(interval) } -} - -// SetSnapshotKeepRecent sets the recent snapshots to keep. -func SetSnapshotKeepRecent(keepRecent uint32) func(*BaseApp) { - return func(app *BaseApp) { app.SetSnapshotKeepRecent(keepRecent) } -} - -// SetSnapshotStore sets the snapshot store. -func SetSnapshotStore(snapshotStore *snapshots.Store) func(*BaseApp) { - return func(app *BaseApp) { app.SetSnapshotStore(snapshotStore) } +// SetSnapshot sets the snapshot store. +func SetSnapshot(snapshotStore *snapshots.Store, opts *snapshotTypes.SnapshotOptions) func(*BaseApp) { + return func(app *BaseApp) { app.SetSnapshot(snapshotStore, opts) } } func (app *BaseApp) SetName(name string) { @@ -201,32 +193,16 @@ func (app *BaseApp) SetStoreLoader(loader StoreLoader) { app.storeLoader = loader } -// SetSnapshotStore sets the snapshot store. -func (app *BaseApp) SetSnapshotStore(snapshotStore *snapshots.Store) { +// SetSnapshot sets the snapshot store and options. +func (app *BaseApp) SetSnapshot(snapshotStore *snapshots.Store, opts *snapshotTypes.SnapshotOptions) { if app.sealed { - panic("SetSnapshotStore() on sealed BaseApp") + panic("SetSnapshot() on sealed BaseApp") } - if snapshotStore == nil { + if snapshotStore == nil || opts.Interval == 0 { app.snapshotManager = nil return } - app.snapshotManager = snapshots.NewManager(snapshotStore, app.cms, nil) -} - -// SetSnapshotInterval sets the snapshot interval. -func (app *BaseApp) SetSnapshotInterval(snapshotInterval uint64) { - if app.sealed { - panic("SetSnapshotInterval() on sealed BaseApp") - } - app.snapshotInterval = snapshotInterval -} - -// SetSnapshotKeepRecent sets the number of recent snapshots to keep. -func (app *BaseApp) SetSnapshotKeepRecent(snapshotKeepRecent uint32) { - if app.sealed { - panic("SetSnapshotKeepRecent() on sealed BaseApp") - } - app.snapshotKeepRecent = snapshotKeepRecent + app.snapshotManager = snapshots.NewManager(snapshotStore, opts, app.cms, nil, app.logger) } // SetInterfaceRegistry sets the InterfaceRegistry. diff --git a/baseapp/util_test.go b/baseapp/util_test.go index 7244aff8307a..c4e5ae5b7199 100644 --- a/baseapp/util_test.go +++ b/baseapp/util_test.go @@ -2,7 +2,7 @@ package baseapp import ( "github.com/cosmos/cosmos-sdk/types" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/snapshots" ) // TODO: Can be removed once we move all middleware tests into x/auth/middleware @@ -31,10 +31,18 @@ func (app *BaseApp) CMS() types.CommitMultiStore { return app.cms } +// GetSnapshotManager() is an exported method to be able to access baseapp's snapshot +// manager in tests. +// +// This method is only accessible in baseapp tests. +func (app *BaseApp) GetSnapshotManager() *snapshots.Manager { + return app.snapshotManager +} + // GetMaximumBlockGas return maximum blocks gas. // // This method is only accessible in baseapp tests. -func (app *BaseApp) GetMaximumBlockGas(ctx sdk.Context) uint64 { +func (app *BaseApp) GetMaximumBlockGas(ctx types.Context) uint64 { return app.getMaximumBlockGas(ctx) } @@ -48,13 +56,13 @@ func (app *BaseApp) GetName() string { // CreateQueryContext calls app's createQueryContext. // // This method is only accessible in baseapp tests. -func (app *BaseApp) CreateQueryContext(height int64, prove bool) (sdk.Context, error) { +func (app *BaseApp) CreateQueryContext(height int64, prove bool) (types.Context, error) { return app.createQueryContext(height, prove) } // MinGasPrices returns minGasPrices. // // This method is only accessible in baseapp tests. -func (app *BaseApp) MinGasPrices() sdk.DecCoins { +func (app *BaseApp) MinGasPrices() types.DecCoins { return app.minGasPrices } diff --git a/pruning/README.md b/pruning/README.md new file mode 100644 index 000000000000..35d0c2351ce7 --- /dev/null +++ b/pruning/README.md @@ -0,0 +1,29 @@ +# Pruning + +## Overview + +Pruning is the mechanism for deleting old heights from the disk. Depending on the use case, +nodes may require different pruning strategies. For example, archive nodes must keep all +the states and prune nothing. On the other hand, a regular validator node may want to only keep 100 latest heights for performance reasons. + +## Strategies + +The strategies are configured in `app.toml`: +pruning = "< strategy >" # where the options are: +- `default`: only the last 100,000 states(approximately 1 week worth of state) are kept; pruning at 100 block intervals +- `nothing`: all historic states will be saved, nothing will be deleted (i.e. archiving node) +- `everything`: 2 latest states will be kept; pruning at 10 block intervals. +- `custom`: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' + +If no strategy is given to `Baseapp`, `nothing` is selected. However, we perform validation on the cli layer to require these to be always set in the config file. + +## Custom Pruning + +These are applied if and only if the pruning strategy is custom: +- `pruning-keep-recent`: N means to keep all of the last N states +- `pruning-interval`: N means to delete old states from disk every Nth block. + +## Relationship to Snapshots + +Snapshot settings are optional. However, if set, they have an effect on how pruning is done by +persisting the heights that are multiples of `state-sync.snapshot-interval` until after the snapshot is complete. See the "Relationship to Pruning" section in `snapshots/README.md` for more details. diff --git a/pruning/manager.go b/pruning/manager.go new file mode 100644 index 000000000000..c2354f8b0fe0 --- /dev/null +++ b/pruning/manager.go @@ -0,0 +1,216 @@ +package pruning + +import ( + "container/list" + "encoding/binary" + "fmt" + "sync" + + "github.com/cosmos/cosmos-sdk/pruning/types" + + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" +) + +type Manager struct { + logger log.Logger + opts *types.PruningOptions + snapshotInterval uint64 + pruneHeights []int64 + pruneSnapshotHeights *list.List + mx sync.Mutex +} + +const ( + pruneHeightsKey = "s/pruneheights" + pruneSnapshotHeightsKey = "s/pruneSnheights" +) + +func NewManager(logger log.Logger) *Manager { + return &Manager{ + logger: logger, + opts: types.NewPruningOptions(types.PruningNothing), + pruneHeights: []int64{}, + // These are the heights that are multiples of snapshotInterval and kept for state sync snapshots. + // The heights are added to this list to be pruned when a snapshot is complete. + pruneSnapshotHeights: list.New(), + mx: sync.Mutex{}, + } +} + +// SetOptions sets the pruning strategy on the manager. +func (m *Manager) SetOptions(opts *types.PruningOptions) { + m.opts = opts +} + +// GetOptions fetches the pruning strategy from the manager. +func (m *Manager) GetOptions() *types.PruningOptions { + return m.opts +} + +// GetPruningHeights returns all heights to be pruned during the next call to Prune(). +func (m *Manager) GetPruningHeights() []int64 { + return m.pruneHeights +} + +// ResetPruningHeights resets the heights to be pruned. +func (m *Manager) ResetPruningHeights() { + m.pruneHeights = make([]int64, 0) +} + +// HandleHeight determines if pruneHeight height needs to be kept for pruning at the right interval prescribed by +// the pruning strategy. Returns true if the given height was kept to be pruned at the next call to Prune(), false otherwise +func (m *Manager) HandleHeight(previousHeight int64) int64 { + if m.opts.GetPruningStrategy() == types.PruningNothing { + return 0 + } + + defer func() { + // handle persisted snapshot heights + m.mx.Lock() + defer m.mx.Unlock() + var next *list.Element + for e := m.pruneSnapshotHeights.Front(); e != nil; e = next { + snHeight := e.Value.(int64) + if snHeight < previousHeight-int64(m.opts.KeepRecent) { + m.pruneHeights = append(m.pruneHeights, snHeight) + + // We must get next before removing to be able to continue iterating. + next = e.Next() + m.pruneSnapshotHeights.Remove(e) + } else { + next = e.Next() + } + } + }() + + if int64(m.opts.KeepRecent) < previousHeight { + pruneHeight := previousHeight - int64(m.opts.KeepRecent) + // We consider this height to be pruned iff: + // + // - snapshotInterval is zero as that means that all heights should be pruned. + // - snapshotInterval % (height - KeepRecent) != 0 as that means the height is not + // a 'snapshot' height. + if m.snapshotInterval == 0 || pruneHeight%int64(m.snapshotInterval) != 0 { + m.pruneHeights = append(m.pruneHeights, pruneHeight) + return pruneHeight + } + } + return 0 +} + +func (m *Manager) HandleHeightSnapshot(height int64) { + if m.opts.GetPruningStrategy() == types.PruningNothing { + return + } + m.mx.Lock() + defer m.mx.Unlock() + m.logger.Debug("HandleHeightSnapshot", "height", height) + m.pruneSnapshotHeights.PushBack(height) +} + +// SetSnapshotInterval sets the interval at which the snapshots are taken. +func (m *Manager) SetSnapshotInterval(snapshotInterval uint64) { + m.snapshotInterval = snapshotInterval +} + +// ShouldPruneAtHeight return true if the given height should be pruned, false otherwise +func (m *Manager) ShouldPruneAtHeight(height int64) bool { + return m.opts.GetPruningStrategy() != types.PruningNothing && m.opts.Interval > 0 && height%int64(m.opts.Interval) == 0 +} + +// FlushPruningHeights flushes the pruning heights to the database for crash recovery. +func (m *Manager) FlushPruningHeights(batch dbm.Batch) { + if m.opts.GetPruningStrategy() == types.PruningNothing { + return + } + m.flushPruningHeights(batch) + m.flushPruningSnapshotHeights(batch) +} + +// LoadPruningHeights loads the pruning heights from the database as a crash recovery. +func (m *Manager) LoadPruningHeights(db dbm.DB) error { + if m.opts.GetPruningStrategy() == types.PruningNothing { + return nil + } + if err := m.loadPruningHeights(db); err != nil { + return err + } + if err := m.loadPruningSnapshotHeights(db); err != nil { + return err + } + return nil +} + +func (m *Manager) loadPruningHeights(db dbm.DB) error { + bz, err := db.Get([]byte(pruneHeightsKey)) + if err != nil { + return fmt.Errorf("failed to get pruned heights: %w", err) + } + if len(bz) == 0 { + return nil + } + + prunedHeights := make([]int64, len(bz)/8) + i, offset := 0, 0 + for offset < len(bz) { + prunedHeights[i] = int64(binary.BigEndian.Uint64(bz[offset : offset+8])) + i++ + offset += 8 + } + + if len(prunedHeights) > 0 { + m.pruneHeights = prunedHeights + } + + return nil +} + +func (m *Manager) loadPruningSnapshotHeights(db dbm.DB) error { + bz, err := db.Get([]byte(pruneSnapshotHeightsKey)) + if err != nil { + return fmt.Errorf("failed to get post-snapshot pruned heights: %w", err) + } + if len(bz) == 0 { + return nil + } + + pruneSnapshotHeights := list.New() + i, offset := 0, 0 + for offset < len(bz) { + pruneSnapshotHeights.PushBack(int64(binary.BigEndian.Uint64(bz[offset : offset+8]))) + i++ + offset += 8 + } + + if pruneSnapshotHeights.Len() > 0 { + m.mx.Lock() + defer m.mx.Unlock() + m.pruneSnapshotHeights = pruneSnapshotHeights + } + + return nil +} + +func (m *Manager) flushPruningHeights(batch dbm.Batch) { + bz := make([]byte, 0) + for _, ph := range m.pruneHeights { + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, uint64(ph)) + bz = append(bz, buf...) + } + + batch.Set([]byte(pruneHeightsKey), bz) +} + +func (m *Manager) flushPruningSnapshotHeights(batch dbm.Batch) { + m.mx.Lock() + defer m.mx.Unlock() + bz := make([]byte, 0) + for e := m.pruneSnapshotHeights.Front(); e != nil; e = e.Next() { + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, uint64(e.Value.(int64))) + bz = append(bz, buf...) + } + batch.Set([]byte(pruneSnapshotHeightsKey), bz) +} diff --git a/pruning/manager_test.go b/pruning/manager_test.go new file mode 100644 index 000000000000..bd45bf8b47db --- /dev/null +++ b/pruning/manager_test.go @@ -0,0 +1,274 @@ +package pruning_test + +import ( + "container/list" + "fmt" + + "sync" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/pruning" + "github.com/cosmos/cosmos-sdk/pruning/types" + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/libs/log" + db "github.com/tendermint/tm-db" +) + +func Test_NewManager(t *testing.T) { + manager := pruning.NewManager(log.NewNopLogger()) + + require.NotNil(t, manager) + require.NotNil(t, manager.GetPruningHeights()) + require.Equal(t, types.PruningNothing, manager.GetOptions().GetPruningStrategy()) +} + +func Test_Strategies(t *testing.T) { + testcases := map[string]struct { + strategy *types.PruningOptions + snapshotInterval uint64 + strategyToAssert types.PruningStrategy + isValid bool + }{ + "prune nothing - no snapshot": { + strategy: types.NewPruningOptions(types.PruningNothing), + strategyToAssert: types.PruningNothing, + }, + "prune nothing - snapshot": { + strategy: types.NewPruningOptions(types.PruningNothing), + strategyToAssert: types.PruningNothing, + snapshotInterval: 100, + }, + "prune default - no snapshot": { + strategy: types.NewPruningOptions(types.PruningDefault), + strategyToAssert: types.PruningDefault, + }, + "prune default - snapshot": { + strategy: types.NewPruningOptions(types.PruningDefault), + strategyToAssert: types.PruningDefault, + snapshotInterval: 100, + }, + "prune everything - no snapshot": { + strategy: types.NewPruningOptions(types.PruningEverything), + strategyToAssert: types.PruningEverything, + }, + "prune everything - snapshot": { + strategy: types.NewPruningOptions(types.PruningEverything), + strategyToAssert: types.PruningEverything, + snapshotInterval: 100, + }, + "custom 100-10-15": { + strategy: types.NewCustomPruningOptions(100, 15), + snapshotInterval: 10, + strategyToAssert: types.PruningCustom, + }, + "custom 10-10-15": { + strategy: types.NewCustomPruningOptions(10, 15), + snapshotInterval: 10, + strategyToAssert: types.PruningCustom, + }, + "custom 100-0-15": { + strategy: types.NewCustomPruningOptions(100, 15), + snapshotInterval: 0, + strategyToAssert: types.PruningCustom, + }, + } + + manager := pruning.NewManager(log.NewNopLogger()) + + require.NotNil(t, manager) + + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + curStrategy := tc.strategy + manager.SetSnapshotInterval(tc.snapshotInterval) + + pruneStrategy := curStrategy.GetPruningStrategy() + require.Equal(t, tc.strategyToAssert, pruneStrategy) + + // Validate strategy parameters + switch pruneStrategy { + case types.PruningDefault: + require.Equal(t, uint64(100000), curStrategy.KeepRecent) + require.Equal(t, uint64(100), curStrategy.Interval) + case types.PruningNothing: + require.Equal(t, uint64(0), curStrategy.KeepRecent) + require.Equal(t, uint64(0), curStrategy.Interval) + case types.PruningEverything: + require.Equal(t, uint64(2), curStrategy.KeepRecent) + require.Equal(t, uint64(10), curStrategy.Interval) + default: + // + } + + manager.SetOptions(curStrategy) + require.Equal(t, tc.strategy, manager.GetOptions()) + + curKeepRecent := curStrategy.KeepRecent + curInterval := curStrategy.Interval + + for curHeight := int64(0); curHeight < 110000; curHeight++ { + handleHeightActual := manager.HandleHeight(curHeight) + shouldPruneAtHeightActual := manager.ShouldPruneAtHeight(curHeight) + + curPruningHeihts := manager.GetPruningHeights() + + curHeightStr := fmt.Sprintf("height: %d", curHeight) + + switch curStrategy.GetPruningStrategy() { + case types.PruningNothing: + require.Equal(t, int64(0), handleHeightActual, curHeightStr) + require.False(t, shouldPruneAtHeightActual, curHeightStr) + + require.Equal(t, 0, len(manager.GetPruningHeights())) + default: + if curHeight > int64(curKeepRecent) && (tc.snapshotInterval != 0 && (curHeight-int64(curKeepRecent))%int64(tc.snapshotInterval) != 0 || tc.snapshotInterval == 0) { + expectedHeight := curHeight - int64(curKeepRecent) + require.Equal(t, curHeight-int64(curKeepRecent), handleHeightActual, curHeightStr) + + require.Contains(t, curPruningHeihts, expectedHeight, curHeightStr) + } else { + require.Equal(t, int64(0), handleHeightActual, curHeightStr) + + require.Equal(t, 0, len(manager.GetPruningHeights())) + } + require.Equal(t, curHeight%int64(curInterval) == 0, shouldPruneAtHeightActual, curHeightStr) + } + manager.ResetPruningHeights() + require.Equal(t, 0, len(manager.GetPruningHeights())) + } + }) + } +} + +func Test_FlushLoad(t *testing.T) { + manager := pruning.NewManager(log.NewNopLogger()) + require.NotNil(t, manager) + + db := db.NewMemDB() + + curStrategy := types.NewCustomPruningOptions(100, 15) + + snapshotInterval := uint64(10) + manager.SetSnapshotInterval(snapshotInterval) + + manager.SetOptions(curStrategy) + require.Equal(t, curStrategy, manager.GetOptions()) + + keepRecent := curStrategy.KeepRecent + + heightsToPruneMirror := make([]int64, 0) + + for curHeight := int64(0); curHeight < 1000; curHeight++ { + handleHeightActual := manager.HandleHeight(curHeight) + + curHeightStr := fmt.Sprintf("height: %d", curHeight) + + if curHeight > int64(keepRecent) && (snapshotInterval != 0 && (curHeight-int64(keepRecent))%int64(snapshotInterval) != 0 || snapshotInterval == 0) { + expectedHandleHeight := curHeight - int64(keepRecent) + require.Equal(t, expectedHandleHeight, handleHeightActual, curHeightStr) + heightsToPruneMirror = append(heightsToPruneMirror, expectedHandleHeight) + } else { + require.Equal(t, int64(0), handleHeightActual, curHeightStr) + } + + if manager.ShouldPruneAtHeight(curHeight) { + manager.ResetPruningHeights() + heightsToPruneMirror = make([]int64, 0) + } + + // N.B.: There is no reason behind the choice of 3. + if curHeight%3 == 0 { + require.Equal(t, heightsToPruneMirror, manager.GetPruningHeights(), curHeightStr) + batch := db.NewBatch() + manager.FlushPruningHeights(batch) + require.NoError(t, batch.Write()) + require.NoError(t, batch.Close()) + + manager.ResetPruningHeights() + require.Equal(t, make([]int64, 0), manager.GetPruningHeights(), curHeightStr) + + err := manager.LoadPruningHeights(db) + require.NoError(t, err) + require.Equal(t, heightsToPruneMirror, manager.GetPruningHeights(), curHeightStr) + } + } +} + +func Test_WithSnapshot(t *testing.T) { + manager := pruning.NewManager(log.NewNopLogger()) + require.NotNil(t, manager) + + curStrategy := types.NewCustomPruningOptions(10, 10) + + snapshotInterval := uint64(15) + manager.SetSnapshotInterval(snapshotInterval) + + manager.SetOptions(curStrategy) + require.Equal(t, curStrategy, manager.GetOptions()) + + keepRecent := curStrategy.KeepRecent + + heightsToPruneMirror := make([]int64, 0) + + mx := sync.Mutex{} + snapshotHeightsToPruneMirror := list.New() + + wg := sync.WaitGroup{} + + for curHeight := int64(1); curHeight < 100000; curHeight++ { + mx.Lock() + handleHeightActual := manager.HandleHeight(curHeight) + + curHeightStr := fmt.Sprintf("height: %d", curHeight) + + if curHeight > int64(keepRecent) && (curHeight-int64(keepRecent))%int64(snapshotInterval) != 0 { + expectedHandleHeight := curHeight - int64(keepRecent) + require.Equal(t, expectedHandleHeight, handleHeightActual, curHeightStr) + heightsToPruneMirror = append(heightsToPruneMirror, expectedHandleHeight) + } else { + require.Equal(t, int64(0), handleHeightActual, curHeightStr) + } + + actualHeightsToPrune := manager.GetPruningHeights() + + var next *list.Element + for e := snapshotHeightsToPruneMirror.Front(); e != nil; e = next { + snapshotHeight := e.Value.(int64) + if snapshotHeight < curHeight-int64(keepRecent) { + heightsToPruneMirror = append(heightsToPruneMirror, snapshotHeight) + + // We must get next before removing to be able to continue iterating. + next = e.Next() + snapshotHeightsToPruneMirror.Remove(e) + } else { + next = e.Next() + } + } + + require.Equal(t, heightsToPruneMirror, actualHeightsToPrune, curHeightStr) + mx.Unlock() + + if manager.ShouldPruneAtHeight(curHeight) { + manager.ResetPruningHeights() + heightsToPruneMirror = make([]int64, 0) + } + + // Mimic taking snapshots in the background + if curHeight%int64(snapshotInterval) == 0 { + wg.Add(1) + go func(curHeightCp int64) { + time.Sleep(time.Nanosecond * 500) + + mx.Lock() + manager.HandleHeightSnapshot(curHeightCp) + snapshotHeightsToPruneMirror.PushBack(curHeightCp) + mx.Unlock() + wg.Done() + }(curHeight) + } + } + + wg.Wait() +} diff --git a/pruning/types/options.go b/pruning/types/options.go new file mode 100644 index 000000000000..84ed73b41e8c --- /dev/null +++ b/pruning/types/options.go @@ -0,0 +1,135 @@ +package types + +import ( + "errors" + "fmt" +) + +// PruningOptions defines the pruning strategy used when determining which +// heights are removed from disk when committing state. +type PruningOptions struct { + // KeepRecent defines how many recent heights to keep on disk. + KeepRecent uint64 + + // Interval defines when the pruned heights are removed from disk. + Interval uint64 + + // Strategy defines the kind of pruning strategy. See below for more information on each. + Strategy PruningStrategy +} + +type PruningStrategy int + +// Pruning option string constants +const ( + PruningOptionDefault = "default" + PruningOptionEverything = "everything" + PruningOptionNothing = "nothing" + PruningOptionCustom = "custom" +) + +const ( + // PruningDefault defines a pruning strategy where the last 100,000 heights are + // kept where to-be pruned heights are pruned at every 10th height. + // The last 100000 heights are kept(approximately 1 week worth of state) assuming the typical + // block time is 6s. If these values + // do not match the applications' requirements, use the "custom" option. + PruningDefault PruningStrategy = iota + // PruningEverything defines a pruning strategy where all committed heights are + // deleted, storing only the current height and last 2 states. To-be pruned heights are + // pruned at every 10th height. + PruningEverything + // PruningNothing defines a pruning strategy where all heights are kept on disk. + // This is the only stretegy where KeepEvery=1 is allowed with state-sync snapshots disabled. + PruningNothing + // PruningCustom defines a pruning strategy where the user specifies the pruning. + PruningCustom + // PruningUndefined defines an undefined pruning strategy. It is to be returned by stores that do not support pruning. + PruningUndefined +) + +const ( + pruneEverythingKeepRecent = 2 + pruneEverythingInterval = 10 +) + +var ( + ErrPruningIntervalZero = errors.New("'pruning-interval' must not be 0. If you want to disable pruning, select pruning = \"nothing\"") + ErrPruningIntervalTooSmall = fmt.Errorf("'pruning-interval' must not be less than %d. For the most aggressive pruning, select pruning = \"everything\"", pruneEverythingInterval) + ErrPruningKeepRecentTooSmall = fmt.Errorf("'pruning-keep-recent' must not be less than %d. For the most aggressive pruning, select pruning = \"everything\"", pruneEverythingKeepRecent) +) + +func NewPruningOptions(pruningStrategy PruningStrategy) *PruningOptions { + switch pruningStrategy { + case PruningDefault: + return &PruningOptions{ + KeepRecent: 100_000, + Interval: 100, + Strategy: PruningDefault, + } + case PruningEverything: + return &PruningOptions{ + KeepRecent: pruneEverythingKeepRecent, + Interval: pruneEverythingInterval, + Strategy: PruningEverything, + } + case PruningNothing: + return &PruningOptions{ + KeepRecent: 0, + Interval: 0, + Strategy: PruningNothing, + } + case PruningCustom: + return &PruningOptions{ + Strategy: PruningCustom, + } + default: + return &PruningOptions{ + Strategy: PruningUndefined, + } + } +} + +func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { + return &PruningOptions{ + KeepRecent: keepRecent, + Interval: interval, + Strategy: PruningCustom, + } +} + +func (po PruningOptions) GetPruningStrategy() PruningStrategy { + return po.Strategy +} + +func (po PruningOptions) Validate() error { + if po.Strategy == PruningNothing { + return nil + } + if po.Interval == 0 { + return ErrPruningIntervalZero + } + if po.Interval < pruneEverythingInterval { + return ErrPruningIntervalTooSmall + } + if po.KeepRecent < pruneEverythingKeepRecent { + return ErrPruningKeepRecentTooSmall + } + return nil +} + +func NewPruningOptionsFromString(strategy string) *PruningOptions { + switch strategy { + case PruningOptionEverything: + return NewPruningOptions(PruningEverything) + + case PruningOptionNothing: + return NewPruningOptions(PruningNothing) + + case PruningOptionDefault: + return NewPruningOptions(PruningDefault) + + default: + return NewPruningOptions(PruningDefault) + } +} diff --git a/pruning/types/options_test.go b/pruning/types/options_test.go new file mode 100644 index 000000000000..c2d4e93e5ccd --- /dev/null +++ b/pruning/types/options_test.go @@ -0,0 +1,29 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPruningOptions_Validate(t *testing.T) { + testCases := []struct { + opts *PruningOptions + expectErr error + }{ + {NewPruningOptions(PruningDefault), nil}, + {NewPruningOptions(PruningEverything), nil}, + {NewPruningOptions(PruningNothing), nil}, + {NewCustomPruningOptions(2, 10), nil}, + {NewCustomPruningOptions(100, 15), nil}, + {NewCustomPruningOptions(1, 10), ErrPruningKeepRecentTooSmall}, + {NewCustomPruningOptions(2, 9), ErrPruningIntervalTooSmall}, + {NewCustomPruningOptions(2, 0), ErrPruningIntervalZero}, + {NewCustomPruningOptions(2, 0), ErrPruningIntervalZero}, + } + + for _, tc := range testCases { + err := tc.opts.Validate() + require.Equal(t, tc.expectErr, err, "options: %v, err: %s", tc.opts, err) + } +} diff --git a/server/config/config.go b/server/config/config.go index 8d4c003eae46..7e37e015177f 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -6,8 +6,8 @@ import ( "github.com/spf13/viper" - storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/telemetry" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -211,7 +211,7 @@ func DefaultConfig() *Config { BaseConfig: BaseConfig{ MinGasPrices: defaultMinGasPrices, InterBlockCache: true, - Pruning: storetypes.PruningOptionDefault, + Pruning: pruningTypes.PruningOptionDefault, PruningKeepRecent: "0", PruningInterval: "0", MinRetainBlocks: 0, @@ -327,9 +327,9 @@ func (c Config) ValidateBasic() error { if c.BaseConfig.MinGasPrices == "" { return sdkerrors.ErrAppConfig.Wrap("set min gas price in app.toml or flag or env variable") } - if c.Pruning == storetypes.PruningOptionEverything && c.StateSync.SnapshotInterval > 0 { + if c.Pruning == pruningTypes.PruningOptionEverything && c.StateSync.SnapshotInterval > 0 { return sdkerrors.ErrAppConfig.Wrapf( - "cannot enable state sync snapshots with '%s' pruning setting", storetypes.PruningOptionEverything, + "cannot enable state sync snapshots with '%s' pruning setting", pruningTypes.PruningOptionEverything, ) } diff --git a/server/config/toml.go b/server/config/toml.go index 4b574b5e7849..a9664db554cd 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -24,8 +24,8 @@ minimum-gas-prices = "{{ .BaseConfig.MinGasPrices }}" # default: the last 362880 states are kept, pruning at 10 block intervals # nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) -# everything: all saved states will be deleted, storing only the current and previous state; pruning at 10 block intervals -# custom: allow pruning options to be manually specified through 'pruning-keep-recent' and 'pruning-interval' +# everything: 2 latest states will be kept; pruning at 10 block intervals. +# custom: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' pruning = "{{ .BaseConfig.Pruning }}" # These are applied if and only if the pruning strategy is custom. diff --git a/server/mock/store.go b/server/mock/store.go index 37852de711eb..6aa339218211 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -6,15 +6,16 @@ import ( protoio "github.com/gogo/protobuf/io" dbm "github.com/tendermint/tm-db" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" - storetypes "github.com/cosmos/cosmos-sdk/store/types" + snapshotTypes "github.com/cosmos/cosmos-sdk/snapshots/types" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + storeTypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" ) var _ sdk.MultiStore = multiStore{} type multiStore struct { - kv map[storetypes.StoreKey]kvStore + kv map[storeTypes.StoreKey]kvStore } func (ms multiStore) CacheMultiStore() sdk.CacheMultiStore { @@ -25,15 +26,15 @@ func (ms multiStore) CacheMultiStoreWithVersion(_ int64) (sdk.CacheMultiStore, e panic("not implemented") } -func (ms multiStore) CacheWrap() storetypes.CacheWrap { +func (ms multiStore) CacheWrap() storeTypes.CacheWrap { panic("not implemented") } -func (ms multiStore) CacheWrapWithTrace(_ io.Writer, _ sdk.TraceContext) storetypes.CacheWrap { +func (ms multiStore) CacheWrapWithTrace(_ io.Writer, _ sdk.TraceContext) storeTypes.CacheWrap { panic("not implemented") } -func (ms multiStore) CacheWrapWithListeners(_ storetypes.StoreKey, _ []storetypes.WriteListener) storetypes.CacheWrap { +func (ms multiStore) CacheWrapWithListeners(_ storeTypes.StoreKey, _ []storeTypes.WriteListener) storeTypes.CacheWrap { panic("not implemented") } @@ -49,39 +50,43 @@ func (ms multiStore) SetTracer(w io.Writer) sdk.MultiStore { panic("not implemented") } -func (ms multiStore) AddListeners(key storetypes.StoreKey, listeners []storetypes.WriteListener) { +func (ms multiStore) AddListeners(key storeTypes.StoreKey, listeners []storeTypes.WriteListener) { panic("not implemented") } -func (ms multiStore) ListeningEnabled(key storetypes.StoreKey) bool { +func (ms multiStore) ListeningEnabled(key storeTypes.StoreKey) bool { panic("not implemented") } -func (ms multiStore) Commit() storetypes.CommitID { +func (ms multiStore) Commit() storeTypes.CommitID { panic("not implemented") } -func (ms multiStore) LastCommitID() storetypes.CommitID { +func (ms multiStore) LastCommitID() storeTypes.CommitID { panic("not implemented") } -func (ms multiStore) SetPruning(opts sdk.PruningOptions) { +func (ms multiStore) SetPruning(opts *pruningTypes.PruningOptions) { panic("not implemented") } -func (ms multiStore) GetPruning() sdk.PruningOptions { +func (ms multiStore) GetPruning() *pruningTypes.PruningOptions { panic("not implemented") } -func (ms multiStore) GetCommitKVStore(key storetypes.StoreKey) storetypes.CommitKVStore { +func (ms multiStore) GetCommitKVStore(key storeTypes.StoreKey) storeTypes.CommitKVStore { panic("not implemented") } -func (ms multiStore) GetCommitStore(key storetypes.StoreKey) storetypes.CommitStore { +func (ms multiStore) GetCommitStore(key storeTypes.StoreKey) storeTypes.CommitStore { panic("not implemented") } -func (ms multiStore) MountStoreWithDB(key storetypes.StoreKey, typ storetypes.StoreType, db dbm.DB) { +func (ms multiStore) GetCommitKVStores() map[storeTypes.StoreKey]storeTypes.CommitKVStore { + panic("not implemented") +} + +func (ms multiStore) MountStoreWithDB(key storeTypes.StoreKey, typ storeTypes.StoreType, db dbm.DB) { ms.kv[key] = kvStore{store: make(map[string][]byte)} } @@ -89,11 +94,11 @@ func (ms multiStore) LoadLatestVersion() error { return nil } -func (ms multiStore) LoadLatestVersionAndUpgrade(upgrades *storetypes.StoreUpgrades) error { +func (ms multiStore) LoadLatestVersionAndUpgrade(upgrades *storeTypes.StoreUpgrades) error { return nil } -func (ms multiStore) LoadVersionAndUpgrade(ver int64, upgrades *storetypes.StoreUpgrades) error { +func (ms multiStore) LoadVersionAndUpgrade(ver int64, upgrades *storeTypes.StoreUpgrades) error { panic("not implemented") } @@ -101,15 +106,23 @@ func (ms multiStore) LoadVersion(ver int64) error { panic("not implemented") } -func (ms multiStore) GetKVStore(key storetypes.StoreKey) sdk.KVStore { +func (ms multiStore) GetKVStore(key storeTypes.StoreKey) sdk.KVStore { return ms.kv[key] } -func (ms multiStore) GetStore(key storetypes.StoreKey) sdk.Store { +func (ms multiStore) GetStore(key storeTypes.StoreKey) sdk.Store { + panic("not implemented") +} + +func (ms multiStore) GetStoreType() storeTypes.StoreType { + panic("not implemented") +} + +func (ms multiStore) PruneSnapshotHeight(height int64) { panic("not implemented") } -func (ms multiStore) GetStoreType() storetypes.StoreType { +func (ms multiStore) SetSnapshotInterval(snapshotInterval uint64) { panic("not implemented") } @@ -130,7 +143,7 @@ func (ms multiStore) Snapshot(height uint64, protoWriter protoio.Writer) error { func (ms multiStore) Restore( height uint64, format uint32, protoReader protoio.Reader, -) (snapshottypes.SnapshotItem, error) { +) (snapshotTypes.SnapshotItem, error) { panic("not implemented") } @@ -140,19 +153,19 @@ type kvStore struct { store map[string][]byte } -func (kv kvStore) CacheWrap() storetypes.CacheWrap { +func (kv kvStore) CacheWrap() storeTypes.CacheWrap { panic("not implemented") } -func (kv kvStore) CacheWrapWithTrace(w io.Writer, tc sdk.TraceContext) storetypes.CacheWrap { +func (kv kvStore) CacheWrapWithTrace(w io.Writer, tc sdk.TraceContext) storeTypes.CacheWrap { panic("not implemented") } -func (kv kvStore) CacheWrapWithListeners(_ storetypes.StoreKey, _ []storetypes.WriteListener) storetypes.CacheWrap { +func (kv kvStore) CacheWrapWithListeners(_ storeTypes.StoreKey, _ []storeTypes.WriteListener) storeTypes.CacheWrap { panic("not implemented") } -func (kv kvStore) GetStoreType() storetypes.StoreType { +func (kv kvStore) GetStoreType() storeTypes.StoreType { panic("not implemented") } @@ -170,7 +183,7 @@ func (kv kvStore) Has(key []byte) bool { } func (kv kvStore) Set(key, value []byte) { - storetypes.AssertValidKey(key) + storeTypes.AssertValidKey(key) kv.store[string(key)] = value } @@ -203,5 +216,5 @@ func (kv kvStore) ReverseSubspaceIterator(prefix []byte) sdk.Iterator { } func NewCommitMultiStore() sdk.CommitMultiStore { - return multiStore{kv: make(map[storetypes.StoreKey]kvStore)} + return multiStore{kv: make(map[storeTypes.StoreKey]kvStore)} } diff --git a/server/pruning.go b/server/pruning.go index fb2ba34e8f87..d6d48de0b8e2 100644 --- a/server/pruning.go +++ b/server/pruning.go @@ -7,22 +7,21 @@ import ( "github.com/spf13/cast" "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/store" - storetypes "github.com/cosmos/cosmos-sdk/store/types" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" ) // GetPruningOptionsFromFlags parses command flags and returns the correct // PruningOptions. If a pruning strategy is provided, that will be parsed and // returned, otherwise, it is assumed custom pruning options are provided. -func GetPruningOptionsFromFlags(appOpts types.AppOptions) (storetypes.PruningOptions, error) { +func GetPruningOptionsFromFlags(appOpts types.AppOptions) (*pruningTypes.PruningOptions, error) { strategy := strings.ToLower(cast.ToString(appOpts.Get(FlagPruning))) switch strategy { - case storetypes.PruningOptionDefault, storetypes.PruningOptionNothing, storetypes.PruningOptionEverything: - return storetypes.NewPruningOptionsFromString(strategy), nil + case pruningTypes.PruningOptionDefault, pruningTypes.PruningOptionNothing, pruningTypes.PruningOptionEverything: + return pruningTypes.NewPruningOptionsFromString(strategy), nil - case storetypes.PruningOptionCustom: - opts := storetypes.NewPruningOptions( + case pruningTypes.PruningOptionCustom: + opts := pruningTypes.NewCustomPruningOptions( cast.ToUint64(appOpts.Get(FlagPruningKeepRecent)), cast.ToUint64(appOpts.Get(FlagPruningInterval)), ) @@ -34,6 +33,6 @@ func GetPruningOptionsFromFlags(appOpts types.AppOptions) (storetypes.PruningOpt return opts, nil default: - return store.PruningOptions{}, fmt.Errorf("unknown pruning strategy %s", strategy) + return nil, fmt.Errorf("unknown pruning strategy %s", strategy) } } diff --git a/server/pruning_test.go b/server/pruning_test.go index 8b4af74cad8b..f7f5a97efe19 100644 --- a/server/pruning_test.go +++ b/server/pruning_test.go @@ -6,48 +6,45 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/store/types" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" ) func TestGetPruningOptionsFromFlags(t *testing.T) { tests := []struct { name string initParams func() *viper.Viper - expectedOptions types.PruningOptions + expectedOptions *pruningTypes.PruningOptions wantErr bool }{ { name: FlagPruning, initParams: func() *viper.Viper { v := viper.New() - v.Set(FlagPruning, types.PruningOptionNothing) + v.Set(FlagPruning, pruningTypes.PruningOptionNothing) return v }, - expectedOptions: types.PruneNothing, + expectedOptions: pruningTypes.NewPruningOptions(pruningTypes.PruningNothing), }, { name: "custom pruning options", initParams: func() *viper.Viper { v := viper.New() - v.Set(FlagPruning, types.PruningOptionCustom) + v.Set(FlagPruning, pruningTypes.PruningOptionCustom) v.Set(FlagPruningKeepRecent, 1234) v.Set(FlagPruningInterval, 10) return v }, - expectedOptions: types.PruningOptions{ - KeepRecent: 1234, - Interval: 10, - }, + expectedOptions: pruningTypes.NewCustomPruningOptions(1234, 10), }, { - name: types.PruningOptionDefault, + name: pruningTypes.PruningOptionDefault, initParams: func() *viper.Viper { v := viper.New() - v.Set(FlagPruning, types.PruningOptionDefault) + v.Set(FlagPruning, pruningTypes.PruningOptionDefault) return v }, - expectedOptions: types.PruneDefault, + expectedOptions: pruningTypes.NewPruningOptions(pruningTypes.PruningDefault), }, } @@ -56,7 +53,7 @@ func TestGetPruningOptionsFromFlags(t *testing.T) { t.Run(tt.name, func(j *testing.T) { viper.Reset() - viper.SetDefault(FlagPruning, types.PruningOptionDefault) + viper.SetDefault(FlagPruning, pruningTypes.PruningOptionDefault) v := tt.initParams() opts, err := GetPruningOptionsFromFlags(v) diff --git a/server/rollback.go b/server/rollback.go index 1413967d54b7..6f4561b8474a 100644 --- a/server/rollback.go +++ b/server/rollback.go @@ -36,7 +36,7 @@ application. return fmt.Errorf("failed to rollback tendermint state: %w", err) } // rollback the multistore - cms := rootmulti.NewStore(db) + cms := rootmulti.NewStore(db, ctx.Logger) cms.RollbackToVersion(height) fmt.Printf("Rolled back state to height %d and hash %X", height, hash) diff --git a/server/start.go b/server/start.go index 6cbaf0a5a343..f0f3d1a0af19 100644 --- a/server/start.go +++ b/server/start.go @@ -10,28 +10,28 @@ import ( "runtime/pprof" "time" - "github.com/spf13/cobra" - abciclient "github.com/tendermint/tendermint/abci/client" - "github.com/tendermint/tendermint/abci/server" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - tmos "github.com/tendermint/tendermint/libs/os" - tmservice "github.com/tendermint/tendermint/libs/service" - "github.com/tendermint/tendermint/node" - "github.com/tendermint/tendermint/rpc/client/local" - tmtypes "github.com/tendermint/tendermint/types" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" - servergrpc "github.com/cosmos/cosmos-sdk/server/grpc" "github.com/cosmos/cosmos-sdk/server/rosetta" - crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server" "github.com/cosmos/cosmos-sdk/server/types" - storetypes "github.com/cosmos/cosmos-sdk/store/types" + servergrpc "github.com/cosmos/cosmos-sdk/server/grpc" + crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + + "github.com/spf13/cobra" + "github.com/tendermint/tendermint/abci/server" + "github.com/tendermint/tendermint/node" + "github.com/tendermint/tendermint/rpc/client/local" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + abciclient "github.com/tendermint/tendermint/abci/client" + tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" + tmos "github.com/tendermint/tendermint/libs/os" + tmservice "github.com/tendermint/tendermint/libs/service" + tmtypes "github.com/tendermint/tendermint/types" ) const ( @@ -86,15 +86,15 @@ func StartCmd(appCreator types.AppCreator, defaultNodeHome string) *cobra.Comman Long: `Run the full node application with Tendermint in or out of process. By default, the application will run with Tendermint in process. -Pruning options can be provided via the '--pruning' flag or alternatively with '--pruning-keep-recent' -and 'pruning-interval' together. +Pruning options can be provided via the '--pruning' flag or alternatively with '--pruning-keep-recent', and +'pruning-interval' together. For '--pruning' the options are as follows: default: the last 362880 states are kept, pruning at 10 block intervals nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) -everything: all saved states will be deleted, storing only the current and previous state; pruning at 10 block intervals -custom: allow pruning options to be manually specified through 'pruning-keep-recent' and 'pruning-interval' +everything: all saved states will be deleted, storing only the current state; pruning at 10 block intervals +custom: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' Node halting configurations exist in the form of two flags: '--halt-height' and '--halt-time'. During the ABCI Commit phase, the node will check if the current block height is greater than or equal to @@ -159,7 +159,7 @@ is performed. Note, when enabled, gRPC will also be automatically enabled. cmd.Flags().Bool(FlagInterBlockCache, true, "Enable inter-block caching") cmd.Flags().String(flagCPUProfile, "", "Enable CPU profiling and write to the provided file") cmd.Flags().Bool(FlagTrace, false, "Provide full stack traces for errors in ABCI Log") - cmd.Flags().String(FlagPruning, storetypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)") + cmd.Flags().String(FlagPruning, pruningTypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)") cmd.Flags().Uint64(FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')") cmd.Flags().Uint64(FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')") cmd.Flags().Uint(FlagInvCheckPeriod, 0, "Assert registered invariants every N blocks") diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 9ae7f10a7b48..bc84fd98c573 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -270,6 +270,10 @@ func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, a panic(err) } + snapshotOptions := sdk.NewSnapshotOptions( + cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval)), + cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))) + return simapp.NewSimApp( logger, db, traceStore, true, skipUpgradeHeights, cast.ToString(appOpts.Get(flags.FlagHome)), @@ -284,9 +288,7 @@ func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, a baseapp.SetInterBlockCache(cache), baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), - baseapp.SetSnapshotStore(snapshotStore), - baseapp.SetSnapshotInterval(cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval))), - baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))), + baseapp.SetSnapshot(snapshotStore, snapshotOptions), ) } diff --git a/snapshots/README.md b/snapshots/README.md index 8f6e526f0832..8d7b314d86d8 100644 --- a/snapshots/README.md +++ b/snapshots/README.md @@ -28,7 +28,9 @@ filesystem under `/data/snapshots/`, with metadata in a LevelDB datab Snapshots are taken asynchronously, i.e. new blocks will be applied concurrently with snapshots being taken. This is possible because IAVL supports querying -immutable historical heights. +immutable historical heights. However, this requires heights that are multiples of `state-sync.snapshot-interval` +to be kept until after the snapshot is complete. It is done to prevent a height from being removed +while it is being snapshotted. When a remote node is state syncing, Tendermint calls the ABCI method `ListSnapshots` to list available local snapshots and `LoadSnapshotChunk` to @@ -47,6 +49,38 @@ can be trivially forged by an adversary. This was considered out of scope for the initial implementation, but can be added later without changes to the ABCI state sync protocol. +## Relationship to Pruning + +Snapshot settings are optional. However, if set, they have an effect on how pruning is done by +persisting the heights that are multiples of `state-sync.snapshot-interval` until after the snapshot is complete. + +If pruning is enabled (not `pruning = "nothing"`), we avoid pruning heights that are multiples of +`state-sync.snapshot-interval` in the regular logic determined by the +pruning settings and applied after every `Commit()`. This is done to prevent a +height from being removed before a snapshot is complete. Therefore, we keep +such heights until after a snapshot is done. At this point, the height is sent to +the `pruning.Manager` to be pruned according to the pruning settings after the next `Commit()`. + +To illustrate, assume that we are currently at height 960 with `pruning-keep-recent = 50`, +`pruning-interval = 10`, and `state-sync.snapshot-interval = 100`. Let's assume that +the snapshot that was triggered at height `900` just finishes. Then, we can prune height +`900` right away (that is, when we call `Commit()` at height 960) because it (`900`) is less than `960 - 50 = 910`. + +Let's now assume that all settings stay the same but `pruning-keep-recent = 100`. In that case, +we cannot prune height `900` which is greater than `960 - 100 = 850`. As a result, height 900 is persisted until +we can prune it according to the pruning settings. + +## Configuration + +- `state-sync.snapshot-interval` + * the interval at which to take snapshots. + * the value of 0 disables snapshots. + * if pruning is enabled, it is done after a snapshot is complete for the heights that are multiples of this interval. + +- `state-sync.snapshot-keep-recent`: + * the number of recent snapshots to keep. + * 0 means keep all. + ## Snapshot Metadata The ABCI Protobuf type for a snapshot is listed below (refer to the ABCI spec @@ -181,7 +215,9 @@ concurrently. During `BaseApp.Commit`, once a state transition has been committed, the height is checked against the `state-sync.snapshot-interval` setting. If the committed height should be snapshotted, a goroutine `BaseApp.snapshot()` is spawned that -calls `snapshots.Manager.Create()` to create the snapshot. +calls `snapshots.Manager.Create()` to create the snapshot. Once a snapshot is +complete and if pruning is enabled, the snapshot height is pruned away by the manager +with the call `PruneSnapshotHeight(...)` to the `snapshots.types.Snapshotter`. `Manager.Create()` will do some basic pre-flight checks, and then start generating a snapshot by calling `rootmulti.Store.Snapshot()`. The chunk stream diff --git a/snapshots/helpers_test.go b/snapshots/helpers_test.go index 63775d3dda2c..6a849fc9f062 100644 --- a/snapshots/helpers_test.go +++ b/snapshots/helpers_test.go @@ -13,6 +13,7 @@ import ( protoio "github.com/gogo/protobuf/io" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" db "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/snapshots" @@ -95,6 +96,8 @@ func snapshotItems(items [][]byte) [][]byte { type mockSnapshotter struct { items [][]byte + prunedHeights map[int64]struct{} + snapshotInterval uint64 } func (m *mockSnapshotter) Restore( @@ -138,10 +141,23 @@ func (m *mockSnapshotter) Snapshot(height uint64, protoWriter protoio.Writer) er func (m *mockSnapshotter) SnapshotFormat() uint32 { return types.CurrentFormat } + func (m *mockSnapshotter) SupportedFormats() []uint32 { return []uint32{types.CurrentFormat} } +func (m *mockSnapshotter) PruneSnapshotHeight(height int64) { + m.prunedHeights[height] = struct{}{} +} + +func (m *mockSnapshotter) GetSnapshotInterval() uint64 { + return m.snapshotInterval +} + +func (m *mockSnapshotter) SetSnapshotInterval(snapshotInterval uint64) { + m.snapshotInterval = snapshotInterval +} + // setupBusyManager creates a manager with an empty store that is busy creating a snapshot at height 1. // The snapshot will complete when the returned closer is called. func setupBusyManager(t *testing.T) *snapshots.Manager { @@ -155,11 +171,14 @@ func setupBusyManager(t *testing.T) *snapshots.Manager { store, err := snapshots.NewStore(db.NewMemDB(), tempdir) require.NoError(t, err) hung := newHungSnapshotter() - mgr := snapshots.NewManager(store, hung, nil) + mgr := snapshots.NewManager(store, opts, hung, nil, log.NewNopLogger()) + require.Equal(t, opts.Interval, hung.snapshotInterval) go func() { _, err := mgr.Create(1) require.NoError(t, err) + _, didPruneHeight := hung.prunedHeights[1] + require.True(t, didPruneHeight) }() time.Sleep(10 * time.Millisecond) t.Cleanup(hung.Close) @@ -170,11 +189,14 @@ func setupBusyManager(t *testing.T) *snapshots.Manager { // hungSnapshotter can be used to test operations in progress. Call close to end the snapshot. type hungSnapshotter struct { ch chan struct{} + prunedHeights map[int64]struct{} + snapshotInterval uint64 } func newHungSnapshotter() *hungSnapshotter { return &hungSnapshotter{ ch: make(chan struct{}), + prunedHeights: make(map[int64]struct{}), } } @@ -187,6 +209,14 @@ func (m *hungSnapshotter) Snapshot(height uint64, protoWriter protoio.Writer) er return nil } +func (m *hungSnapshotter) PruneSnapshotHeight(height int64) { + m.prunedHeights[height] = struct{}{} +} + +func (m *hungSnapshotter) SetSnapshotInterval(snapshotInterval uint64) { + m.snapshotInterval = snapshotInterval +} + func (m *hungSnapshotter) Restore( height uint64, format uint32, protoReader protoio.Reader, ) (types.SnapshotItem, error) { diff --git a/snapshots/manager.go b/snapshots/manager.go index 2d94d1561c4e..02e2458df42c 100644 --- a/snapshots/manager.go +++ b/snapshots/manager.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/sha256" "fmt" + "errors" "io" "math" "sort" @@ -11,28 +12,9 @@ import ( "github.com/cosmos/cosmos-sdk/snapshots/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/tendermint/tendermint/libs/log" ) -const ( - opNone operation = "" - opSnapshot operation = "snapshot" - opPrune operation = "prune" - opRestore operation = "restore" - - chunkBufferSize = 4 - - snapshotMaxItemSize = int(64e6) // SDK has no key/value size limit, so we set an arbitrary limit -) - -// operation represents a Manager operation. Only one operation can be in progress at a time. -type operation string - -// restoreDone represents the result of a restore operation. -type restoreDone struct { - complete bool // if true, restore completed successfully (not prematurely) - err error // if non-nil, restore errored -} - // Manager manages snapshot and restore operations for an app, making sure only a single // long-running operation is in progress at any given time, and provides convenience methods // mirroring the ABCI interface. @@ -47,9 +29,13 @@ type restoreDone struct { // 2) io.ReadCloser streams automatically propagate IO errors, and can pass arbitrary // errors via io.Pipe.CloseWithError(). type Manager struct { - store *Store - multistore types.Snapshotter extensions map[string]types.ExtensionSnapshotter + // store is the snapshot store where all completed snapshots are persisted. + store *Store + opts *types.SnapshotOptions + // multistore is the store from which snapshots are taken. + multistore types.Snapshotter + logger log.Logger mtx sync.Mutex operation operation @@ -59,12 +45,39 @@ type Manager struct { restoreChunkIndex uint32 } +// operation represents a Manager operation. Only one operation can be in progress at a time. +type operation string + +// restoreDone represents the result of a restore operation. +type restoreDone struct { + complete bool // if true, restore completed successfully (not prematurely) + err error // if non-nil, restore errored +} + +const ( + opNone operation = "" + opSnapshot operation = "snapshot" + opPrune operation = "prune" + opRestore operation = "restore" + + chunkBufferSize = 4 + + snapshotMaxItemSize = int(64e6) // SDK has no key/value size limit, so we set an arbitrary limit +) + +var ( + ErrOptsZeroSnapshotInterval = errors.New("snaphot-interval must not be 0") +) + // NewManager creates a new manager. -func NewManager(store *Store, multistore types.Snapshotter, extensions map[string]types.ExtensionSnapshotter) *Manager { +func NewManager(store *Store, opts *types.SnapshotOptions, multistore types.Snapshotter, extensions map[string]types.ExtensionSnapshotter, logger log.Logger) *Manager { + multistore.SetSnapshotInterval(opts.Interval) return &Manager{ - store: store, + store: store, + opts: opts, multistore: multistore, extensions: extensions, + logger: logger, } } @@ -121,15 +134,22 @@ func (m *Manager) endLocked() { m.restoreChunkIndex = 0 } -// sortedExtensionNames sort extension names for deterministic iteration. -func (m *Manager) sortedExtensionNames() []string { - names := make([]string, 0, len(m.extensions)) - for name := range m.extensions { - names = append(names, name) - } +// GetInterval returns snapshot interval. +func (m *Manager) GetInterval() uint64 { + return m.opts.Interval +} - sort.Strings(names) - return names +// GetKeepRecent returns snapshot keep-recent. +func (m *Manager) GetKeepRecent() uint32 { + return m.opts.KeepRecent +} + +// GetSnapshotBlockRetentionHeights returns the number of heights needed +// for block retention. Blocks since the oldest available snapshot must be +// available for state sync nodes to catch up (oldest because a node may be +// restoring an old snapshot while a new snapshot was taken). +func (m *Manager) GetSnapshotBlockRetentionHeights() int64 { + return int64(m.opts.Interval * uint64(m.opts.KeepRecent)) } // Create creates a snapshot and returns its metadata. @@ -137,6 +157,9 @@ func (m *Manager) Create(height uint64) (*types.Snapshot, error) { if m == nil { return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "no snapshot store configured") } + + defer m.multistore.PruneSnapshotHeight(int64(height)) + err := m.begin(opSnapshot) if err != nil { return nil, err @@ -367,6 +390,17 @@ func (m *Manager) RestoreChunk(chunk []byte) (bool, error) { return false, nil } +// sortedExtensionNames sort extension names for deterministic iteration. +func (m *Manager) sortedExtensionNames() []string { + names := make([]string, 0, len(m.extensions)) + for name := range m.extensions { + names = append(names, name) + } + + sort.Strings(names) + return names +} + // IsFormatSupported returns if the snapshotter supports restoration from given format. func IsFormatSupported(snapshotter types.ExtensionSnapshotter, format uint32) bool { for _, i := range snapshotter.SupportedFormats() { @@ -376,3 +410,45 @@ func IsFormatSupported(snapshotter types.ExtensionSnapshotter, format uint32) bo } return false } + +// SnapshotIfApplicable takes a snapshot of the current state if we are on a snapshot height. +// It also prunes any old snapshots. The snapshotting and pruning happen in separate goroutines. +func (m *Manager) SnapshotIfApplicable(height int64) { + if m == nil { + return + } + if !m.shouldTakeSnapshot(height) { + m.logger.Debug("snapshot is skipped", "height", height) + return + } + go m.snapshot(height) +} + +// shouldTakeSnapshot returns true is snapshot should be taken at height. +func (m *Manager) shouldTakeSnapshot(height int64) bool { + return m.opts.Interval > 0 && uint64(height)%m.opts.Interval == 0 +} + +func (m *Manager) snapshot(height int64) { + m.logger.Info("creating state snapshot", "height", height) + + snapshot, err := m.Create(uint64(height)) + if err != nil { + m.logger.Error("failed to create state snapshot", "height", height, "err", err) + return + } + + m.logger.Info("completed state snapshot", "height", height, "format", snapshot.Format) + + if m.opts.KeepRecent > 0 { + m.logger.Debug("pruning state snapshots") + + pruned, err := m.Prune(m.opts.KeepRecent) + if err != nil { + m.logger.Error("Failed to prune state snapshots", "err", err) + return + } + + m.logger.Debug("pruned state snapshots", "pruned", pruned) + } +} diff --git a/snapshots/manager_test.go b/snapshots/manager_test.go index 0989bb4bd210..ecaff9578b30 100644 --- a/snapshots/manager_test.go +++ b/snapshots/manager_test.go @@ -6,14 +6,19 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/snapshots" "github.com/cosmos/cosmos-sdk/snapshots/types" ) +var opts = types.NewSnapshotOptions(1500, 2) + func TestManager_List(t *testing.T) { store := setupStore(t) - manager := snapshots.NewManager(store, nil, nil) + snapshotter := &mockSnapshotter{} + manager := snapshots.NewManager(store, opts, snapshotter, nil, log.NewNopLogger()) + require.Equal(t, opts.Interval, snapshotter.GetSnapshotInterval()) mgrList, err := manager.List() require.NoError(t, err) @@ -32,7 +37,7 @@ func TestManager_List(t *testing.T) { func TestManager_LoadChunk(t *testing.T) { store := setupStore(t) - manager := snapshots.NewManager(store, nil, nil) + manager := snapshots.NewManager(store, opts, &mockSnapshotter{}, nil, log.NewNopLogger()) // Existing chunk should return body chunk, err := manager.LoadChunk(2, 1, 1) @@ -60,9 +65,10 @@ func TestManager_Take(t *testing.T) { } snapshotter := &mockSnapshotter{ items: items, + prunedHeights: make(map[int64]struct{}), } expectChunks := snapshotItems(items) - manager := snapshots.NewManager(store, snapshotter, nil) + manager := snapshots.NewManager(store, opts, snapshotter, nil, log.NewNopLogger()) // nil manager should return error _, err := (*snapshots.Manager)(nil).Create(1) @@ -71,10 +77,15 @@ func TestManager_Take(t *testing.T) { // creating a snapshot at a lower height than the latest should error _, err = manager.Create(3) require.Error(t, err) + _, didPruneHeight := snapshotter.prunedHeights[3] + require.True(t, didPruneHeight) // creating a snapshot at a higher height should be fine, and should return it snapshot, err := manager.Create(5) require.NoError(t, err) + _, didPruneHeight = snapshotter.prunedHeights[5] + require.True(t, didPruneHeight) + assert.Equal(t, &types.Snapshot{ Height: 5, Format: snapshotter.SnapshotFormat(), @@ -98,7 +109,7 @@ func TestManager_Take(t *testing.T) { func TestManager_Prune(t *testing.T) { store := setupStore(t) - manager := snapshots.NewManager(store, nil, nil) + manager := snapshots.NewManager(store, opts, &mockSnapshotter{}, nil, log.NewNopLogger()) pruned, err := manager.Prune(2) require.NoError(t, err) @@ -116,8 +127,10 @@ func TestManager_Prune(t *testing.T) { func TestManager_Restore(t *testing.T) { store := setupStore(t) - target := &mockSnapshotter{} - manager := snapshots.NewManager(store, target, nil) + target := &mockSnapshotter{ + prunedHeights: make(map[int64]struct{}), + } + manager := snapshots.NewManager(store, opts, target, nil, log.NewNopLogger()) expectItems := [][]byte{ {1, 2, 3}, @@ -165,6 +178,8 @@ func TestManager_Restore(t *testing.T) { // While the restore is in progress, any other operations fail _, err = manager.Create(4) require.Error(t, err) + _, didPruneHeight := target.prunedHeights[4] + require.True(t, didPruneHeight) _, err = manager.Prune(1) require.Error(t, err) diff --git a/snapshots/store.go b/snapshots/store.go index 0a3e4388e8b4..b7cbfaa0455e 100644 --- a/snapshots/store.go +++ b/snapshots/store.go @@ -14,6 +14,7 @@ import ( db "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/snapshots/types" + store "github.com/cosmos/cosmos-sdk/store/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -31,6 +32,8 @@ type Store struct { saving map[uint64]bool // heights currently being saved } +var _ store.Store = (*Store)(nil) + // NewStore creates a new snapshot store. func NewStore(db db.DB, dir string) (*Store, error) { if dir == "" { @@ -293,6 +296,28 @@ func (s *Store) Save( return snapshot, s.saveSnapshot(snapshot) } +// GetStoreType implements the Store interface. It returns the underlying Store type. +func (*Store) GetStoreType() store.StoreType { + return store.StoreTypeSnapshot +} + +// CacheWrap implements the Store interface. It panics because a Store +// cannot be branched. +func (*Store) CacheWrap() store.CacheWrap { + panic("cannot CacheWrap a snapshot Store") +} + +// CacheWrapWithTrace implements the Store interface. It panics as a +// Store cannot be branched. +func (*Store) CacheWrapWithTrace(_ io.Writer, _ store.TraceContext) store.CacheWrap { + panic("cannot CacheWrapWithTrace a snapshot Store") +} + +// CacheWrapWithListeners implements the Store interface. +func (*Store) CacheWrapWithListeners(_ store.StoreKey, _ []store.WriteListener) store.CacheWrap { + panic("cannot CacheWrapWithListeners a snapshot Store") +} + // saveSnapshot saves snapshot metadata to the database. func (s *Store) saveSnapshot(snapshot *types.Snapshot) error { value, err := proto.Marshal(snapshot) diff --git a/snapshots/types/options.go b/snapshots/types/options.go new file mode 100644 index 000000000000..16b078157b62 --- /dev/null +++ b/snapshots/types/options.go @@ -0,0 +1,18 @@ +package types + +// SnapshotOptions defines the snapshot strategy used when determining which +// heights are snapshotted for state sync. +type SnapshotOptions struct { + // Interval defines at which heights the snapshot is taken. + Interval uint64 + + // KeepRecent defines how many snapshots to keep. + KeepRecent uint32 +} + +func NewSnapshotOptions(interval uint64, keepRecent uint32) *SnapshotOptions { + return &SnapshotOptions{ + Interval: interval, + KeepRecent: keepRecent, + } +} diff --git a/snapshots/types/snapshotter.go b/snapshots/types/snapshotter.go index f747920d13ad..cc0a18abd26b 100644 --- a/snapshots/types/snapshotter.go +++ b/snapshots/types/snapshotter.go @@ -11,7 +11,17 @@ type Snapshotter interface { // Snapshot writes snapshot items into the protobuf writer. Snapshot(height uint64, protoWriter protoio.Writer) error - // Restore restores a state snapshot from the protobuf items read from the reader. + // PruneSnapshotHeight prunes the given height according to the prune strategy. + // If PruneNothing, this is a no-op. + // If other strategy, this height is persisted until it is + // less than - KeepRecent and % Interval == 0 + PruneSnapshotHeight(height int64) + + // SetSnapshotInterval sets the interval at which the snapshots are taken. + // It is used by the store to determine which heights to retain until after the snapshot is complete. + SetSnapshotInterval(snapshotInterval uint64) + + // Restore restores a state snapshot, taking snapshot chunk readers as input. // If the ready channel is non-nil, it returns a ready signal (by being closed) once the // restorer is ready to accept chunks. Restore(height uint64, format uint32, protoReader protoio.Reader) (SnapshotItem, error) diff --git a/store/iavl/store.go b/store/iavl/store.go index a5706553668c..28906f4819ff 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -12,6 +12,7 @@ import ( tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" dbm "github.com/tendermint/tm-db" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" @@ -128,13 +129,13 @@ func (st *Store) LastCommitID() types.CommitID { // SetPruning panics as pruning options should be provided at initialization // since IAVl accepts pruning options directly. -func (st *Store) SetPruning(_ types.PruningOptions) { +func (st *Store) SetPruning(_ *pruningTypes.PruningOptions) { panic("cannot set pruning options on an initialized IAVL store") } // SetPruning panics as pruning options should be provided at initialization // since IAVl accepts pruning options directly. -func (st *Store) GetPruning() types.PruningOptions { +func (st *Store) GetPruning() *pruningTypes.PruningOptions { panic("cannot get pruning options on an initialized IAVL store") } diff --git a/store/mem/store.go b/store/mem/store.go index c8aa6dca5997..1f6ebacdc2dc 100644 --- a/store/mem/store.go +++ b/store/mem/store.go @@ -5,6 +5,7 @@ import ( dbm "github.com/tendermint/tm-db" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/listenkv" @@ -54,10 +55,12 @@ func (s Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types // Commit performs a no-op as entries are persistent between commitments. func (s *Store) Commit() (id types.CommitID) { return } -func (s *Store) SetPruning(pruning types.PruningOptions) {} +func (s *Store) SetPruning(pruning *pruningTypes.PruningOptions) {} // GetPruning is a no-op as pruning options cannot be directly set on this store. // They must be set on the root commit multi-store. -func (s *Store) GetPruning() types.PruningOptions { return types.PruningOptions{} } +func (s *Store) GetPruning() *pruningTypes.PruningOptions { + return pruningTypes.NewPruningOptions(pruningTypes.PruningUndefined) +} func (s Store) LastCommitID() (id types.CommitID) { return } diff --git a/store/rootmulti/dbadapter.go b/store/rootmulti/dbadapter.go index 4d6e5afeb875..157681461eec 100644 --- a/store/rootmulti/dbadapter.go +++ b/store/rootmulti/dbadapter.go @@ -1,6 +1,7 @@ package rootmulti import ( + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -30,8 +31,10 @@ func (cdsa commitDBStoreAdapter) LastCommitID() types.CommitID { } } -func (cdsa commitDBStoreAdapter) SetPruning(_ types.PruningOptions) {} +func (cdsa commitDBStoreAdapter) SetPruning(_ *pruningTypes.PruningOptions) {} // GetPruning is a no-op as pruning options cannot be directly set on this store. // They must be set on the root commit multi-store. -func (cdsa commitDBStoreAdapter) GetPruning() types.PruningOptions { return types.PruningOptions{} } +func (cdsa commitDBStoreAdapter) GetPruning() *pruningTypes.PruningOptions { + return pruningTypes.NewPruningOptions(pruningTypes.PruningUndefined) +} diff --git a/store/rootmulti/proof_test.go b/store/rootmulti/proof_test.go index 10f8397e7284..d593732d4c66 100644 --- a/store/rootmulti/proof_test.go +++ b/store/rootmulti/proof_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/iavl" @@ -57,7 +58,7 @@ func TestVerifyIAVLStoreQueryProof(t *testing.T) { func TestVerifyMultiStoreQueryProof(t *testing.T) { // Create main tree for testing. db := dbm.NewMemDB() - store := NewStore(db) + store := NewStore(db, log.NewNopLogger()) iavlStoreKey := types.NewKVStoreKey("iavlStoreKey") store.MountStoreWithDB(iavlStoreKey, types.StoreTypeIAVL, nil) @@ -112,7 +113,7 @@ func TestVerifyMultiStoreQueryProof(t *testing.T) { func TestVerifyMultiStoreQueryProofAbsence(t *testing.T) { // Create main tree for testing. db := dbm.NewMemDB() - store := NewStore(db) + store := NewStore(db, log.NewNopLogger()) iavlStoreKey := types.NewKVStoreKey("iavlStoreKey") store.MountStoreWithDB(iavlStoreKey, types.StoreTypeIAVL, nil) diff --git a/store/rootmulti/snapshot_test.go b/store/rootmulti/snapshot_test.go index 92e1311fdd81..bad1603da7c9 100644 --- a/store/rootmulti/snapshot_test.go +++ b/store/rootmulti/snapshot_test.go @@ -18,11 +18,12 @@ import ( "github.com/cosmos/cosmos-sdk/store/iavl" "github.com/cosmos/cosmos-sdk/store/rootmulti" "github.com/cosmos/cosmos-sdk/store/types" + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" ) func newMultiStoreWithGeneratedData(db dbm.DB, stores uint8, storeKeys uint64) *rootmulti.Store { - multiStore := rootmulti.NewStore(db) + multiStore := rootmulti.NewStore(db, log.NewNopLogger()) r := rand.New(rand.NewSource(49872768940)) // Fixed seed for deterministic tests keys := []*types.KVStoreKey{} @@ -54,7 +55,7 @@ func newMultiStoreWithGeneratedData(db dbm.DB, stores uint8, storeKeys uint64) * } func newMultiStoreWithMixedMounts(db dbm.DB) *rootmulti.Store { - store := rootmulti.NewStore(db) + store := rootmulti.NewStore(db, log.NewNopLogger()) store.MountStoreWithDB(types.NewKVStoreKey("iavl1"), types.StoreTypeIAVL, nil) store.MountStoreWithDB(types.NewKVStoreKey("iavl2"), types.StoreTypeIAVL, nil) store.MountStoreWithDB(types.NewKVStoreKey("iavl3"), types.StoreTypeIAVL, nil) @@ -234,7 +235,7 @@ func benchmarkMultistoreSnapshot(b *testing.B, stores uint8, storeKeys uint64) { b.StartTimer() for i := 0; i < b.N; i++ { - target := rootmulti.NewStore(dbm.NewMemDB()) + target := rootmulti.NewStore(dbm.NewMemDB(), log.NewNopLogger()) for _, key := range source.StoreKeysByName() { target.MountStoreWithDB(key, types.StoreTypeIAVL, nil) } @@ -269,7 +270,7 @@ func benchmarkMultistoreSnapshotRestore(b *testing.B, stores uint8, storeKeys ui b.StartTimer() for i := 0; i < b.N; i++ { - target := rootmulti.NewStore(dbm.NewMemDB()) + target := rootmulti.NewStore(dbm.NewMemDB(), log.NewNopLogger()) for _, key := range source.StoreKeysByName() { target.MountStoreWithDB(key, types.StoreTypeIAVL, nil) } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index f38bd41824b4..6101df0679bf 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -1,7 +1,6 @@ package rootmulti import ( - "encoding/binary" "fmt" "io" "math" @@ -9,14 +8,8 @@ import ( "strings" "sync" - iavltree "github.com/cosmos/iavl" - protoio "github.com/gogo/protobuf/io" - gogotypes "github.com/gogo/protobuf/types" - "github.com/pkg/errors" - abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tm-db" - - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/pruning" + "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/iavl" @@ -25,12 +18,21 @@ import ( "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/transient" "github.com/cosmos/cosmos-sdk/store/types" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/tendermint/tendermint/libs/log" + "github.com/pkg/errors" + iavltree "github.com/cosmos/iavl" + protoio "github.com/gogo/protobuf/io" + gogotypes "github.com/gogo/protobuf/types" + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tm-db" ) const ( latestVersionKey = "s/latest" - pruneHeightsKey = "s/pruneheights" commitInfoKeyFmt = "s/%d" // s/ ) @@ -39,14 +41,14 @@ const ( // the CommitMultiStore interface. type Store struct { db dbm.DB + logger log.Logger lastCommitInfo *types.CommitInfo - pruningOpts types.PruningOptions + pruningManager *pruning.Manager iavlCacheSize int storesParams map[types.StoreKey]storeParams stores map[types.StoreKey]types.CommitKVStore keysByName map[string]types.StoreKey lazyLoading bool - pruneHeights []int64 initialVersion int64 removalMap map[types.StoreKey]bool @@ -68,30 +70,36 @@ var ( // store will be created with a PruneNothing pruning strategy by default. After // a store is created, KVStores must be mounted and finally LoadLatestVersion or // LoadVersion must be called. -func NewStore(db dbm.DB) *Store { +func NewStore(db dbm.DB, logger log.Logger) *Store { return &Store{ db: db, - pruningOpts: types.PruneNothing, + logger: logger, iavlCacheSize: iavl.DefaultIAVLCacheSize, storesParams: make(map[types.StoreKey]storeParams), stores: make(map[types.StoreKey]types.CommitKVStore), keysByName: make(map[string]types.StoreKey), - pruneHeights: make([]int64, 0), listeners: make(map[types.StoreKey][]types.WriteListener), removalMap: make(map[types.StoreKey]bool), + pruningManager: pruning.NewManager(logger), } } // GetPruning fetches the pruning strategy from the root store. -func (rs *Store) GetPruning() types.PruningOptions { - return rs.pruningOpts +func (rs *Store) GetPruning() *pruningTypes.PruningOptions { + return rs.pruningManager.GetOptions() } // SetPruning sets the pruning strategy on the root store and all the sub-stores. // Note, calling SetPruning on the root store prior to LoadVersion or // LoadLatestVersion performs a no-op as the stores aren't mounted yet. -func (rs *Store) SetPruning(pruningOpts types.PruningOptions) { - rs.pruningOpts = pruningOpts +func (rs *Store) SetPruning(pruningOpts *pruningTypes.PruningOptions) { + rs.pruningManager.SetOptions(pruningOpts) +} + +// SetSnapshotInterval sets the interval at which the snapshots are taken. +// It is used by the store to determine which heights to retain until after the snapshot is complete. +func (rs *Store) SetSnapshotInterval(snapshotInterval uint64) { + rs.pruningManager.SetSnapshotInterval(snapshotInterval) } func (rs *Store) SetIAVLCacheSize(cacheSize int) { @@ -153,6 +161,11 @@ func (rs *Store) StoreKeysByName() map[string]types.StoreKey { return rs.keysByName } +// GetCommitKVStores get all kv stores associated wit the multistore. +func (rs *Store) GetCommitKVStores() map[types.StoreKey]types.CommitKVStore { + return rs.stores +} + // LoadLatestVersionAndUpgrade implements CommitMultiStore func (rs *Store) LoadLatestVersionAndUpgrade(upgrades *types.StoreUpgrades) error { ver := getLatestVersion(rs.db) @@ -262,9 +275,8 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error { rs.stores = newStores // load any pruned heights we missed from disk to be pruned on the next run - ph, err := getPruningHeights(rs.db) - if err == nil && len(ph) > 0 { - rs.pruneHeights = ph + if err := rs.pruningManager.LoadPruningHeights(rs.db); err != nil { + return err } return nil @@ -309,6 +321,14 @@ func moveKVStoreData(oldDB types.KVStore, newDB types.KVStore) error { return deleteKVStore(oldDB) } +// PruneSnapshotHeight prunes the given height according to the prune strategy. +// If PruneNothing, this is a no-op. +// If other strategy, this height is persisted until it is +// less than - KeepRecent and % Interval == 0 +func (rs *Store) PruneSnapshotHeight(height int64) { + rs.pruningManager.HandleHeightSnapshot(height) +} + // SetInterBlockCache sets the Store's internal inter-block (persistent) cache. // When this is defined, all CommitKVStores will be wrapped with their respective // inter-block cache. @@ -409,6 +429,7 @@ func (rs *Store) Commit() types.CommitID { } rs.lastCommitInfo = commitStores(version, rs.stores, rs.removalMap) + defer rs.flushMetadata(rs.db, version, rs.lastCommitInfo) // remove remnants of removed stores for sk := range rs.removalMap { @@ -418,54 +439,19 @@ func (rs *Store) Commit() types.CommitID { delete(rs.keysByName, sk.Name()) } } - // reset the removalMap rs.removalMap = make(map[types.StoreKey]bool) - // Determine if pruneHeight height needs to be added to the list of heights to - // be pruned, where pruneHeight = (commitHeight - 1) - KeepRecent. - if rs.pruningOpts.Interval > 0 && int64(rs.pruningOpts.KeepRecent) < previousHeight { - pruneHeight := previousHeight - int64(rs.pruningOpts.KeepRecent) - rs.pruneHeights = append(rs.pruneHeights, pruneHeight) - } - - // batch prune if the current height is a pruning interval height - if rs.pruningOpts.Interval > 0 && version%int64(rs.pruningOpts.Interval) == 0 { - rs.pruneStores() + if err := rs.handlePruning(version); err != nil { + panic(err) } - flushMetadata(rs.db, version, rs.lastCommitInfo, rs.pruneHeights) - return types.CommitID{ Version: version, Hash: rs.lastCommitInfo.Hash(), } } -// pruneStores will batch delete a list of heights from each mounted sub-store. -// Afterwards, pruneHeights is reset. -func (rs *Store) pruneStores() { - if len(rs.pruneHeights) == 0 { - return - } - - for key, store := range rs.stores { - if store.GetStoreType() == types.StoreTypeIAVL { - // If the store is wrapped with an inter-block cache, we must first unwrap - // it to get the underlying IAVL store. - store = rs.GetCommitKVStore(key) - - if err := store.(*iavl.Store).DeleteVersions(rs.pruneHeights...); err != nil { - if errCause := errors.Cause(err); errCause != nil && errCause != iavltree.ErrVersionDoesNotExist { - panic(err) - } - } - } - } - - rs.pruneHeights = make([]int64, 0) -} - // CacheWrap implements CacheWrapper/Store/CommitStore. func (rs *Store) CacheWrap() types.CacheWrap { return rs.CacheMultiStore().(types.CacheWrap) @@ -559,7 +545,43 @@ func (rs *Store) GetKVStore(key types.StoreKey) types.KVStore { return store } -// GetStoreByName performs a lookup of a StoreKey given a store name typically +func (rs *Store) handlePruning(version int64) error { + rs.pruningManager.HandleHeight(version - 1) // we should never prune the current version. + if rs.pruningManager.ShouldPruneAtHeight(version) { + rs.logger.Info("prune start", "height", version) + defer rs.logger.Info("prune end", "height", version) + return rs.pruneStores() + } + return nil +} + +func (rs *Store) pruneStores() error { + pruningHeights := rs.pruningManager.GetPruningHeights() + rs.logger.Debug(fmt.Sprintf("pruning the following heights: %v\n", pruningHeights)) + + if len(pruningHeights) == 0 { + return nil + } + + for key, store := range rs.stores { + // If the store is wrapped with an inter-block cache, we must first unwrap + // it to get the underlying IAVL store. + if store.GetStoreType() == types.StoreTypeIAVL { + + store = rs.GetCommitKVStore(key) + + if err := store.(*iavl.Store).DeleteVersions(pruningHeights...); err != nil { + if errCause := errors.Cause(err); errCause != nil && errCause != iavltree.ErrVersionDoesNotExist { + return err + } + } + } + } + rs.pruningManager.ResetPruningHeights() + return nil +} + +// getStoreByName performs a lookup of a StoreKey given a store name typically // provided in a path. The StoreKey is then used to perform a lookup and return // a Store. If the Store is wrapped in an inter-block cache, it will be unwrapped // prior to being returned. If the StoreKey does not exist, nil is returned. @@ -672,7 +694,7 @@ func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error { if height == 0 { return sdkerrors.Wrap(sdkerrors.ErrLogic, "cannot snapshot height 0") } - if height > uint64(rs.LastCommitID().Version) { + if height > uint64(getLatestVersion(rs.db)) { return sdkerrors.Wrapf(sdkerrors.ErrLogic, "cannot snapshot future height %v", height) } @@ -825,7 +847,7 @@ loop: importer.Close() } - flushMetadata(rs.db, int64(height), rs.buildCommitInfo(int64(height)), []int64{}) + rs.flushMetadata(rs.db, int64(height), rs.buildCommitInfo(int64(height))) return snapshotItem, rs.LoadLatestVersion() } @@ -916,9 +938,12 @@ func (rs *Store) RollbackToVersion(target int64) int64 { return current } for ; current > target; current-- { - rs.pruneHeights = append(rs.pruneHeights, current) + rs.pruningManager.HandleHeight(current) + } + err := rs.pruneStores() + if err != nil { + panic(err) } - rs.pruneStores() // update latest height bz, err := gogotypes.StdInt64Marshal(current) @@ -930,6 +955,26 @@ func (rs *Store) RollbackToVersion(target int64) int64 { return current } +func (rs *Store) flushMetadata(db dbm.DB, version int64, cInfo *types.CommitInfo) { + rs.logger.Debug("flushing metadata", "height", version) + batch := db.NewBatch() + defer batch.Close() + + if cInfo != nil { + flushCommitInfo(batch, version, cInfo) + } else { + rs.logger.Debug("commitInfo is nil, not flushed", "height", version) + } + + flushLatestVersion(batch, version) + rs.pruningManager.FlushPruningHeights(batch) + + if err := batch.WriteSync(); err != nil { + panic(fmt.Errorf("error on batch write %w", err)) + } + rs.logger.Debug("flushing metadata finished", "height", version) +} + type storeParams struct { key types.StoreKey db dbm.DB @@ -1002,7 +1047,7 @@ func getCommitInfo(db dbm.DB, ver int64) (*types.CommitInfo, error) { return cInfo, nil } -func setCommitInfo(batch dbm.Batch, version int64, cInfo *types.CommitInfo) { +func flushCommitInfo(batch dbm.Batch, version int64, cInfo *types.CommitInfo) { bz, err := cInfo.Marshal() if err != nil { panic(err) @@ -1012,7 +1057,7 @@ func setCommitInfo(batch dbm.Batch, version int64, cInfo *types.CommitInfo) { batch.Set([]byte(cInfoKey), bz) } -func setLatestVersion(batch dbm.Batch, version int64) { +func flushLatestVersion(batch dbm.Batch, version int64) { bz, err := gogotypes.StdInt64Marshal(version) if err != nil { panic(err) @@ -1020,47 +1065,3 @@ func setLatestVersion(batch dbm.Batch, version int64) { batch.Set([]byte(latestVersionKey), bz) } - -func setPruningHeights(batch dbm.Batch, pruneHeights []int64) { - bz := make([]byte, 0) - for _, ph := range pruneHeights { - buf := make([]byte, 8) - binary.BigEndian.PutUint64(buf, uint64(ph)) - bz = append(bz, buf...) - } - - batch.Set([]byte(pruneHeightsKey), bz) -} - -func getPruningHeights(db dbm.DB) ([]int64, error) { - bz, err := db.Get([]byte(pruneHeightsKey)) - if err != nil { - return nil, fmt.Errorf("failed to get pruned heights: %w", err) - } - if len(bz) == 0 { - return nil, errors.New("no pruned heights found") - } - - prunedHeights := make([]int64, len(bz)/8) - i, offset := 0, 0 - for offset < len(bz) { - prunedHeights[i] = int64(binary.BigEndian.Uint64(bz[offset : offset+8])) - i++ - offset += 8 - } - - return prunedHeights, nil -} - -func flushMetadata(db dbm.DB, version int64, cInfo *types.CommitInfo, pruneHeights []int64) { - batch := db.NewBatch() - defer batch.Close() - - setCommitInfo(batch, version, cInfo) - setLatestVersion(batch, version) - setPruningHeights(batch, pruneHeights) - - if err := batch.Write(); err != nil { - panic(fmt.Errorf("error on batch write %w", err)) - } -} diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 80cbcf68cbd0..bbf2f9524d7e 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -8,10 +8,12 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" codecTypes "github.com/cosmos/cosmos-sdk/codec/types" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/iavl" sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps" @@ -22,13 +24,13 @@ import ( func TestStoreType(t *testing.T) { db := dbm.NewMemDB() - store := NewStore(db) + store := NewStore(db, log.NewNopLogger()) store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, db) } func TestGetCommitKVStore(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, types.PruneDefault) + ms := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningDefault)) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -45,7 +47,7 @@ func TestGetCommitKVStore(t *testing.T) { func TestStoreMount(t *testing.T) { db := dbm.NewMemDB() - store := NewStore(db) + store := NewStore(db, log.NewNopLogger()) key1 := types.NewKVStoreKey("store1") key2 := types.NewKVStoreKey("store2") @@ -61,7 +63,7 @@ func TestStoreMount(t *testing.T) { func TestCacheMultiStore(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, types.PruneNothing) + ms := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) cacheMulti := ms.CacheMultiStore() require.IsType(t, cachemulti.Store{}, cacheMulti) @@ -69,7 +71,7 @@ func TestCacheMultiStore(t *testing.T) { func TestCacheMultiStoreWithVersion(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, types.PruneNothing) + ms := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -106,7 +108,7 @@ func TestCacheMultiStoreWithVersion(t *testing.T) { func TestHashStableWithEmptyCommit(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, types.PruneNothing) + ms := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -130,7 +132,7 @@ func TestHashStableWithEmptyCommit(t *testing.T) { func TestMultistoreCommitLoad(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - store := newMultiStoreWithMounts(db, types.PruneNothing) + store := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err := store.LoadLatestVersion() require.Nil(t, err) @@ -155,7 +157,7 @@ func TestMultistoreCommitLoad(t *testing.T) { } // Load the latest multistore again and check version. - store = newMultiStoreWithMounts(db, types.PruneNothing) + store = newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err = store.LoadLatestVersion() require.Nil(t, err) commitID = getExpectedCommitID(store, nCommits) @@ -168,7 +170,7 @@ func TestMultistoreCommitLoad(t *testing.T) { // Load an older multistore and check version. ver := nCommits - 1 - store = newMultiStoreWithMounts(db, types.PruneNothing) + store = newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err = store.LoadVersion(ver) require.Nil(t, err) commitID = getExpectedCommitID(store, ver) @@ -177,7 +179,7 @@ func TestMultistoreCommitLoad(t *testing.T) { func TestMultistoreLoadWithUpgrade(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - store := newMultiStoreWithMounts(db, types.PruneNothing) + store := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err := store.LoadLatestVersion() require.Nil(t, err) @@ -212,7 +214,7 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { checkContains(t, ci.StoreInfos, []string{"store1", "store2", "store3"}) // Load without changes and make sure it is sensible - store = newMultiStoreWithMounts(db, types.PruneNothing) + store = newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err = store.LoadLatestVersion() require.Nil(t, err) @@ -225,7 +227,7 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.Equal(t, v2, s2.Get(k2)) // now, let's load with upgrades... - restore, upgrades := newMultiStoreWithModifiedMounts(db, types.PruneNothing) + restore, upgrades := newMultiStoreWithModifiedMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err = restore.LoadLatestVersionAndUpgrade(upgrades) require.Nil(t, err) @@ -270,7 +272,7 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { migratedID := restore.Commit() require.Equal(t, migratedID.Version, int64(2)) - reload, _ := newMultiStoreWithModifiedMounts(db, types.PruneNothing) + reload, _ := newMultiStoreWithModifiedMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err = reload.LoadLatestVersion() require.Nil(t, err) require.Equal(t, migratedID, reload.LastCommitID()) @@ -319,10 +321,7 @@ func TestParsePath(t *testing.T) { func TestMultiStoreRestart(t *testing.T) { db := dbm.NewMemDB() - pruning := types.PruningOptions{ - KeepRecent: 2, - Interval: 1, - } + pruning := pruningTypes.NewCustomPruningOptions(2, 1) multi := newMultiStoreWithMounts(db, pruning) err := multi.LoadLatestVersion() require.Nil(t, err) @@ -401,7 +400,7 @@ func TestMultiStoreRestart(t *testing.T) { func TestMultiStoreQuery(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, types.PruneNothing) + multi := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err := multi.LoadLatestVersion() require.Nil(t, err) @@ -428,7 +427,7 @@ func TestMultiStoreQuery(t *testing.T) { ver := cid.Version // Reload multistore from database - multi = newMultiStoreWithMounts(db, types.PruneNothing) + multi = newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) err = multi.LoadLatestVersion() require.Nil(t, err) @@ -473,15 +472,15 @@ func TestMultiStore_Pruning(t *testing.T) { testCases := []struct { name string numVersions int64 - po types.PruningOptions + po *pruningTypes.PruningOptions deleted []int64 saved []int64 }{ - {"prune nothing", 10, types.PruneNothing, nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, - {"prune everything", 10, types.PruneEverything, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}, []int64{10}}, - {"prune some; no batch", 10, types.NewPruningOptions(2, 1), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}}, - {"prune some; small batch", 10, types.NewPruningOptions(2, 3), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}}, - {"prune some; large batch", 10, types.NewPruningOptions(2, 11), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, + {"prune nothing", 10, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, + {"prune everything", 10, pruningTypes.NewPruningOptions(pruningTypes.PruningEverything), []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}, []int64{10}}, + {"prune some; no batch", 10, pruningTypes.NewCustomPruningOptions(2, 1), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}}, + {"prune some; small batch", 10, pruningTypes.NewCustomPruningOptions(2, 3), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}}, + {"prune some; large batch", 10, pruningTypes.NewCustomPruningOptions(2, 11), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, } for _, tc := range testCases { @@ -511,7 +510,8 @@ func TestMultiStore_Pruning(t *testing.T) { func TestMultiStore_PruningRestart(t *testing.T) { db := dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, types.NewPruningOptions(2, 11)) + ms := newMultiStoreWithMounts(db, pruningTypes.NewCustomPruningOptions(2, 11)) + ms.SetSnapshotInterval(3) require.NoError(t, ms.LoadLatestVersion()) // Commit enough to build up heights to prune, where on the next block we should @@ -523,19 +523,20 @@ func TestMultiStore_PruningRestart(t *testing.T) { pruneHeights := []int64{1, 2, 4, 5, 7} // ensure we've persisted the current batch of heights to prune to the store's DB - ph, err := getPruningHeights(ms.db) + err := ms.pruningManager.LoadPruningHeights(ms.db) require.NoError(t, err) - require.Equal(t, []int64{1, 2, 3, 4, 5, 6, 7}, ph) + require.Equal(t, pruneHeights, ms.pruningManager.GetPruningHeights()) // "restart" - ms = newMultiStoreWithMounts(db, types.NewPruningOptions(2, 11)) + ms = newMultiStoreWithMounts(db, pruningTypes.NewCustomPruningOptions(2, 11)) + ms.SetSnapshotInterval(3) err = ms.LoadLatestVersion() require.NoError(t, err) - require.Equal(t, []int64{1, 2, 3, 4, 5, 6, 7}, ms.pruneHeights) + require.Equal(t, pruneHeights, ms.pruningManager.GetPruningHeights()) // commit one more block and ensure the heights have been pruned ms.Commit() - require.Empty(t, ms.pruneHeights) + require.Empty(t, ms.pruningManager.GetPruningHeights()) for _, v := range pruneHeights { _, err := ms.CacheMultiStoreWithVersion(v) @@ -545,7 +546,7 @@ func TestMultiStore_PruningRestart(t *testing.T) { func TestSetInitialVersion(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, types.PruneNothing) + multi := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) require.NoError(t, multi.LoadLatestVersion()) @@ -563,7 +564,7 @@ func TestSetInitialVersion(t *testing.T) { func TestAddListenersAndListeningEnabled(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, types.PruneNothing) + multi := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) testKey := types.NewKVStoreKey("listening_test_key") enabled := multi.ListeningEnabled(testKey) require.False(t, enabled) @@ -594,7 +595,7 @@ var ( func TestGetListenWrappedKVStore(t *testing.T) { buf := new(bytes.Buffer) var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, types.PruneNothing) + ms := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) ms.LoadLatestVersion() mockListeners := []types.WriteListener{types.NewStoreKVPairWriteListener(buf, testMarshaller)} ms.AddListeners(testStoreKey1, mockListeners) @@ -637,6 +638,7 @@ func TestGetListenWrappedKVStore(t *testing.T) { StoreKey: testStoreKey2.Name(), Delete: false, }) + require.NoError(t, err) kvPairSet2Bytes := buf.Bytes() buf.Reset() require.Equal(t, expectedOutputKVPairSet2, kvPairSet2Bytes) @@ -648,6 +650,7 @@ func TestGetListenWrappedKVStore(t *testing.T) { StoreKey: testStoreKey2.Name(), Delete: true, }) + require.NoError(t, err) kvPairDelete2Bytes := buf.Bytes() buf.Reset() require.Equal(t, expectedOutputKVPairDelete2, kvPairDelete2Bytes) @@ -668,7 +671,7 @@ func TestGetListenWrappedKVStore(t *testing.T) { func TestCacheWraps(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, types.PruneNothing) + multi := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) cacheWrapper := multi.CacheWrap() require.IsType(t, cachemulti.Store{}, cacheWrapper) @@ -682,7 +685,7 @@ func TestCacheWraps(t *testing.T) { func TestTraceConcurrency(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, types.PruneNothing) + multi := newMultiStoreWithMounts(db, types.NewPruningOptions(types.PruningNothing)) err := multi.LoadLatestVersion() require.NoError(t, err) @@ -739,9 +742,9 @@ var ( testStoreKey3 = types.NewKVStoreKey("store3") ) -func newMultiStoreWithMounts(db dbm.DB, pruningOpts types.PruningOptions) *Store { - store := NewStore(db) - store.pruningOpts = pruningOpts +func newMultiStoreWithMounts(db dbm.DB, pruningOpts *pruningTypes.PruningOptions) *Store { + store := NewStore(db, log.NewNopLogger()) + store.SetPruning(pruningOpts) store.MountStoreWithDB(testStoreKey1, types.StoreTypeIAVL, nil) store.MountStoreWithDB(testStoreKey2, types.StoreTypeIAVL, nil) @@ -750,9 +753,9 @@ func newMultiStoreWithMounts(db dbm.DB, pruningOpts types.PruningOptions) *Store return store } -func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts types.PruningOptions) (*Store, *types.StoreUpgrades) { - store := NewStore(db) - store.pruningOpts = pruningOpts +func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts *pruningTypes.PruningOptions) (*Store, *types.StoreUpgrades) { + store := NewStore(db, log.NewNopLogger()) + store.SetPruning(pruningOpts) store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil) store.MountStoreWithDB(types.NewKVStoreKey("restore2"), types.StoreTypeIAVL, nil) diff --git a/store/store.go b/store/store.go index 2c068c413f47..492bd4fee1dc 100644 --- a/store/store.go +++ b/store/store.go @@ -1,6 +1,7 @@ package store import ( + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/cache" @@ -9,7 +10,7 @@ import ( ) func NewCommitMultiStore(db dbm.DB) types.CommitMultiStore { - return rootmulti.NewStore(db) + return rootmulti.NewStore(db, log.NewNopLogger()) } func NewCommitKVStoreCacheManager() types.MultiStorePersistentCache { diff --git a/store/transient/store.go b/store/transient/store.go index 572ab55f7697..90370b5939c6 100644 --- a/store/transient/store.go +++ b/store/transient/store.go @@ -3,6 +3,7 @@ package transient import ( dbm "github.com/tendermint/tm-db" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -27,11 +28,13 @@ func (ts *Store) Commit() (id types.CommitID) { return } -func (ts *Store) SetPruning(_ types.PruningOptions) {} +func (ts *Store) SetPruning(_ *pruningTypes.PruningOptions) {} // GetPruning is a no-op as pruning options cannot be directly set on this store. // They must be set on the root commit multi-store. -func (ts *Store) GetPruning() types.PruningOptions { return types.PruningOptions{} } +func (ts *Store) GetPruning() *pruningTypes.PruningOptions { + return pruningTypes.NewPruningOptions(pruningTypes.PruningUndefined) +} // Implements CommitStore func (ts *Store) LastCommitID() (id types.CommitID) { diff --git a/store/transient/store_test.go b/store/transient/store_test.go index 16a165b3ba2e..c13d91448f5e 100644 --- a/store/transient/store_test.go +++ b/store/transient/store_test.go @@ -6,8 +6,9 @@ import ( "github.com/stretchr/testify/require" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + "github.com/cosmos/cosmos-sdk/store/transient" types "github.com/cosmos/cosmos-sdk/store/v2alpha1" - "github.com/cosmos/cosmos-sdk/store/v2alpha1/transient" ) var k, v = []byte("hello"), []byte("world") @@ -26,7 +27,7 @@ func TestTransientStore(t *testing.T) { require.Nil(t, tstore.Get(k)) // no-op - tstore.SetPruning(types.PruningOptions{}) + tstore.SetPruning(pruningTypes.NewPruningOptions(pruningTypes.PruningUndefined)) emptyCommitID := tstore.LastCommitID() require.Equal(t, emptyCommitID.Version, int64(0)) diff --git a/store/types/pruning.go b/store/types/pruning.go deleted file mode 100644 index 3dd05b02bd12..000000000000 --- a/store/types/pruning.go +++ /dev/null @@ -1,71 +0,0 @@ -package types - -import ( - "fmt" -) - -// Pruning option string constants -const ( - PruningOptionDefault = "default" - PruningOptionEverything = "everything" - PruningOptionNothing = "nothing" - PruningOptionCustom = "custom" -) - -var ( - // PruneDefault defines a pruning strategy where the last 362880 heights are - // kept in addition to every 100th and where to-be pruned heights are pruned - // at every 10th height. The last 362880 heights are kept assuming the typical - // block time is 5s and typical unbonding period is 21 days. If these values - // do not match the applications' requirements, use the "custom" option. - PruneDefault = NewPruningOptions(362880, 10) - - // PruneEverything defines a pruning strategy where all committed heights are - // deleted, storing only the current and previous height and where to-be pruned - // heights are pruned at every 10th height. - PruneEverything = NewPruningOptions(2, 10) - - // PruneNothing defines a pruning strategy where all heights are kept on disk. - PruneNothing = NewPruningOptions(0, 0) -) - -// PruningOptions defines the pruning strategy used when determining which -// heights are removed from disk when committing state. -type PruningOptions struct { - // KeepRecent defines how many recent heights to keep on disk. - KeepRecent uint64 - - // Interval defines when the pruned heights are removed from disk. - Interval uint64 -} - -func NewPruningOptions(keepRecent, interval uint64) PruningOptions { - return PruningOptions{ - KeepRecent: keepRecent, - Interval: interval, - } -} - -func (po PruningOptions) Validate() error { - if po.KeepRecent > 0 && po.Interval == 0 { - return fmt.Errorf("invalid 'Interval' when pruning recent heights: %d", po.Interval) - } - - return nil -} - -func NewPruningOptionsFromString(strategy string) PruningOptions { - switch strategy { - case PruningOptionEverything: - return PruneEverything - - case PruningOptionNothing: - return PruneNothing - - case PruningOptionDefault: - return PruneDefault - - default: - return PruneDefault - } -} diff --git a/store/types/pruning_test.go b/store/types/pruning_test.go deleted file mode 100644 index d524aea70ed4..000000000000 --- a/store/types/pruning_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package types - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestPruningOptions_Validate(t *testing.T) { - testCases := []struct { - keepRecent uint64 - interval uint64 - expectErr bool - }{ - {100, 10, false}, // default - {0, 10, false}, // everything - {0, 0, false}, // nothing - {100, 0, true}, // invalid interval - } - - for _, tc := range testCases { - po := NewPruningOptions(tc.keepRecent, tc.interval) - err := po.Validate() - require.Equal(t, tc.expectErr, err != nil, "options: %v, err: %s", po, err) - } -} diff --git a/store/types/store.go b/store/types/store.go index bbf1b875803f..c4a08f711584 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -8,7 +8,8 @@ import ( tmstrings "github.com/tendermint/tendermint/libs/strings" dbm "github.com/tendermint/tm-db" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + snapshotTypes "github.com/cosmos/cosmos-sdk/snapshots/types" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/types/kv" ) @@ -22,8 +23,8 @@ type Committer interface { Commit() CommitID LastCommitID() CommitID - SetPruning(PruningOptions) - GetPruning() PruningOptions + SetPruning(*PruningOptions) + GetPruning() *PruningOptions } // Stores of MultiStore must implement CommitStore. @@ -142,7 +143,7 @@ type CacheMultiStore interface { type CommitMultiStore interface { Committer MultiStore - snapshottypes.Snapshotter + snapshotTypes.Snapshotter // Mount a store of type using the given db. // If db == nil, the new store will use the CommitMultiStore db. @@ -154,6 +155,9 @@ type CommitMultiStore interface { // Panics on a nil key. GetCommitKVStore(key StoreKey) CommitKVStore + // GetCommitKVStores get all kv stores associated with the multistore. + GetCommitKVStores() map[StoreKey]CommitKVStore + // Load the latest persisted version. Called once after all calls to // Mount*Store() are complete. LoadLatestVersion() error @@ -298,6 +302,7 @@ const ( StoreTypeMemory StoreTypeSMT StoreTypePersistent + StoreTypeSnapshot ) func (st StoreType) String() string { @@ -322,6 +327,9 @@ func (st StoreType) String() string { case StoreTypePersistent: return "StoreTypePersistent" + + case StoreTypeSnapshot: + return "StoreTypeSnapshot" } return "unknown store type" @@ -439,3 +447,34 @@ type StoreWithInitialVersion interface { // starting a new chain at an arbitrary height. SetInitialVersion(version int64) } + +type ( + PruningOptions = pruningTypes.PruningOptions + PruningStrategy = pruningTypes.PruningStrategy +) + +const ( + PruningOptionDefault = pruningTypes.PruningOptionDefault + PruningOptionEverything = pruningTypes.PruningOptionEverything + PruningOptionNothing = pruningTypes.PruningOptionNothing + PruningOptionCustom = pruningTypes.PruningOptionCustom + + PruningDefault = pruningTypes.PruningDefault + PruningEverything = pruningTypes.PruningEverything + PruningNothing = pruningTypes.PruningNothing + PruningCustom = pruningTypes.PruningCustom +) + +func NewPruningOptions(pruningStrategy PruningStrategy) *PruningOptions { + return pruningTypes.NewPruningOptions(pruningStrategy) +} + +func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { + return pruningTypes.NewCustomPruningOptions(keepRecent, interval) +} + +type SnapshotOptions = snapshotTypes.SnapshotOptions + +func NewSnapshotOptions(interval uint64, keepRecent uint32) *SnapshotOptions { + return snapshotTypes.NewSnapshotOptions(interval, keepRecent) +} diff --git a/store/types/utils_test.go b/store/types/utils_test.go index 32064d7e1821..7af25af15f95 100644 --- a/store/types/utils_test.go +++ b/store/types/utils_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/rootmulti" @@ -13,7 +14,7 @@ import ( func initTestStores(t *testing.T) (types.KVStore, types.KVStore) { db := dbm.NewMemDB() - ms := rootmulti.NewStore(db) + ms := rootmulti.NewStore(db, log.NewNopLogger()) key1 := types.NewKVStoreKey("store1") key2 := types.NewKVStoreKey("store2") diff --git a/store/v2alpha1/mem/store.go b/store/v2alpha1/mem/store.go index b984aac81dc8..4f9ec299f44e 100644 --- a/store/v2alpha1/mem/store.go +++ b/store/v2alpha1/mem/store.go @@ -38,7 +38,7 @@ func (s *Store) Commit() (id types.CommitID) { return } -func (s *Store) SetPruning(pruning types.PruningOptions) {} -func (s *Store) GetPruning() types.PruningOptions { return types.PruningOptions{} } +func (s *Store) SetPruning(*types.PruningOptions) {} +func (s *Store) GetPruning() *types.PruningOptions { return &types.PruningOptions{} } func (s Store) LastCommitID() (id types.CommitID) { return } diff --git a/store/v2alpha1/multi/migration_test.go b/store/v2alpha1/multi/migration_test.go index 09f1f74b5a16..bf7b0f921cd0 100644 --- a/store/v2alpha1/multi/migration_test.go +++ b/store/v2alpha1/multi/migration_test.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/rootmulti" "github.com/cosmos/cosmos-sdk/store/types" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" ) @@ -19,7 +20,7 @@ func TestMigrationV2(t *testing.T) { // setup a rootmulti store db := dbm.NewMemDB() - v1Store := rootmulti.NewStore(db) + v1Store := rootmulti.NewStore(db, log.NewNopLogger()) // mount the kvStores var keys []*types.KVStoreKey @@ -94,7 +95,7 @@ func TestMigrationV2(t *testing.T) { func TestMigrateV2ForEmptyStore(t *testing.T) { // setup a rootmulti store db := dbm.NewMemDB() - v1Store := rootmulti.NewStore(db) + v1Store := rootmulti.NewStore(db, log.NewNopLogger()) err := v1Store.LoadLatestVersion() require.Nil(t, err) db2 := memdb.NewDB() diff --git a/store/v2alpha1/multi/snapshot_test.go b/store/v2alpha1/multi/snapshot_test.go index 0495e95e1e10..6242928c0c01 100644 --- a/store/v2alpha1/multi/snapshot_test.go +++ b/store/v2alpha1/multi/snapshot_test.go @@ -24,7 +24,7 @@ import ( func multiStoreConfig(t *testing.T, stores int) StoreConfig { opts := DefaultStoreConfig() - opts.Pruning = types.PruneNothing + opts.Pruning = types.NewPruningOptions(types.PruningNothing) for i := 0; i < stores; i++ { sKey := types.NewKVStoreKey(fmt.Sprintf("store%d", i)) diff --git a/store/v2alpha1/multi/store.go b/store/v2alpha1/multi/store.go index 191239bc83f7..e50022e8b984 100644 --- a/store/v2alpha1/multi/store.go +++ b/store/v2alpha1/multi/store.go @@ -56,7 +56,7 @@ func ErrStoreNotFound(skey string) error { // StoreConfig is used to define a schema and other options and pass them to the MultiStore constructor. type StoreConfig struct { // Version pruning options for backing DBs. - Pruning types.PruningOptions + Pruning *types.PruningOptions // The minimum allowed version number. InitialVersion uint64 // The backing DB to use for the state commitment Merkle tree data. @@ -92,7 +92,7 @@ type Store struct { mtx sync.RWMutex // Copied from StoreConfig - Pruning types.PruningOptions + Pruning *types.PruningOptions InitialVersion uint64 // if *traceListenMixin @@ -152,7 +152,7 @@ func newTraceListenMixin() *traceListenMixin { // pruning with PruneDefault, no listeners and no tracer. func DefaultStoreConfig() StoreConfig { return StoreConfig{ - Pruning: types.PruneDefault, + Pruning: types.NewPruningOptions(types.PruneDefault), prefixRegistry: prefixRegistry{ StoreSchema: StoreSchema{}, }, @@ -175,12 +175,12 @@ func validSubStoreType(sst types.StoreType) bool { } // Returns true iff both schema maps match exactly (including mem/tran stores) -func (this StoreSchema) equal(that StoreSchema) bool { - if len(this) != len(that) { +func (ss StoreSchema) equal(that StoreSchema) bool { + if len(ss) != len(that) { return false } for key, val := range that { - myval, has := this[key] + myval, has := ss[key] if !has { return false } @@ -248,7 +248,7 @@ func NewStore(db dbm.DBConnection, opts StoreConfig) (ret *Store, err error) { } // Version sets of each DB must match if !versions.Equal(scVersions) { - err = fmt.Errorf("Storage and StateCommitment DB have different version history") //nolint:stylecheck + err = fmt.Errorf("different version history between Storage and StateCommitment DB ") return } err = opts.StateCommitmentDB.Revert() @@ -689,6 +689,20 @@ func (rs *Store) CacheMultiStore() types.CacheMultiStore { } } +// PruneSnapshotHeight prunes the given height according to the prune strategy. +// If PruneNothing, this is a no-op. +// If other strategy, this height is persisted until it is +// less than - KeepRecent and % Interval == 0 +func (rs *Store) PruneSnapshotHeight(height int64) { + panic("not implemented") +} + +// SetSnapshotInterval sets the interval at which the snapshots are taken. +// It is used by the store to determine which heights to retain until after the snapshot is complete. +func (rs *Store) SetSnapshotInterval(snapshotInterval uint64) { + panic("not implemented") +} + // parsePath expects a format like /[/] // Must start with /, subpath may be empty // Returns error if it doesn't start with / @@ -769,7 +783,7 @@ func (rs *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { // TODO: actual IBC compatible proof. This is a placeholder so unit tests can pass res.ProofOps, err = substore.GetProof(res.Key) if err != nil { - return sdkerrors.QueryResult(fmt.Errorf("Merkle proof creation failed for key: %v", res.Key), false) //nolint: stylecheck // proper name + return sdkerrors.QueryResult(fmt.Errorf("merkle proof creation failed for key: %v", res.Key), false) } case "/subspace": @@ -894,5 +908,5 @@ func (tlm *traceListenMixin) wrapTraceListen(store types.KVStore, skey types.Sto return store } -func (s *Store) GetPruning() types.PruningOptions { return s.Pruning } -func (s *Store) SetPruning(po types.PruningOptions) { s.Pruning = po } +func (s *Store) GetPruning() *types.PruningOptions { return s.Pruning } +func (s *Store) SetPruning(po *types.PruningOptions) { s.Pruning = po } diff --git a/store/v2alpha1/multi/store_test.go b/store/v2alpha1/multi/store_test.go index d157f0099084..f03f5b9f5d25 100644 --- a/store/v2alpha1/multi/store_test.go +++ b/store/v2alpha1/multi/store_test.go @@ -18,7 +18,6 @@ import ( ) var ( - cacheSize = 100 alohaData = map[string]string{ "hello": "goodbye", "aloha": "shalom", @@ -40,7 +39,7 @@ func simpleStoreConfig(t *testing.T) StoreConfig { func storeConfig123(t *testing.T) StoreConfig { opts := DefaultStoreConfig() - opts.Pruning = types.PruneNothing + opts.Pruning = types.NewPruningOptions(types.PruneNothing) require.NoError(t, opts.RegisterSubstore(skey_1.Name(), types.StoreTypePersistent)) require.NoError(t, opts.RegisterSubstore(skey_2.Name(), types.StoreTypePersistent)) require.NoError(t, opts.RegisterSubstore(skey_3.Name(), types.StoreTypePersistent)) @@ -101,7 +100,7 @@ func TestConstructors(t *testing.T) { require.NoError(t, store.Close()) t.Run("fail to load if InitialVersion > lowest existing version", func(t *testing.T) { - opts := StoreConfig{InitialVersion: 5, Pruning: types.PruneNothing} + opts := StoreConfig{InitialVersion: 5, Pruning: types.NewPruningOptions(types.PruneNothing)} store, err = NewStore(db, opts) require.Error(t, err) db.Close() @@ -247,7 +246,7 @@ func TestCommit(t *testing.T) { } } basicOpts := simpleStoreConfig(t) - basicOpts.Pruning = types.PruneNothing + basicOpts.Pruning = types.NewPruningOptions(types.PruneNothing) t.Run("sanity tests for Merkle hashing", func(t *testing.T) { testBasic(basicOpts) }) @@ -286,7 +285,7 @@ func TestCommit(t *testing.T) { } opts := simpleStoreConfig(t) - opts.Pruning = types.PruneNothing + opts.Pruning = types.NewPruningOptions(types.PruneNothing) // Ensure Store's commit is rolled back in each failure case... t.Run("recover after failed Commit", func(t *testing.T) { @@ -349,7 +348,7 @@ func TestCommit(t *testing.T) { t.Run("height overflow triggers failure", func(t *testing.T) { opts.StateCommitmentDB = nil opts.InitialVersion = math.MaxInt64 - opts.Pruning = types.PruneNothing + opts.Pruning = types.NewPruningOptions(types.PruneNothing) store, err := NewStore(memdb.NewDB(), opts) require.NoError(t, err) require.Equal(t, int64(math.MaxInt64), store.Commit().Version) @@ -360,7 +359,7 @@ func TestCommit(t *testing.T) { t.Run("first commit version matches InitialVersion", func(t *testing.T) { opts = simpleStoreConfig(t) opts.InitialVersion = 5 - opts.Pruning = types.PruneNothing + opts.Pruning = types.NewPruningOptions(types.PruneNothing) opts.StateCommitmentDB = memdb.NewDB() store, err := NewStore(memdb.NewDB(), opts) require.NoError(t, err) @@ -395,13 +394,13 @@ func sliceToSet(slice []uint64) map[uint64]struct{} { func TestPruning(t *testing.T) { // Save versions up to 10 and verify pruning at final commit testCases := []struct { - types.PruningOptions + *types.PruningOptions kept []uint64 }{ - {types.PruningOptions{2, 10}, []uint64{8, 9, 10}}, - {types.PruningOptions{0, 10}, []uint64{10}}, - {types.PruneEverything, []uint64{8, 9, 10}}, - {types.PruneNothing, []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, + {types.NewCustomPruningOptions(2, 10), []uint64{8, 9, 10}}, + {types.NewCustomPruningOptions(0, 10), []uint64{10}}, + {types.NewPruningOptions(types.PruneEverything), []uint64{8, 9, 10}}, + {types.NewPruningOptions(types.PruneNothing), []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, } for tci, tc := range testCases { @@ -443,7 +442,7 @@ func TestPruning(t *testing.T) { db := memdb.NewDB() opts := simpleStoreConfig(t) - opts.Pruning = types.PruningOptions{0, 10} + opts.Pruning = types.NewCustomPruningOptions(0, 10) store, err := NewStore(db, opts) require.NoError(t, err) @@ -689,7 +688,7 @@ func TestGetVersion(t *testing.T) { require.Panics(t, func() { subview.Set([]byte{1}, []byte{1}) }) require.Panics(t, func() { subview.Delete([]byte{0}) }) // nonexistent version shouldn't be accessible - view, err = store.GetVersion(cid.Version + 1) + _, err = store.GetVersion(cid.Version + 1) require.Equal(t, ErrVersionDoesNotExist, err) substore := store.GetKVStore(skey_1) @@ -750,7 +749,7 @@ func TestMultiStoreMigration(t *testing.T) { t.Run("basic migration", func(t *testing.T) { // now, let's load with upgrades... opts.Upgrades = []types.StoreUpgrades{ - types.StoreUpgrades{ + { Added: []string{skey_4.Name()}, Renamed: []types.StoreRename{{ OldKey: skey_2.Name(), diff --git a/store/v2alpha1/multi/view_store.go b/store/v2alpha1/multi/view_store.go index 29c391287a93..d4b97325dd15 100644 --- a/store/v2alpha1/multi/view_store.go +++ b/store/v2alpha1/multi/view_store.go @@ -86,7 +86,7 @@ func (st *viewSubstore) CacheWrapWithListeners(storeKey types.StoreKey, listener func (s *viewStore) getMerkleRoots() (ret map[string][]byte, err error) { ret = map[string][]byte{} - for key, _ := range s.schema { + for key := range s.schema { sub, has := s.substoreCache[key] if !has { sub, err = s.getSubstore(key) diff --git a/store/v2alpha1/transient/store.go b/store/v2alpha1/transient/store.go index 2a9609afb12b..d62956368e44 100644 --- a/store/v2alpha1/transient/store.go +++ b/store/v2alpha1/transient/store.go @@ -40,7 +40,7 @@ func (ts *Store) Commit() (id types.CommitID) { return } -func (ts *Store) SetPruning(types.PruningOptions) {} -func (ts *Store) GetPruning() types.PruningOptions { return types.PruningOptions{} } +func (ts *Store) SetPruning(*types.PruningOptions) {} +func (ts *Store) GetPruning() *types.PruningOptions { return &types.PruningOptions{} } func (ts *Store) LastCommitID() (id types.CommitID) { return } diff --git a/store/v2alpha1/types.go b/store/v2alpha1/types.go index 5aacfc2d4133..91f75088d649 100644 --- a/store/v2alpha1/types.go +++ b/store/v2alpha1/types.go @@ -16,6 +16,7 @@ type ( StoreRename = v1.StoreRename Iterator = v1.Iterator PruningOptions = v1.PruningOptions + PruningStrategy = v1.PruningStrategy TraceContext = v1.TraceContext WriteListener = v1.WriteListener @@ -46,9 +47,9 @@ const ( ) var ( - PruneDefault = v1.PruneDefault - PruneEverything = v1.PruneEverything - PruneNothing = v1.PruneNothing + PruneDefault = v1.PruningDefault + PruneEverything = v1.PruningEverything + PruneNothing = v1.PruningNothing NewKVStoreKey = v1.NewKVStoreKey PrefixEndBytes = v1.PrefixEndBytes @@ -114,3 +115,11 @@ type CacheMultiStore interface { // MultiStorePersistentCache provides inter-block (persistent) caching capabilities for a CommitMultiStore. // TODO: placeholder. Implement and redefine this type MultiStorePersistentCache = v1.MultiStorePersistentCache + +func NewPruningOptions(pruningStrategy PruningStrategy) *PruningOptions { + return v1.NewPruningOptions(pruningStrategy) +} + +func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { + return v1.NewCustomPruningOptions(keepRecent, interval) +} diff --git a/testutil/network/network.go b/testutil/network/network.go index 71fe7283b051..684c70264656 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -32,13 +32,13 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" srvconfig "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/simapp/params" - storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -61,7 +61,7 @@ func NewAppConstructor(encodingCfg params.EncodingConfig) AppConstructor { val.Ctx.Logger, dbm.NewMemDB(), nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0, encodingCfg, simapp.EmptyAppOptions{}, - baseapp.SetPruning(storetypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), + baseapp.SetPruning(pruningTypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices), ) } @@ -119,7 +119,7 @@ func DefaultConfig() Config { AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction), StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction), BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction), - PruningStrategy: storetypes.PruningOptionNothing, + PruningStrategy: pruningTypes.PruningOptionNothing, CleanupDir: true, SigningAlgo: string(hd.Secp256k1Type), KeyringOptions: []keyring.Option{}, diff --git a/testutil/snapshots/util.go b/testutil/snapshots/util.go new file mode 100644 index 000000000000..6c4bf2d992ba --- /dev/null +++ b/testutil/snapshots/util.go @@ -0,0 +1,19 @@ +package snapshots + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func GetTempDir(t *testing.T) string { + // ioutil.TempDir() is used instead of testing.T.TempDir() + // see https://github.com/cosmos/cosmos-sdk/pull/8475 for + // this change's rationale. + tempdir, err := ioutil.TempDir("", "") + require.NoError(t, err) + t.Cleanup(func() { _ = os.RemoveAll(tempdir) }) + return tempdir +} diff --git a/types/store.go b/types/store.go index b50f95d02a7a..a9604da8baa2 100644 --- a/types/store.go +++ b/types/store.go @@ -9,10 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/types/kv" ) -type ( - PruningOptions = types.PruningOptions -) - type ( Store = types.Store Committer = types.Committer @@ -155,15 +151,27 @@ type ( GasConfig = types.GasConfig ) -func NewGasMeter(limit Gas) GasMeter { - return types.NewGasMeter(limit) -} - type ( ErrorOutOfGas = types.ErrorOutOfGas ErrorGasOverflow = types.ErrorGasOverflow ) +func NewGasMeter(limit Gas) GasMeter { + return types.NewGasMeter(limit) +} + func NewInfiniteGasMeter() GasMeter { return types.NewInfiniteGasMeter() } + +func NewSnapshotOptions(interval uint64, keepRecent uint32) *types.SnapshotOptions { + return types.NewSnapshotOptions(interval, keepRecent) +} + +func NewPruningOptions(pruningStrategy types.PruningStrategy) *types.PruningOptions { + return types.NewPruningOptions(pruningStrategy) +} + +func NewCustomPruningOptions(keepRecent, interval uint64) *types.PruningOptions { + return types.NewCustomPruningOptions(keepRecent, interval) +} diff --git a/types/store_test.go b/types/store_test.go index d2039f8cb896..7d4dfecb644b 100644 --- a/types/store_test.go +++ b/types/store_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/rootmulti" @@ -108,7 +109,7 @@ func (s *storeTestSuite) TestDiffKVStores() { func (s *storeTestSuite) initTestStores() (types.KVStore, types.KVStore) { db := dbm.NewMemDB() - ms := rootmulti.NewStore(db) + ms := rootmulti.NewStore(db, log.NewNopLogger()) key1 := types.NewKVStoreKey("store1") key2 := types.NewKVStoreKey("store2") diff --git a/x/upgrade/types/storeloader_test.go b/x/upgrade/types/storeloader_test.go index 341a2ffe30da..4031642d56da 100644 --- a/x/upgrade/types/storeloader_test.go +++ b/x/upgrade/types/storeloader_test.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/store/rootmulti" storetypes "github.com/cosmos/cosmos-sdk/store/types" + pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -34,8 +35,8 @@ func defaultLogger() log.Logger { } func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { - rs := rootmulti.NewStore(db) - rs.SetPruning(storetypes.PruneNothing) + rs := rootmulti.NewStore(db, log.NewNopLogger()) + rs.SetPruning(pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) key := sdk.NewKVStoreKey(storeKey) rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() @@ -51,8 +52,8 @@ func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { } func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) { - rs := rootmulti.NewStore(db) - rs.SetPruning(storetypes.PruneNothing) + rs := rootmulti.NewStore(db, log.NewNopLogger()) + rs.SetPruning(pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) key := sdk.NewKVStoreKey(storeKey) rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() @@ -122,7 +123,7 @@ func TestSetLoader(t *testing.T) { initStore(t, db, tc.origStoreKey, k, v) // load the app with the existing db - opts := []func(*baseapp.BaseApp){baseapp.SetPruning(storetypes.PruneNothing)} + opts := []func(*baseapp.BaseApp){baseapp.SetPruning(pruningTypes.NewPruningOptions(pruningTypes.PruningNothing))} origapp := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, opts...) origapp.MountStores(sdk.NewKVStoreKey(tc.origStoreKey)) From 271314ab57c838f4f448d9de71e3828c6c7bd69c Mon Sep 17 00:00:00 2001 From: Roman Akhtariev Date: Wed, 30 Mar 2022 22:16:01 +0000 Subject: [PATCH 02/58] fix GetBlockRetentionHeight --- baseapp/abci.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index e5d008eab5fd..1732abdc3e73 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -687,22 +687,6 @@ func (app *BaseApp) GetBlockRetentionHeight(commitHeight int64) int64 { } if app.snapshotManager != nil { - // Define the state pruning offset, i.e. the block offset at which the - // underlying logical database is persisted to disk. - statePruningOffset := int64(app.snapshotManager.GetInterval()) - if statePruningOffset > 0 { - if commitHeight > statePruningOffset { - v := commitHeight - (commitHeight % statePruningOffset) - retentionHeight = minNonZero(retentionHeight, v) - } else { - // Hitting this case means we have persisting enabled but have yet to reach - // a height in which we persist state, so we return zero regardless of other - // conditions. Otherwise, we could end up pruning blocks without having - // any state committed to disk. - return 0 - } - } - snapshotRetentionHeights := app.snapshotManager.GetSnapshotBlockRetentionHeights() if snapshotRetentionHeights > 0 { retentionHeight = minNonZero(retentionHeight, commitHeight-snapshotRetentionHeights) From 640c7a6fb820fadbb9cf6588bfbb2c2234646d05 Mon Sep 17 00:00:00 2001 From: Roman Akhtariev Date: Wed, 30 Mar 2022 22:24:27 +0000 Subject: [PATCH 03/58] avoid snapshots/store implementing Store interface --- snapshots/store.go | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/snapshots/store.go b/snapshots/store.go index b7cbfaa0455e..0a3e4388e8b4 100644 --- a/snapshots/store.go +++ b/snapshots/store.go @@ -14,7 +14,6 @@ import ( db "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/snapshots/types" - store "github.com/cosmos/cosmos-sdk/store/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -32,8 +31,6 @@ type Store struct { saving map[uint64]bool // heights currently being saved } -var _ store.Store = (*Store)(nil) - // NewStore creates a new snapshot store. func NewStore(db db.DB, dir string) (*Store, error) { if dir == "" { @@ -296,28 +293,6 @@ func (s *Store) Save( return snapshot, s.saveSnapshot(snapshot) } -// GetStoreType implements the Store interface. It returns the underlying Store type. -func (*Store) GetStoreType() store.StoreType { - return store.StoreTypeSnapshot -} - -// CacheWrap implements the Store interface. It panics because a Store -// cannot be branched. -func (*Store) CacheWrap() store.CacheWrap { - panic("cannot CacheWrap a snapshot Store") -} - -// CacheWrapWithTrace implements the Store interface. It panics as a -// Store cannot be branched. -func (*Store) CacheWrapWithTrace(_ io.Writer, _ store.TraceContext) store.CacheWrap { - panic("cannot CacheWrapWithTrace a snapshot Store") -} - -// CacheWrapWithListeners implements the Store interface. -func (*Store) CacheWrapWithListeners(_ store.StoreKey, _ []store.WriteListener) store.CacheWrap { - panic("cannot CacheWrapWithListeners a snapshot Store") -} - // saveSnapshot saves snapshot metadata to the database. func (s *Store) saveSnapshot(snapshot *types.Snapshot) error { value, err := proto.Marshal(snapshot) From bc55f111bdd3efa594c1cf53bb0c66042959fdf1 Mon Sep 17 00:00:00 2001 From: Roman Akhtariev Date: Wed, 30 Mar 2022 23:06:15 +0000 Subject: [PATCH 04/58] always use testutil.GetTempDir for creating a temp dir in tests --- baseapp/abci_test.go | 4 ++-- baseapp/baseapp_test.go | 39 +++++++++++++------------------------- snapshots/helpers_test.go | 37 +++++++++++++++--------------------- snapshots/store_test.go | 10 +--------- testutil/ioutil.go | 15 ++++++++++++++- testutil/snapshots/util.go | 19 ------------------- 6 files changed, 45 insertions(+), 79 deletions(-) delete mode 100644 testutil/snapshots/util.go diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 2d4f31815585..0d822db988f7 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/snapshots" pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" - snaphotsTestUtil "github.com/cosmos/cosmos-sdk/testutil/snapshots" + "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -20,7 +20,7 @@ func TestGetBlockRentionHeight(t *testing.T) { db := dbm.NewMemDB() name := t.Name() - snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), snaphotsTestUtil.GetTempDir(t)) + snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), testutil.GetTempDir(t)) require.NoError(t, err) testCases := map[string]struct { diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 5d16ced3a02f..f773d32b276a 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -8,7 +8,6 @@ import ( "fmt" "math" "math/rand" - "os" "strings" "sync" "testing" @@ -29,7 +28,7 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" storeTypes "github.com/cosmos/cosmos-sdk/store/types" - snaphotsTestUtil "github.com/cosmos/cosmos-sdk/testutil/snapshots" + "github.com/cosmos/cosmos-sdk/testutil" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -158,7 +157,7 @@ func testTxHandler(options middleware.TxHandlerOptions, customTxHandlerMiddlewar } // simple one store baseapp with data and snapshots. Each tx is 1 MB in size (uncompressed). -func setupBaseAppWithSnapshots(t *testing.T, config *setupConfig) (*baseapp.BaseApp, func(), error) { +func setupBaseAppWithSnapshots(t *testing.T, config *setupConfig) (*baseapp.BaseApp, error) { codec := codec.NewLegacyAmino() registerTestCodec(codec) routerOpt := func(bapp *baseapp.BaseApp) { @@ -187,17 +186,12 @@ func setupBaseAppWithSnapshots(t *testing.T, config *setupConfig) (*baseapp.Base } snapshotTimeout := 1 * time.Minute - snapshotDir, err := os.MkdirTemp("", "baseapp") + snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), testutil.GetTempDir(t)) require.NoError(t, err) - snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), snapshotDir) - require.NoError(t, err) - teardown := func() { - _ = os.RemoveAll(snapshotDir) - } app, err := setupBaseApp(t, routerOpt, baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(config.snapshotInterval, uint32(config.snapshotKeepRecent))), baseapp.SetPruning(config.pruningOpts)) if err != nil { - return nil, nil, err + return nil, err } app.InitChain(abci.RequestInitChain{}) @@ -241,7 +235,7 @@ func setupBaseAppWithSnapshots(t *testing.T, config *setupConfig) (*baseapp.Base } } - return app, teardown, nil + return app, nil } func TestMountStores(t *testing.T) { @@ -499,7 +493,7 @@ func TestLoadVersionPruning(t *testing.T) { db := dbm.NewMemDB() name := t.Name() - snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), snaphotsTestUtil.GetTempDir(t)) + snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), testutil.GetTempDir(t)) require.NoError(t, err) snapshotOpt := baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(3, 1)) @@ -1945,9 +1939,8 @@ func TestListSnapshots(t *testing.T) { pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), } - app, teardown, err := setupBaseAppWithSnapshots(t, setupConfig) + app, err := setupBaseAppWithSnapshots(t, setupConfig) require.NoError(t, err) - defer teardown() resp := app.ListSnapshots(abci.RequestListSnapshots{}) for _, s := range resp.Snapshots { @@ -2044,7 +2037,7 @@ func TestSnapshotWithPruning(t *testing.T) { for name, tc := range testcases { t.Run(name, func(t *testing.T) { - app, teardown, err := setupBaseAppWithSnapshots(t, tc.config) + app, err := setupBaseAppWithSnapshots(t, tc.config) if tc.expectedErr != nil { require.Error(t, err) @@ -2053,8 +2046,6 @@ func TestSnapshotWithPruning(t *testing.T) { } require.NoError(t, err) - defer teardown() - resp := app.ListSnapshots(abci.RequestListSnapshots{}) for _, s := range resp.Snapshots { assert.NotEmpty(t, s.Hash) @@ -2104,9 +2095,8 @@ func TestLoadSnapshotChunk(t *testing.T) { snapshotKeepRecent: 2, pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), } - app, teardown, err := setupBaseAppWithSnapshots(t, setupConfig) + app, err := setupBaseAppWithSnapshots(t, setupConfig) require.NoError(t, err) - defer teardown() testcases := map[string]struct { height uint64 @@ -2148,9 +2138,8 @@ func TestOfferSnapshot_Errors(t *testing.T) { snapshotKeepRecent: 2, pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), } - app, teardown, err := setupBaseAppWithSnapshots(t, setupConfig) + app, err := setupBaseAppWithSnapshots(t, setupConfig) require.NoError(t, err) - defer teardown() m := snapshottypes.Metadata{ChunkHashes: [][]byte{{1}, {2}, {3}}} metadata, err := m.Marshal() @@ -2211,9 +2200,8 @@ func TestApplySnapshotChunk(t *testing.T) { snapshotKeepRecent: 2, pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), } - source, teardown, err := setupBaseAppWithSnapshots(t, setupConfig1) + source, err := setupBaseAppWithSnapshots(t, setupConfig1) require.NoError(t, err) - defer teardown() setupConfig2 := &setupConfig{ blocks: 0, @@ -2222,9 +2210,8 @@ func TestApplySnapshotChunk(t *testing.T) { snapshotKeepRecent: 2, pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), } - target, teardown, err := setupBaseAppWithSnapshots(t, setupConfig2) + target, err := setupBaseAppWithSnapshots(t, setupConfig2) require.NoError(t, err) - defer teardown() // Fetch latest snapshot to restore respList := source.ListSnapshots(abci.RequestListSnapshots{}) @@ -2368,7 +2355,7 @@ func TestBaseApp_Init(t *testing.T) { name := t.Name() logger := defaultLogger() - snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), snaphotsTestUtil.GetTempDir(t)) + snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), testutil.GetTempDir(t)) require.NoError(t, err) testCases := map[string]struct { diff --git a/snapshots/helpers_test.go b/snapshots/helpers_test.go index 6a849fc9f062..b579eaaf1112 100644 --- a/snapshots/helpers_test.go +++ b/snapshots/helpers_test.go @@ -7,7 +7,6 @@ import ( "crypto/sha256" "errors" "io" - "os" "testing" "time" @@ -17,7 +16,8 @@ import ( db "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/cosmos/cosmos-sdk/snapshots/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/testutil" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -74,7 +74,7 @@ func snapshotItems(items [][]byte) [][]byte { zWriter, _ := zlib.NewWriterLevel(bufWriter, 7) protoWriter := protoio.NewDelimitedWriter(zWriter) for _, item := range items { - _ = types.WriteExtensionItem(protoWriter, item) + _ = snapshottypes.WriteExtensionItem(protoWriter, item) } _ = protoWriter.Close() _ = zWriter.Close() @@ -102,36 +102,36 @@ type mockSnapshotter struct { func (m *mockSnapshotter) Restore( height uint64, format uint32, protoReader protoio.Reader, -) (types.SnapshotItem, error) { +) (snapshottypes.SnapshotItem, error) { if format == 0 { - return types.SnapshotItem{}, types.ErrUnknownFormat + return snapshottypes.SnapshotItem{}, snapshottypes.ErrUnknownFormat } if m.items != nil { - return types.SnapshotItem{}, errors.New("already has contents") + return snapshottypes.SnapshotItem{}, errors.New("already has contents") } m.items = [][]byte{} for { - item := &types.SnapshotItem{} + item := &snapshottypes.SnapshotItem{} err := protoReader.ReadMsg(item) if err == io.EOF { break } else if err != nil { - return types.SnapshotItem{}, sdkerrors.Wrap(err, "invalid protobuf message") + return snapshottypes.SnapshotItem{}, sdkerrors.Wrap(err, "invalid protobuf message") } payload := item.GetExtensionPayload() if payload == nil { - return types.SnapshotItem{}, sdkerrors.Wrap(err, "invalid protobuf message") + return snapshottypes.SnapshotItem{}, sdkerrors.Wrap(err, "invalid protobuf message") } m.items = append(m.items, payload.Payload) } - return types.SnapshotItem{}, nil + return snapshottypes.SnapshotItem{}, nil } func (m *mockSnapshotter) Snapshot(height uint64, protoWriter protoio.Writer) error { for _, item := range m.items { - if err := types.WriteExtensionItem(protoWriter, item); err != nil { + if err := snapshottypes.WriteExtensionItem(protoWriter, item); err != nil { return err } } @@ -139,11 +139,11 @@ func (m *mockSnapshotter) Snapshot(height uint64, protoWriter protoio.Writer) er } func (m *mockSnapshotter) SnapshotFormat() uint32 { - return types.CurrentFormat + return snapshottypes.CurrentFormat } func (m *mockSnapshotter) SupportedFormats() []uint32 { - return []uint32{types.CurrentFormat} + return []uint32{snapshottypes.CurrentFormat} } func (m *mockSnapshotter) PruneSnapshotHeight(height int64) { @@ -161,14 +161,7 @@ func (m *mockSnapshotter) SetSnapshotInterval(snapshotInterval uint64) { // setupBusyManager creates a manager with an empty store that is busy creating a snapshot at height 1. // The snapshot will complete when the returned closer is called. func setupBusyManager(t *testing.T) *snapshots.Manager { - // os.MkdirTemp() is used instead of testing.T.TempDir() - // see https://github.com/cosmos/cosmos-sdk/pull/8475 for - // this change's rationale. - tempdir, err := os.MkdirTemp("", "") - require.NoError(t, err) - t.Cleanup(func() { _ = os.RemoveAll(tempdir) }) - - store, err := snapshots.NewStore(db.NewMemDB(), tempdir) + store, err := snapshots.NewStore(db.NewMemDB(), testutil.GetTempDir(t)) require.NoError(t, err) hung := newHungSnapshotter() mgr := snapshots.NewManager(store, opts, hung, nil, log.NewNopLogger()) @@ -219,6 +212,6 @@ func (m *hungSnapshotter) SetSnapshotInterval(snapshotInterval uint64) { func (m *hungSnapshotter) Restore( height uint64, format uint32, protoReader protoio.Reader, -) (types.SnapshotItem, error) { +) (snapshottypes.SnapshotItem, error) { panic("not implemented") } diff --git a/snapshots/store_test.go b/snapshots/store_test.go index 47ac556d2b42..1cb27f577211 100644 --- a/snapshots/store_test.go +++ b/snapshots/store_test.go @@ -4,7 +4,6 @@ import ( "bytes" "errors" "io" - "os" "path/filepath" "testing" "time" @@ -19,14 +18,7 @@ import ( ) func setupStore(t *testing.T) *snapshots.Store { - // os.MkdirTemp() is used instead of testing.T.TempDir() - // see https://github.com/cosmos/cosmos-sdk/pull/8475 for - // this change's rationale. - tempdir, err := os.MkdirTemp("", "") - require.NoError(t, err) - t.Cleanup(func() { _ = os.RemoveAll(tempdir) }) - - store, err := snapshots.NewStore(db.NewMemDB(), tempdir) + store, err := snapshots.NewStore(db.NewMemDB(), testutil.GetTempDir(t)) require.NoError(t, err) _, err = store.Save(1, 1, makeChunks([][]byte{ diff --git a/testutil/ioutil.go b/testutil/ioutil.go index 6ff54d24ecb0..2d65a96a01d1 100644 --- a/testutil/ioutil.go +++ b/testutil/ioutil.go @@ -3,6 +3,7 @@ package testutil import ( "bytes" "io" + "io/ioutil" "os" "strings" "testing" @@ -67,8 +68,20 @@ func WriteToNewTempFile(t testing.TB, s string) *os.File { func TempFile(t testing.TB) *os.File { t.Helper() - fp, err := os.CreateTemp(t.TempDir(), "") + fp, err := os.CreateTemp(GetTempDir(t), "") require.NoError(t, err) return fp } + +// GetTempDir returns a writable temporary director for the test to use. +func GetTempDir(t testing.TB) string { + t.Helper() + // ioutil.TempDir() is used instead of testing.T.TempDir() + // see https://github.com/cosmos/cosmos-sdk/pull/8475 for + // this change's rationale. + tempdir, err := ioutil.TempDir("", "") + require.NoError(t, err) + t.Cleanup(func() { _ = os.RemoveAll(tempdir) }) + return tempdir +} diff --git a/testutil/snapshots/util.go b/testutil/snapshots/util.go deleted file mode 100644 index 6c4bf2d992ba..000000000000 --- a/testutil/snapshots/util.go +++ /dev/null @@ -1,19 +0,0 @@ -package snapshots - -import ( - "io/ioutil" - "os" - "testing" - - "github.com/stretchr/testify/require" -) - -func GetTempDir(t *testing.T) string { - // ioutil.TempDir() is used instead of testing.T.TempDir() - // see https://github.com/cosmos/cosmos-sdk/pull/8475 for - // this change's rationale. - tempdir, err := ioutil.TempDir("", "") - require.NoError(t, err) - t.Cleanup(func() { _ = os.RemoveAll(tempdir) }) - return tempdir -} From 5613d2adb7dbb56f98380d13a05760ca710c0a5f Mon Sep 17 00:00:00 2001 From: Roman Akhtariev Date: Wed, 30 Mar 2022 23:10:45 +0000 Subject: [PATCH 05/58] use os.MkdirTemp for creating temp dir --- testutil/ioutil.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testutil/ioutil.go b/testutil/ioutil.go index 2d65a96a01d1..ef33eaa4411e 100644 --- a/testutil/ioutil.go +++ b/testutil/ioutil.go @@ -3,7 +3,6 @@ package testutil import ( "bytes" "io" - "io/ioutil" "os" "strings" "testing" @@ -77,10 +76,11 @@ func TempFile(t testing.TB) *os.File { // GetTempDir returns a writable temporary director for the test to use. func GetTempDir(t testing.TB) string { t.Helper() - // ioutil.TempDir() is used instead of testing.T.TempDir() - // see https://github.com/cosmos/cosmos-sdk/pull/8475 for + // os.MkDir() is used instead of testing.T.TempDir() + // see https://github.com/cosmos/cosmos-sdk/pull/8475 and + // https://github.com/cosmos/cosmos-sdk/pull/10341 for // this change's rationale. - tempdir, err := ioutil.TempDir("", "") + tempdir, err := os.MkdirTemp("", "") require.NoError(t, err) t.Cleanup(func() { _ = os.RemoveAll(tempdir) }) return tempdir From a0d29c69fec004f490836b32c18e77054479558c Mon Sep 17 00:00:00 2001 From: Roman Akhtariev Date: Wed, 30 Mar 2022 23:21:44 +0000 Subject: [PATCH 06/58] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 487c256e03bb..fb6ba4b12941 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,6 +85,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* [\#11496](https://github.com/cosmos/cosmos-sdk/pull/11496) refactor abstractions for snapshot and pruning; snapshot intervals eventually pruned; unit tests. * (store)[\#11152](https://github.com/cosmos/cosmos-sdk/pull/11152) Remove `keep-every` from pruning options. * [\#10950](https://github.com/cosmos/cosmos-sdk/pull/10950) Add `envPrefix` parameter to `cmd.Execute`. * (x/mint) [\#10441](https://github.com/cosmos/cosmos-sdk/pull/10441) The `NewAppModule` function now accepts an inflation calculation function as an argument. From d7449ddbe1b8882eb69b874514f513b1bba6cf64 Mon Sep 17 00:00:00 2001 From: Roman Akhtariev Date: Fri, 1 Apr 2022 15:44:23 +0000 Subject: [PATCH 07/58] rename pruningTypes to pruningtypes --- baseapp/abci_test.go | 4 +- baseapp/baseapp_test.go | 22 +++++------ baseapp/options.go | 8 ++-- server/config/config.go | 8 ++-- server/mock/store.go | 6 +-- server/pruning.go | 12 +++--- server/pruning_test.go | 20 +++++----- server/start.go | 18 ++++----- store/iavl/store.go | 6 +-- store/mem/store.go | 8 ++-- store/rootmulti/dbadapter.go | 8 ++-- store/rootmulti/store.go | 14 +++---- store/rootmulti/store_test.go | 58 ++++++++++++++--------------- store/transient/store.go | 8 ++-- store/transient/store_test.go | 4 +- store/types/store.go | 28 +++++++------- testutil/network/network.go | 6 +-- x/upgrade/types/storeloader_test.go | 8 ++-- 18 files changed, 123 insertions(+), 123 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 0d822db988f7..4520fc04e7a0 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/cosmos/cosmos-sdk/baseapp" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/snapshots" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" @@ -44,7 +44,7 @@ func TestGetBlockRentionHeight(t *testing.T) { "pruning iavl snapshot only": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(pruningTypes.PruningNothing)), + baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)), baseapp.SetMinRetainBlocks(1), baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(10000, 1)), ), diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index f773d32b276a..3fc8ce757e5d 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -21,26 +21,26 @@ import ( "github.com/cosmos/cosmos-sdk/store/rootmulti" "github.com/cosmos/cosmos-sdk/testutil/testdata" - "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/cosmos/cosmos-sdk/x/auth/middleware" - "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" - "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" storeTypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx" + "github.com/cosmos/cosmos-sdk/x/auth/middleware" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" - "google.golang.org/protobuf/proto" "github.com/gogo/protobuf/jsonpb" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" + "google.golang.org/protobuf/proto" ) var ( @@ -2448,7 +2448,7 @@ func TestBaseApp_Init(t *testing.T) { ), sdk.NewCustomPruningOptions(10, 0), sdk.NewSnapshotOptions(1500, 2), - pruningTypes.ErrPruningIntervalZero, + pruningtypes.ErrPruningIntervalZero, }, "error custom pruning too small interval": { baseapp.NewBaseApp(name, logger, db, @@ -2457,7 +2457,7 @@ func TestBaseApp_Init(t *testing.T) { ), sdk.NewCustomPruningOptions(10, 9), sdk.NewSnapshotOptions(1500, 2), - pruningTypes.ErrPruningIntervalTooSmall, + pruningtypes.ErrPruningIntervalTooSmall, }, "error custom pruning too small keep recent": { baseapp.NewBaseApp(name, logger, db, @@ -2466,7 +2466,7 @@ func TestBaseApp_Init(t *testing.T) { ), sdk.NewCustomPruningOptions(9, 10), sdk.NewSnapshotOptions(1500, 2), - pruningTypes.ErrPruningKeepRecentTooSmall, + pruningtypes.ErrPruningKeepRecentTooSmall, }, "snapshot zero interval - manager not set": { baseapp.NewBaseApp(name, logger, db, diff --git a/baseapp/options.go b/baseapp/options.go index 8b5e54a9f31e..3bbb43b27774 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -7,19 +7,19 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/types/tx" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" snapshotTypes "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx" ) // File for storing in-package BaseApp optional functions, // for options that need access to non-exported fields of the BaseApp // SetPruning sets a pruning option on the multistore associated with the app -func SetPruning(opts *pruningTypes.PruningOptions) func(*BaseApp) { +func SetPruning(opts *pruningtypes.PruningOptions) func(*BaseApp) { return func(bapp *BaseApp) { bapp.cms.SetPruning(opts) } } diff --git a/server/config/config.go b/server/config/config.go index 7e37e015177f..2329018f8c04 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -6,8 +6,8 @@ import ( "github.com/spf13/viper" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/telemetry" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -211,7 +211,7 @@ func DefaultConfig() *Config { BaseConfig: BaseConfig{ MinGasPrices: defaultMinGasPrices, InterBlockCache: true, - Pruning: pruningTypes.PruningOptionDefault, + Pruning: pruningtypes.PruningOptionDefault, PruningKeepRecent: "0", PruningInterval: "0", MinRetainBlocks: 0, @@ -327,9 +327,9 @@ func (c Config) ValidateBasic() error { if c.BaseConfig.MinGasPrices == "" { return sdkerrors.ErrAppConfig.Wrap("set min gas price in app.toml or flag or env variable") } - if c.Pruning == pruningTypes.PruningOptionEverything && c.StateSync.SnapshotInterval > 0 { + if c.Pruning == pruningtypes.PruningOptionEverything && c.StateSync.SnapshotInterval > 0 { return sdkerrors.ErrAppConfig.Wrapf( - "cannot enable state sync snapshots with '%s' pruning setting", pruningTypes.PruningOptionEverything, + "cannot enable state sync snapshots with '%s' pruning setting", pruningtypes.PruningOptionEverything, ) } diff --git a/server/mock/store.go b/server/mock/store.go index 6aa339218211..4ca10c40683a 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -6,8 +6,8 @@ import ( protoio "github.com/gogo/protobuf/io" dbm "github.com/tendermint/tm-db" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" snapshotTypes "github.com/cosmos/cosmos-sdk/snapshots/types" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" storeTypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -66,11 +66,11 @@ func (ms multiStore) LastCommitID() storeTypes.CommitID { panic("not implemented") } -func (ms multiStore) SetPruning(opts *pruningTypes.PruningOptions) { +func (ms multiStore) SetPruning(opts *pruningtypes.PruningOptions) { panic("not implemented") } -func (ms multiStore) GetPruning() *pruningTypes.PruningOptions { +func (ms multiStore) GetPruning() *pruningtypes.PruningOptions { panic("not implemented") } diff --git a/server/pruning.go b/server/pruning.go index d6d48de0b8e2..ee9c36dcaa39 100644 --- a/server/pruning.go +++ b/server/pruning.go @@ -6,22 +6,22 @@ import ( "github.com/spf13/cast" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/server/types" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" ) // GetPruningOptionsFromFlags parses command flags and returns the correct // PruningOptions. If a pruning strategy is provided, that will be parsed and // returned, otherwise, it is assumed custom pruning options are provided. -func GetPruningOptionsFromFlags(appOpts types.AppOptions) (*pruningTypes.PruningOptions, error) { +func GetPruningOptionsFromFlags(appOpts types.AppOptions) (*pruningtypes.PruningOptions, error) { strategy := strings.ToLower(cast.ToString(appOpts.Get(FlagPruning))) switch strategy { - case pruningTypes.PruningOptionDefault, pruningTypes.PruningOptionNothing, pruningTypes.PruningOptionEverything: - return pruningTypes.NewPruningOptionsFromString(strategy), nil + case pruningtypes.PruningOptionDefault, pruningtypes.PruningOptionNothing, pruningtypes.PruningOptionEverything: + return pruningtypes.NewPruningOptionsFromString(strategy), nil - case pruningTypes.PruningOptionCustom: - opts := pruningTypes.NewCustomPruningOptions( + case pruningtypes.PruningOptionCustom: + opts := pruningtypes.NewCustomPruningOptions( cast.ToUint64(appOpts.Get(FlagPruningKeepRecent)), cast.ToUint64(appOpts.Get(FlagPruningInterval)), ) diff --git a/server/pruning_test.go b/server/pruning_test.go index f7f5a97efe19..2321476b548f 100644 --- a/server/pruning_test.go +++ b/server/pruning_test.go @@ -6,45 +6,45 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/require" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) func TestGetPruningOptionsFromFlags(t *testing.T) { tests := []struct { name string initParams func() *viper.Viper - expectedOptions *pruningTypes.PruningOptions + expectedOptions *pruningtypes.PruningOptions wantErr bool }{ { name: FlagPruning, initParams: func() *viper.Viper { v := viper.New() - v.Set(FlagPruning, pruningTypes.PruningOptionNothing) + v.Set(FlagPruning, pruningtypes.PruningOptionNothing) return v }, - expectedOptions: pruningTypes.NewPruningOptions(pruningTypes.PruningNothing), + expectedOptions: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), }, { name: "custom pruning options", initParams: func() *viper.Viper { v := viper.New() - v.Set(FlagPruning, pruningTypes.PruningOptionCustom) + v.Set(FlagPruning, pruningtypes.PruningOptionCustom) v.Set(FlagPruningKeepRecent, 1234) v.Set(FlagPruningInterval, 10) return v }, - expectedOptions: pruningTypes.NewCustomPruningOptions(1234, 10), + expectedOptions: pruningtypes.NewCustomPruningOptions(1234, 10), }, { - name: pruningTypes.PruningOptionDefault, + name: pruningtypes.PruningOptionDefault, initParams: func() *viper.Viper { v := viper.New() - v.Set(FlagPruning, pruningTypes.PruningOptionDefault) + v.Set(FlagPruning, pruningtypes.PruningOptionDefault) return v }, - expectedOptions: pruningTypes.NewPruningOptions(pruningTypes.PruningDefault), + expectedOptions: pruningtypes.NewPruningOptions(pruningtypes.PruningDefault), }, } @@ -53,7 +53,7 @@ func TestGetPruningOptionsFromFlags(t *testing.T) { t.Run(tt.name, func(j *testing.T) { viper.Reset() - viper.SetDefault(FlagPruning, pruningTypes.PruningOptionDefault) + viper.SetDefault(FlagPruning, pruningtypes.PruningOptionDefault) v := tt.initParams() opts, err := GetPruningOptionsFromFlags(v) diff --git a/server/start.go b/server/start.go index f0f3d1a0af19..bc0485c11b24 100644 --- a/server/start.go +++ b/server/start.go @@ -13,25 +13,25 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" - "github.com/cosmos/cosmos-sdk/server/rosetta" - "github.com/cosmos/cosmos-sdk/server/types" servergrpc "github.com/cosmos/cosmos-sdk/server/grpc" + "github.com/cosmos/cosmos-sdk/server/rosetta" crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + "github.com/cosmos/cosmos-sdk/server/types" "github.com/spf13/cobra" - "github.com/tendermint/tendermint/abci/server" - "github.com/tendermint/tendermint/node" - "github.com/tendermint/tendermint/rpc/client/local" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" abciclient "github.com/tendermint/tendermint/abci/client" + "github.com/tendermint/tendermint/abci/server" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" tmos "github.com/tendermint/tendermint/libs/os" tmservice "github.com/tendermint/tendermint/libs/service" + "github.com/tendermint/tendermint/node" + "github.com/tendermint/tendermint/rpc/client/local" tmtypes "github.com/tendermint/tendermint/types" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" ) const ( @@ -159,7 +159,7 @@ is performed. Note, when enabled, gRPC will also be automatically enabled. cmd.Flags().Bool(FlagInterBlockCache, true, "Enable inter-block caching") cmd.Flags().String(flagCPUProfile, "", "Enable CPU profiling and write to the provided file") cmd.Flags().Bool(FlagTrace, false, "Provide full stack traces for errors in ABCI Log") - cmd.Flags().String(FlagPruning, pruningTypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)") + cmd.Flags().String(FlagPruning, pruningtypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)") cmd.Flags().Uint64(FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')") cmd.Flags().Uint64(FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')") cmd.Flags().Uint(FlagInvCheckPeriod, 0, "Assert registered invariants every N blocks") diff --git a/store/iavl/store.go b/store/iavl/store.go index 28906f4819ff..fdcf3b96eda4 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -12,7 +12,7 @@ import ( tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" dbm "github.com/tendermint/tm-db" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" @@ -129,13 +129,13 @@ func (st *Store) LastCommitID() types.CommitID { // SetPruning panics as pruning options should be provided at initialization // since IAVl accepts pruning options directly. -func (st *Store) SetPruning(_ *pruningTypes.PruningOptions) { +func (st *Store) SetPruning(_ *pruningtypes.PruningOptions) { panic("cannot set pruning options on an initialized IAVL store") } // SetPruning panics as pruning options should be provided at initialization // since IAVl accepts pruning options directly. -func (st *Store) GetPruning() *pruningTypes.PruningOptions { +func (st *Store) GetPruning() *pruningtypes.PruningOptions { panic("cannot get pruning options on an initialized IAVL store") } diff --git a/store/mem/store.go b/store/mem/store.go index 1f6ebacdc2dc..b48a566c853b 100644 --- a/store/mem/store.go +++ b/store/mem/store.go @@ -5,7 +5,7 @@ import ( dbm "github.com/tendermint/tm-db" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/listenkv" @@ -55,12 +55,12 @@ func (s Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types // Commit performs a no-op as entries are persistent between commitments. func (s *Store) Commit() (id types.CommitID) { return } -func (s *Store) SetPruning(pruning *pruningTypes.PruningOptions) {} +func (s *Store) SetPruning(pruning *pruningtypes.PruningOptions) {} // GetPruning is a no-op as pruning options cannot be directly set on this store. // They must be set on the root commit multi-store. -func (s *Store) GetPruning() *pruningTypes.PruningOptions { - return pruningTypes.NewPruningOptions(pruningTypes.PruningUndefined) +func (s *Store) GetPruning() *pruningtypes.PruningOptions { + return pruningtypes.NewPruningOptions(pruningtypes.PruningUndefined) } func (s Store) LastCommitID() (id types.CommitID) { return } diff --git a/store/rootmulti/dbadapter.go b/store/rootmulti/dbadapter.go index 157681461eec..b862375ae017 100644 --- a/store/rootmulti/dbadapter.go +++ b/store/rootmulti/dbadapter.go @@ -1,7 +1,7 @@ package rootmulti import ( - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -31,10 +31,10 @@ func (cdsa commitDBStoreAdapter) LastCommitID() types.CommitID { } } -func (cdsa commitDBStoreAdapter) SetPruning(_ *pruningTypes.PruningOptions) {} +func (cdsa commitDBStoreAdapter) SetPruning(_ *pruningtypes.PruningOptions) {} // GetPruning is a no-op as pruning options cannot be directly set on this store. // They must be set on the root commit multi-store. -func (cdsa commitDBStoreAdapter) GetPruning() *pruningTypes.PruningOptions { - return pruningTypes.NewPruningOptions(pruningTypes.PruningUndefined) +func (cdsa commitDBStoreAdapter) GetPruning() *pruningtypes.PruningOptions { + return pruningtypes.NewPruningOptions(pruningtypes.PruningUndefined) } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 6101df0679bf..2cd4516181ac 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -9,7 +9,9 @@ import ( "sync" "github.com/cosmos/cosmos-sdk/pruning" - + + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/iavl" @@ -18,16 +20,14 @@ import ( "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/transient" "github.com/cosmos/cosmos-sdk/store/types" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/tendermint/tendermint/libs/log" - "github.com/pkg/errors" iavltree "github.com/cosmos/iavl" protoio "github.com/gogo/protobuf/io" gogotypes "github.com/gogo/protobuf/types" + "github.com/pkg/errors" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" ) @@ -85,14 +85,14 @@ func NewStore(db dbm.DB, logger log.Logger) *Store { } // GetPruning fetches the pruning strategy from the root store. -func (rs *Store) GetPruning() *pruningTypes.PruningOptions { +func (rs *Store) GetPruning() *pruningtypes.PruningOptions { return rs.pruningManager.GetOptions() } // SetPruning sets the pruning strategy on the root store and all the sub-stores. // Note, calling SetPruning on the root store prior to LoadVersion or // LoadLatestVersion performs a no-op as the stores aren't mounted yet. -func (rs *Store) SetPruning(pruningOpts *pruningTypes.PruningOptions) { +func (rs *Store) SetPruning(pruningOpts *pruningtypes.PruningOptions) { rs.pruningManager.SetOptions(pruningOpts) } diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index bbf2f9524d7e..4fe61b4b44ef 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -13,7 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codecTypes "github.com/cosmos/cosmos-sdk/codec/types" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/iavl" sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps" @@ -30,7 +30,7 @@ func TestStoreType(t *testing.T) { func TestGetCommitKVStore(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningDefault)) + ms := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningDefault)) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -63,7 +63,7 @@ func TestStoreMount(t *testing.T) { func TestCacheMultiStore(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + ms := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) cacheMulti := ms.CacheMultiStore() require.IsType(t, cachemulti.Store{}, cacheMulti) @@ -71,7 +71,7 @@ func TestCacheMultiStore(t *testing.T) { func TestCacheMultiStoreWithVersion(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + ms := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -108,7 +108,7 @@ func TestCacheMultiStoreWithVersion(t *testing.T) { func TestHashStableWithEmptyCommit(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + ms := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -132,7 +132,7 @@ func TestHashStableWithEmptyCommit(t *testing.T) { func TestMultistoreCommitLoad(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - store := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + store := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err := store.LoadLatestVersion() require.Nil(t, err) @@ -157,7 +157,7 @@ func TestMultistoreCommitLoad(t *testing.T) { } // Load the latest multistore again and check version. - store = newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + store = newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err = store.LoadLatestVersion() require.Nil(t, err) commitID = getExpectedCommitID(store, nCommits) @@ -170,7 +170,7 @@ func TestMultistoreCommitLoad(t *testing.T) { // Load an older multistore and check version. ver := nCommits - 1 - store = newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + store = newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err = store.LoadVersion(ver) require.Nil(t, err) commitID = getExpectedCommitID(store, ver) @@ -179,7 +179,7 @@ func TestMultistoreCommitLoad(t *testing.T) { func TestMultistoreLoadWithUpgrade(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - store := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + store := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err := store.LoadLatestVersion() require.Nil(t, err) @@ -214,7 +214,7 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { checkContains(t, ci.StoreInfos, []string{"store1", "store2", "store3"}) // Load without changes and make sure it is sensible - store = newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + store = newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err = store.LoadLatestVersion() require.Nil(t, err) @@ -227,7 +227,7 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { require.Equal(t, v2, s2.Get(k2)) // now, let's load with upgrades... - restore, upgrades := newMultiStoreWithModifiedMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + restore, upgrades := newMultiStoreWithModifiedMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err = restore.LoadLatestVersionAndUpgrade(upgrades) require.Nil(t, err) @@ -272,7 +272,7 @@ func TestMultistoreLoadWithUpgrade(t *testing.T) { migratedID := restore.Commit() require.Equal(t, migratedID.Version, int64(2)) - reload, _ := newMultiStoreWithModifiedMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + reload, _ := newMultiStoreWithModifiedMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err = reload.LoadLatestVersion() require.Nil(t, err) require.Equal(t, migratedID, reload.LastCommitID()) @@ -321,7 +321,7 @@ func TestParsePath(t *testing.T) { func TestMultiStoreRestart(t *testing.T) { db := dbm.NewMemDB() - pruning := pruningTypes.NewCustomPruningOptions(2, 1) + pruning := pruningtypes.NewCustomPruningOptions(2, 1) multi := newMultiStoreWithMounts(db, pruning) err := multi.LoadLatestVersion() require.Nil(t, err) @@ -400,7 +400,7 @@ func TestMultiStoreRestart(t *testing.T) { func TestMultiStoreQuery(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + multi := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err := multi.LoadLatestVersion() require.Nil(t, err) @@ -427,7 +427,7 @@ func TestMultiStoreQuery(t *testing.T) { ver := cid.Version // Reload multistore from database - multi = newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + multi = newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err = multi.LoadLatestVersion() require.Nil(t, err) @@ -472,15 +472,15 @@ func TestMultiStore_Pruning(t *testing.T) { testCases := []struct { name string numVersions int64 - po *pruningTypes.PruningOptions + po *pruningtypes.PruningOptions deleted []int64 saved []int64 }{ - {"prune nothing", 10, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, - {"prune everything", 10, pruningTypes.NewPruningOptions(pruningTypes.PruningEverything), []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}, []int64{10}}, - {"prune some; no batch", 10, pruningTypes.NewCustomPruningOptions(2, 1), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}}, - {"prune some; small batch", 10, pruningTypes.NewCustomPruningOptions(2, 3), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}}, - {"prune some; large batch", 10, pruningTypes.NewCustomPruningOptions(2, 11), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, + {"prune nothing", 10, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, + {"prune everything", 10, pruningtypes.NewPruningOptions(pruningtypes.PruningEverything), []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}, []int64{10}}, + {"prune some; no batch", 10, pruningtypes.NewCustomPruningOptions(2, 1), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}}, + {"prune some; small batch", 10, pruningtypes.NewCustomPruningOptions(2, 3), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}}, + {"prune some; large batch", 10, pruningtypes.NewCustomPruningOptions(2, 11), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, } for _, tc := range testCases { @@ -510,7 +510,7 @@ func TestMultiStore_Pruning(t *testing.T) { func TestMultiStore_PruningRestart(t *testing.T) { db := dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, pruningTypes.NewCustomPruningOptions(2, 11)) + ms := newMultiStoreWithMounts(db, pruningtypes.NewCustomPruningOptions(2, 11)) ms.SetSnapshotInterval(3) require.NoError(t, ms.LoadLatestVersion()) @@ -528,7 +528,7 @@ func TestMultiStore_PruningRestart(t *testing.T) { require.Equal(t, pruneHeights, ms.pruningManager.GetPruningHeights()) // "restart" - ms = newMultiStoreWithMounts(db, pruningTypes.NewCustomPruningOptions(2, 11)) + ms = newMultiStoreWithMounts(db, pruningtypes.NewCustomPruningOptions(2, 11)) ms.SetSnapshotInterval(3) err = ms.LoadLatestVersion() require.NoError(t, err) @@ -546,7 +546,7 @@ func TestMultiStore_PruningRestart(t *testing.T) { func TestSetInitialVersion(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + multi := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) require.NoError(t, multi.LoadLatestVersion()) @@ -564,7 +564,7 @@ func TestSetInitialVersion(t *testing.T) { func TestAddListenersAndListeningEnabled(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + multi := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) testKey := types.NewKVStoreKey("listening_test_key") enabled := multi.ListeningEnabled(testKey) require.False(t, enabled) @@ -595,7 +595,7 @@ var ( func TestGetListenWrappedKVStore(t *testing.T) { buf := new(bytes.Buffer) var db dbm.DB = dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + ms := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) ms.LoadLatestVersion() mockListeners := []types.WriteListener{types.NewStoreKVPairWriteListener(buf, testMarshaller)} ms.AddListeners(testStoreKey1, mockListeners) @@ -671,7 +671,7 @@ func TestGetListenWrappedKVStore(t *testing.T) { func TestCacheWraps(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + multi := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) cacheWrapper := multi.CacheWrap() require.IsType(t, cachemulti.Store{}, cacheWrapper) @@ -742,7 +742,7 @@ var ( testStoreKey3 = types.NewKVStoreKey("store3") ) -func newMultiStoreWithMounts(db dbm.DB, pruningOpts *pruningTypes.PruningOptions) *Store { +func newMultiStoreWithMounts(db dbm.DB, pruningOpts *pruningtypes.PruningOptions) *Store { store := NewStore(db, log.NewNopLogger()) store.SetPruning(pruningOpts) @@ -753,7 +753,7 @@ func newMultiStoreWithMounts(db dbm.DB, pruningOpts *pruningTypes.PruningOptions return store } -func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts *pruningTypes.PruningOptions) (*Store, *types.StoreUpgrades) { +func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts *pruningtypes.PruningOptions) (*Store, *types.StoreUpgrades) { store := NewStore(db, log.NewNopLogger()) store.SetPruning(pruningOpts) diff --git a/store/transient/store.go b/store/transient/store.go index 90370b5939c6..5c40c3b134f5 100644 --- a/store/transient/store.go +++ b/store/transient/store.go @@ -3,7 +3,7 @@ package transient import ( dbm "github.com/tendermint/tm-db" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -28,12 +28,12 @@ func (ts *Store) Commit() (id types.CommitID) { return } -func (ts *Store) SetPruning(_ *pruningTypes.PruningOptions) {} +func (ts *Store) SetPruning(_ *pruningtypes.PruningOptions) {} // GetPruning is a no-op as pruning options cannot be directly set on this store. // They must be set on the root commit multi-store. -func (ts *Store) GetPruning() *pruningTypes.PruningOptions { - return pruningTypes.NewPruningOptions(pruningTypes.PruningUndefined) +func (ts *Store) GetPruning() *pruningtypes.PruningOptions { + return pruningtypes.NewPruningOptions(pruningtypes.PruningUndefined) } // Implements CommitStore diff --git a/store/transient/store_test.go b/store/transient/store_test.go index c13d91448f5e..900e6cb7a918 100644 --- a/store/transient/store_test.go +++ b/store/transient/store_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/transient" types "github.com/cosmos/cosmos-sdk/store/v2alpha1" ) @@ -27,7 +27,7 @@ func TestTransientStore(t *testing.T) { require.Nil(t, tstore.Get(k)) // no-op - tstore.SetPruning(pruningTypes.NewPruningOptions(pruningTypes.PruningUndefined)) + tstore.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningUndefined)) emptyCommitID := tstore.LastCommitID() require.Equal(t, emptyCommitID.Version, int64(0)) diff --git a/store/types/store.go b/store/types/store.go index c4a08f711584..6ba93ee13f9e 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -8,8 +8,8 @@ import ( tmstrings "github.com/tendermint/tendermint/libs/strings" dbm "github.com/tendermint/tm-db" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" snapshotTypes "github.com/cosmos/cosmos-sdk/snapshots/types" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/types/kv" ) @@ -449,28 +449,28 @@ type StoreWithInitialVersion interface { } type ( - PruningOptions = pruningTypes.PruningOptions - PruningStrategy = pruningTypes.PruningStrategy + PruningOptions = pruningtypes.PruningOptions + PruningStrategy = pruningtypes.PruningStrategy ) const ( - PruningOptionDefault = pruningTypes.PruningOptionDefault - PruningOptionEverything = pruningTypes.PruningOptionEverything - PruningOptionNothing = pruningTypes.PruningOptionNothing - PruningOptionCustom = pruningTypes.PruningOptionCustom - - PruningDefault = pruningTypes.PruningDefault - PruningEverything = pruningTypes.PruningEverything - PruningNothing = pruningTypes.PruningNothing - PruningCustom = pruningTypes.PruningCustom + PruningOptionDefault = pruningtypes.PruningOptionDefault + PruningOptionEverything = pruningtypes.PruningOptionEverything + PruningOptionNothing = pruningtypes.PruningOptionNothing + PruningOptionCustom = pruningtypes.PruningOptionCustom + + PruningDefault = pruningtypes.PruningDefault + PruningEverything = pruningtypes.PruningEverything + PruningNothing = pruningtypes.PruningNothing + PruningCustom = pruningtypes.PruningCustom ) func NewPruningOptions(pruningStrategy PruningStrategy) *PruningOptions { - return pruningTypes.NewPruningOptions(pruningStrategy) + return pruningtypes.NewPruningOptions(pruningStrategy) } func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { - return pruningTypes.NewCustomPruningOptions(keepRecent, interval) + return pruningtypes.NewCustomPruningOptions(keepRecent, interval) } type SnapshotOptions = snapshotTypes.SnapshotOptions diff --git a/testutil/network/network.go b/testutil/network/network.go index 684c70264656..995eb56889df 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -32,7 +32,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" srvconfig "github.com/cosmos/cosmos-sdk/server/config" @@ -61,7 +61,7 @@ func NewAppConstructor(encodingCfg params.EncodingConfig) AppConstructor { val.Ctx.Logger, dbm.NewMemDB(), nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0, encodingCfg, simapp.EmptyAppOptions{}, - baseapp.SetPruning(pruningTypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), + baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices), ) } @@ -119,7 +119,7 @@ func DefaultConfig() Config { AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction), StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction), BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction), - PruningStrategy: pruningTypes.PruningOptionNothing, + PruningStrategy: pruningtypes.PruningOptionNothing, CleanupDir: true, SigningAlgo: string(hd.Secp256k1Type), KeyringOptions: []keyring.Option{}, diff --git a/x/upgrade/types/storeloader_test.go b/x/upgrade/types/storeloader_test.go index 4031642d56da..ba3d772039b7 100644 --- a/x/upgrade/types/storeloader_test.go +++ b/x/upgrade/types/storeloader_test.go @@ -14,10 +14,10 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/baseapp" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/store/rootmulti" storetypes "github.com/cosmos/cosmos-sdk/store/types" - pruningTypes "github.com/cosmos/cosmos-sdk/pruning/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -36,7 +36,7 @@ func defaultLogger() log.Logger { func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { rs := rootmulti.NewStore(db, log.NewNopLogger()) - rs.SetPruning(pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + rs.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) key := sdk.NewKVStoreKey(storeKey) rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() @@ -53,7 +53,7 @@ func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) { rs := rootmulti.NewStore(db, log.NewNopLogger()) - rs.SetPruning(pruningTypes.NewPruningOptions(pruningTypes.PruningNothing)) + rs.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) key := sdk.NewKVStoreKey(storeKey) rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() @@ -123,7 +123,7 @@ func TestSetLoader(t *testing.T) { initStore(t, db, tc.origStoreKey, k, v) // load the app with the existing db - opts := []func(*baseapp.BaseApp){baseapp.SetPruning(pruningTypes.NewPruningOptions(pruningTypes.PruningNothing))} + opts := []func(*baseapp.BaseApp){baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing))} origapp := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, opts...) origapp.MountStores(sdk.NewKVStoreKey(tc.origStoreKey)) From aef77b5a90cf3bab73daedeb30c627e2a5b192ab Mon Sep 17 00:00:00 2001 From: Roman Akhtariev Date: Fri, 1 Apr 2022 15:45:37 +0000 Subject: [PATCH 08/58] rename snapshotTypes to snapshotypes --- baseapp/options.go | 6 +++--- server/mock/store.go | 4 ++-- snapshots/helpers_test.go | 10 +++++----- store/types/store.go | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/baseapp/options.go b/baseapp/options.go index 3bbb43b27774..dddff27feaf6 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/snapshots" - snapshotTypes "github.com/cosmos/cosmos-sdk/snapshots/types" + snapshotypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx" @@ -72,7 +72,7 @@ func SetInterBlockCache(cache sdk.MultiStorePersistentCache) func(*BaseApp) { } // SetSnapshot sets the snapshot store. -func SetSnapshot(snapshotStore *snapshots.Store, opts *snapshotTypes.SnapshotOptions) func(*BaseApp) { +func SetSnapshot(snapshotStore *snapshots.Store, opts *snapshotypes.SnapshotOptions) func(*BaseApp) { return func(app *BaseApp) { app.SetSnapshot(snapshotStore, opts) } } @@ -194,7 +194,7 @@ func (app *BaseApp) SetStoreLoader(loader StoreLoader) { } // SetSnapshot sets the snapshot store and options. -func (app *BaseApp) SetSnapshot(snapshotStore *snapshots.Store, opts *snapshotTypes.SnapshotOptions) { +func (app *BaseApp) SetSnapshot(snapshotStore *snapshots.Store, opts *snapshotypes.SnapshotOptions) { if app.sealed { panic("SetSnapshot() on sealed BaseApp") } diff --git a/server/mock/store.go b/server/mock/store.go index 4ca10c40683a..2108d8eee072 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -7,7 +7,7 @@ import ( dbm "github.com/tendermint/tm-db" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" - snapshotTypes "github.com/cosmos/cosmos-sdk/snapshots/types" + snapshotypes "github.com/cosmos/cosmos-sdk/snapshots/types" storeTypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -143,7 +143,7 @@ func (ms multiStore) Snapshot(height uint64, protoWriter protoio.Writer) error { func (ms multiStore) Restore( height uint64, format uint32, protoReader protoio.Reader, -) (snapshotTypes.SnapshotItem, error) { +) (snapshotypes.SnapshotItem, error) { panic("not implemented") } diff --git a/snapshots/helpers_test.go b/snapshots/helpers_test.go index b579eaaf1112..d10381bf3315 100644 --- a/snapshots/helpers_test.go +++ b/snapshots/helpers_test.go @@ -95,8 +95,8 @@ func snapshotItems(items [][]byte) [][]byte { } type mockSnapshotter struct { - items [][]byte - prunedHeights map[int64]struct{} + items [][]byte + prunedHeights map[int64]struct{} snapshotInterval uint64 } @@ -181,14 +181,14 @@ func setupBusyManager(t *testing.T) *snapshots.Manager { // hungSnapshotter can be used to test operations in progress. Call close to end the snapshot. type hungSnapshotter struct { - ch chan struct{} - prunedHeights map[int64]struct{} + ch chan struct{} + prunedHeights map[int64]struct{} snapshotInterval uint64 } func newHungSnapshotter() *hungSnapshotter { return &hungSnapshotter{ - ch: make(chan struct{}), + ch: make(chan struct{}), prunedHeights: make(map[int64]struct{}), } } diff --git a/store/types/store.go b/store/types/store.go index 6ba93ee13f9e..f7e86c62d80f 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -9,7 +9,7 @@ import ( dbm "github.com/tendermint/tm-db" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" - snapshotTypes "github.com/cosmos/cosmos-sdk/snapshots/types" + snapshotypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/types/kv" ) @@ -143,7 +143,7 @@ type CacheMultiStore interface { type CommitMultiStore interface { Committer MultiStore - snapshotTypes.Snapshotter + snapshotypes.Snapshotter // Mount a store of type using the given db. // If db == nil, the new store will use the CommitMultiStore db. @@ -473,8 +473,8 @@ func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { return pruningtypes.NewCustomPruningOptions(keepRecent, interval) } -type SnapshotOptions = snapshotTypes.SnapshotOptions +type SnapshotOptions = snapshotypes.SnapshotOptions func NewSnapshotOptions(interval uint64, keepRecent uint32) *SnapshotOptions { - return snapshotTypes.NewSnapshotOptions(interval, keepRecent) + return snapshotypes.NewSnapshotOptions(interval, keepRecent) } From a7c031198bcd13fd5f44fabbe28bebe02ef96c48 Mon Sep 17 00:00:00 2001 From: Roman Akhtariev Date: Fri, 1 Apr 2022 15:58:28 +0000 Subject: [PATCH 09/58] update pruning default with correct values, update pruning everything description in command --- pruning/README.md | 2 +- pruning/types/options.go | 11 +++++------ server/start.go | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pruning/README.md b/pruning/README.md index 35d0c2351ce7..91b9435bec2b 100644 --- a/pruning/README.md +++ b/pruning/README.md @@ -10,7 +10,7 @@ the states and prune nothing. On the other hand, a regular validator node may wa The strategies are configured in `app.toml`: pruning = "< strategy >" # where the options are: -- `default`: only the last 100,000 states(approximately 1 week worth of state) are kept; pruning at 100 block intervals +- `default`: only the last 362,880 states(approximately 3.5 weeks worth of state) are kept; pruning at 10 block intervals - `nothing`: all historic states will be saved, nothing will be deleted (i.e. archiving node) - `everything`: 2 latest states will be kept; pruning at 10 block intervals. - `custom`: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' diff --git a/pruning/types/options.go b/pruning/types/options.go index 84ed73b41e8c..bfb1dc814184 100644 --- a/pruning/types/options.go +++ b/pruning/types/options.go @@ -29,11 +29,10 @@ const ( ) const ( - // PruningDefault defines a pruning strategy where the last 100,000 heights are + // PruningDefault defines a pruning strategy where the last 362880 heights are // kept where to-be pruned heights are pruned at every 10th height. - // The last 100000 heights are kept(approximately 1 week worth of state) assuming the typical - // block time is 6s. If these values - // do not match the applications' requirements, use the "custom" option. + // The last 362880 heights are kept(approximately 3.5 weeks worth of state) assuming the typical + // block time is 6s. If these values do not match the applications' requirements, use the "custom" option. PruningDefault PruningStrategy = iota // PruningEverything defines a pruning strategy where all committed heights are // deleted, storing only the current height and last 2 states. To-be pruned heights are @@ -63,8 +62,8 @@ func NewPruningOptions(pruningStrategy PruningStrategy) *PruningOptions { switch pruningStrategy { case PruningDefault: return &PruningOptions{ - KeepRecent: 100_000, - Interval: 100, + KeepRecent: 362880, + Interval: 10, Strategy: PruningDefault, } case PruningEverything: diff --git a/server/start.go b/server/start.go index bc0485c11b24..1afee407b563 100644 --- a/server/start.go +++ b/server/start.go @@ -93,7 +93,7 @@ For '--pruning' the options are as follows: default: the last 362880 states are kept, pruning at 10 block intervals nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) -everything: all saved states will be deleted, storing only the current state; pruning at 10 block intervals +everything: 2 latest states will be kept; pruning at 10 block intervals. custom: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' Node halting configurations exist in the form of two flags: '--halt-height' and '--halt-time'. During From d66ed2972d94a886dceb152bf7f19576cfa20418 Mon Sep 17 00:00:00 2001 From: Roman Akhtariev Date: Fri, 1 Apr 2022 16:03:31 +0000 Subject: [PATCH 10/58] fix pruning options unit test to reflect the updated default value --- pruning/manager_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pruning/manager_test.go b/pruning/manager_test.go index bd45bf8b47db..f7cb55becbf3 100644 --- a/pruning/manager_test.go +++ b/pruning/manager_test.go @@ -90,8 +90,8 @@ func Test_Strategies(t *testing.T) { // Validate strategy parameters switch pruneStrategy { case types.PruningDefault: - require.Equal(t, uint64(100000), curStrategy.KeepRecent) - require.Equal(t, uint64(100), curStrategy.Interval) + require.Equal(t, uint64(362880), curStrategy.KeepRecent) + require.Equal(t, uint64(10), curStrategy.Interval) case types.PruningNothing: require.Equal(t, uint64(0), curStrategy.KeepRecent) require.Equal(t, uint64(0), curStrategy.Interval) From d12d255bb6f01661d127e430c956328ec4c3dd47 Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 14:32:28 -0400 Subject: [PATCH 11/58] address functional and security related comments --- baseapp/baseapp.go | 5 +-- pruning/export_test.go | 12 ++++++ pruning/manager.go | 72 ++++++++++++++++++++------------- pruning/manager_test.go | 82 +++++++++++++++++++++++++++++++++++--- snapshots/manager.go | 9 ++++- snapshots/types/options.go | 2 +- store/rootmulti/store.go | 28 +++++++------ 7 files changed, 157 insertions(+), 53 deletions(-) create mode 100644 pruning/export_test.go diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 62d607c9d456..062b003c57a6 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -308,10 +308,7 @@ func (app *BaseApp) Init() error { if !ok { return errors.New("rootmulti store is required") } - if err := rms.GetPruning().Validate(); err != nil { - return err - } - return nil + return rms.GetPruning().Validate() } func (app *BaseApp) setMinGasPrices(gasPrices sdk.DecCoins) { diff --git a/pruning/export_test.go b/pruning/export_test.go new file mode 100644 index 000000000000..c4bc2d432ef2 --- /dev/null +++ b/pruning/export_test.go @@ -0,0 +1,12 @@ +package pruning + +const ErrNegativeHeightsFmt = errNegativeHeightsFmt + +var ( + PruneHeightsKey = pruneHeightsKey + PruneSnapshotHeightsKey = pruneSnapshotHeightsKey + + // functions + Int64SliceToBytes = int64SliceToBytes + ListToBytes = listToBytes +) diff --git a/pruning/manager.go b/pruning/manager.go index c2354f8b0fe0..e2fdf4319ccd 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -21,9 +21,11 @@ type Manager struct { mx sync.Mutex } -const ( - pruneHeightsKey = "s/pruneheights" - pruneSnapshotHeightsKey = "s/pruneSnheights" +const errNegativeHeightsFmt = "failed to get pruned heights: %d" + +var ( + pruneHeightsKey = []byte("s/pruneheights") + pruneSnapshotHeightsKey = []byte("s/pruneSnheights") ) func NewManager(logger log.Logger) *Manager { @@ -55,7 +57,8 @@ func (m *Manager) GetPruningHeights() []int64 { // ResetPruningHeights resets the heights to be pruned. func (m *Manager) ResetPruningHeights() { - m.pruneHeights = make([]int64, 0) + // reuse previously allocated memory. + m.pruneHeights = m.pruneHeights[:0] } // HandleHeight determines if pruneHeight height needs to be kept for pruning at the right interval prescribed by @@ -116,7 +119,7 @@ func (m *Manager) SetSnapshotInterval(snapshotInterval uint64) { // ShouldPruneAtHeight return true if the given height should be pruned, false otherwise func (m *Manager) ShouldPruneAtHeight(height int64) bool { - return m.opts.GetPruningStrategy() != types.PruningNothing && m.opts.Interval > 0 && height%int64(m.opts.Interval) == 0 + return m.opts.Interval > 0 && m.opts.GetPruningStrategy() != types.PruningNothing && height%int64(m.opts.Interval) == 0 } // FlushPruningHeights flushes the pruning heights to the database for crash recovery. @@ -136,14 +139,11 @@ func (m *Manager) LoadPruningHeights(db dbm.DB) error { if err := m.loadPruningHeights(db); err != nil { return err } - if err := m.loadPruningSnapshotHeights(db); err != nil { - return err - } - return nil + return m.loadPruningSnapshotHeights(db) } func (m *Manager) loadPruningHeights(db dbm.DB) error { - bz, err := db.Get([]byte(pruneHeightsKey)) + bz, err := db.Get(pruneHeightsKey) if err != nil { return fmt.Errorf("failed to get pruned heights: %w", err) } @@ -154,7 +154,12 @@ func (m *Manager) loadPruningHeights(db dbm.DB) error { prunedHeights := make([]int64, len(bz)/8) i, offset := 0, 0 for offset < len(bz) { - prunedHeights[i] = int64(binary.BigEndian.Uint64(bz[offset : offset+8])) + h := int64(binary.BigEndian.Uint64(bz[offset : offset+8])) + if h < 0 { + return fmt.Errorf(errNegativeHeightsFmt, h) + } + + prunedHeights[i] = h i++ offset += 8 } @@ -167,7 +172,7 @@ func (m *Manager) loadPruningHeights(db dbm.DB) error { } func (m *Manager) loadPruningSnapshotHeights(db dbm.DB) error { - bz, err := db.Get([]byte(pruneSnapshotHeightsKey)) + bz, err := db.Get(pruneSnapshotHeightsKey) if err != nil { return fmt.Errorf("failed to get post-snapshot pruned heights: %w", err) } @@ -178,39 +183,50 @@ func (m *Manager) loadPruningSnapshotHeights(db dbm.DB) error { pruneSnapshotHeights := list.New() i, offset := 0, 0 for offset < len(bz) { - pruneSnapshotHeights.PushBack(int64(binary.BigEndian.Uint64(bz[offset : offset+8]))) + h := int64(binary.BigEndian.Uint64(bz[offset : offset+8])) + if h < 0 { + return fmt.Errorf(errNegativeHeightsFmt, h) + } + + pruneSnapshotHeights.PushBack(h) i++ offset += 8 } - if pruneSnapshotHeights.Len() > 0 { - m.mx.Lock() - defer m.mx.Unlock() - m.pruneSnapshotHeights = pruneSnapshotHeights - } + m.mx.Lock() + defer m.mx.Unlock() + m.pruneSnapshotHeights = pruneSnapshotHeights return nil } func (m *Manager) flushPruningHeights(batch dbm.Batch) { - bz := make([]byte, 0) - for _, ph := range m.pruneHeights { + batch.Set(pruneHeightsKey, int64SliceToBytes(m.pruneHeights)) +} + +func (m *Manager) flushPruningSnapshotHeights(batch dbm.Batch) { + m.mx.Lock() + defer m.mx.Unlock() + batch.Set(pruneSnapshotHeightsKey, listToBytes(m.pruneSnapshotHeights)) +} + +// TODO: convert to a generic version with Go 1.18. +func int64SliceToBytes(slice []int64) []byte { + bz := make([]byte, 0, len(slice)*8) + for _, ph := range slice { buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, uint64(ph)) bz = append(bz, buf...) } - - batch.Set([]byte(pruneHeightsKey), bz) + return bz } -func (m *Manager) flushPruningSnapshotHeights(batch dbm.Batch) { - m.mx.Lock() - defer m.mx.Unlock() - bz := make([]byte, 0) - for e := m.pruneSnapshotHeights.Front(); e != nil; e = e.Next() { +func listToBytes(list *list.List) []byte { + bz := make([]byte, 0, list.Len()*8) + for e := list.Front(); e != nil; e = e.Next() { buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, uint64(e.Value.(int64))) bz = append(bz, buf...) } - batch.Set([]byte(pruneSnapshotHeightsKey), bz) + return bz } diff --git a/pruning/manager_test.go b/pruning/manager_test.go index f7cb55becbf3..783a0052c87b 100644 --- a/pruning/manager_test.go +++ b/pruning/manager_test.go @@ -16,7 +16,7 @@ import ( db "github.com/tendermint/tm-db" ) -func Test_NewManager(t *testing.T) { +func TestNewManager(t *testing.T) { manager := pruning.NewManager(log.NewNopLogger()) require.NotNil(t, manager) @@ -24,7 +24,7 @@ func Test_NewManager(t *testing.T) { require.Equal(t, types.PruningNothing, manager.GetOptions().GetPruningStrategy()) } -func Test_Strategies(t *testing.T) { +func TestStrategies(t *testing.T) { testcases := map[string]struct { strategy *types.PruningOptions snapshotInterval uint64 @@ -142,7 +142,7 @@ func Test_Strategies(t *testing.T) { } } -func Test_FlushLoad(t *testing.T) { +func TestFlushLoad(t *testing.T) { manager := pruning.NewManager(log.NewNopLogger()) require.NotNil(t, manager) @@ -196,7 +196,78 @@ func Test_FlushLoad(t *testing.T) { } } -func Test_WithSnapshot(t *testing.T) { +func TestLoadPruningHeights(t *testing.T) { + var ( + manager = pruning.NewManager(log.NewNopLogger()) + err error + ) + require.NotNil(t, manager) + + // must not be PruningNothing + manager.SetOptions(types.NewPruningOptions(types.PruningDefault)) + + testcases := map[string]struct{ + flushedPruningHeights[]int64 + getFlushedPruningSnapshotHeights func () *list.List + expectedResult error + } { + "negative pruningHeight - error": { + flushedPruningHeights: []int64{10, 0, -1}, + expectedResult: fmt.Errorf(pruning.ErrNegativeHeightsFmt, -1), + }, + "negative snapshotPruningHeight - error": { + getFlushedPruningSnapshotHeights: func() *list.List { + l := list.New() + l.PushBack(int64(5)) + l.PushBack(int64(-2)) + l.PushBack(int64(3)) + return l + }, + expectedResult: fmt.Errorf(pruning.ErrNegativeHeightsFmt, -2), + }, + "both have negative - pruningHeight error": { + flushedPruningHeights: []int64{10, 0, -1}, + getFlushedPruningSnapshotHeights: func() *list.List { + l := list.New() + l.PushBack(int64(5)) + l.PushBack(int64(-2)) + l.PushBack(int64(3)) + return l + }, + expectedResult: fmt.Errorf(pruning.ErrNegativeHeightsFmt, -1), + }, + "both non-negative - success": { + flushedPruningHeights: []int64{10, 0, 3}, + getFlushedPruningSnapshotHeights: func() *list.List { + l := list.New() + l.PushBack(int64(5)) + l.PushBack(int64(0)) + l.PushBack(int64(3)) + return l + }, + }, + } + + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + db := db.NewMemDB() + if tc.flushedPruningHeights != nil { + err = db.Set(pruning.PruneHeightsKey, pruning.Int64SliceToBytes(tc.flushedPruningHeights)) + require.NoError(t, err) + } + + if tc.getFlushedPruningSnapshotHeights != nil { + err = db.Set(pruning.PruneSnapshotHeightsKey, pruning.ListToBytes(tc.getFlushedPruningSnapshotHeights())) + require.NoError(t, err) + } + + err = manager.LoadPruningHeights(db) + require.Equal(t, tc.expectedResult, err) + }) + } +} + +func TestWithSnapshot(t *testing.T) { manager := pruning.NewManager(log.NewNopLogger()) require.NotNil(t, manager) @@ -216,6 +287,7 @@ func Test_WithSnapshot(t *testing.T) { snapshotHeightsToPruneMirror := list.New() wg := sync.WaitGroup{} + defer wg.Wait() for curHeight := int64(1); curHeight < 100000; curHeight++ { mx.Lock() @@ -269,6 +341,4 @@ func Test_WithSnapshot(t *testing.T) { }(curHeight) } } - - wg.Wait() } diff --git a/snapshots/manager.go b/snapshots/manager.go index 02e2458df42c..70530ec032d7 100644 --- a/snapshots/manager.go +++ b/snapshots/manager.go @@ -134,12 +134,12 @@ func (m *Manager) endLocked() { m.restoreChunkIndex = 0 } -// GetInterval returns snapshot interval. +// GetInterval returns snapshot interval represented in heights. func (m *Manager) GetInterval() uint64 { return m.opts.Interval } -// GetKeepRecent returns snapshot keep-recent. +// GetKeepRecent returns snapshot keep-recent represented in heights. func (m *Manager) GetKeepRecent() uint32 { return m.opts.KeepRecent } @@ -432,6 +432,11 @@ func (m *Manager) shouldTakeSnapshot(height int64) bool { func (m *Manager) snapshot(height int64) { m.logger.Info("creating state snapshot", "height", height) + if height < 0 { + m.logger.Error("snapshot height must be positive", "height", height) + return + } + snapshot, err := m.Create(uint64(height)) if err != nil { m.logger.Error("failed to create state snapshot", "height", height, "err", err) diff --git a/snapshots/types/options.go b/snapshots/types/options.go index 16b078157b62..c419c019e4e8 100644 --- a/snapshots/types/options.go +++ b/snapshots/types/options.go @@ -6,7 +6,7 @@ type SnapshotOptions struct { // Interval defines at which heights the snapshot is taken. Interval uint64 - // KeepRecent defines how many snapshots to keep. + // KeepRecent defines how many snapshots to keep in heights. KeepRecent uint32 } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 2cd4516181ac..ef58d3b9169e 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -547,12 +547,12 @@ func (rs *Store) GetKVStore(key types.StoreKey) types.KVStore { func (rs *Store) handlePruning(version int64) error { rs.pruningManager.HandleHeight(version - 1) // we should never prune the current version. - if rs.pruningManager.ShouldPruneAtHeight(version) { - rs.logger.Info("prune start", "height", version) - defer rs.logger.Info("prune end", "height", version) - return rs.pruneStores() + if !rs.pruningManager.ShouldPruneAtHeight(version) { + return nil } - return nil + rs.logger.Info("prune start", "height", version) + defer rs.logger.Info("prune end", "height", version) + return rs.pruneStores() } func (rs *Store) pruneStores() error { @@ -566,15 +566,19 @@ func (rs *Store) pruneStores() error { for key, store := range rs.stores { // If the store is wrapped with an inter-block cache, we must first unwrap // it to get the underlying IAVL store. - if store.GetStoreType() == types.StoreTypeIAVL { + if store.GetStoreType() != types.StoreTypeIAVL { + continue + } - store = rs.GetCommitKVStore(key) + store = rs.GetCommitKVStore(key) - if err := store.(*iavl.Store).DeleteVersions(pruningHeights...); err != nil { - if errCause := errors.Cause(err); errCause != nil && errCause != iavltree.ErrVersionDoesNotExist { - return err - } - } + err := store.(*iavl.Store).DeleteVersions(pruningHeights...) + if err == nil { + continue + } + + if errCause := errors.Cause(err); errCause != nil && errCause != iavltree.ErrVersionDoesNotExist { + return err } } rs.pruningManager.ResetPruningHeights() From 8e420a78079545c4630fa776fde558e85e7be763 Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 14:43:45 -0400 Subject: [PATCH 12/58] storetypes --- baseapp/baseapp_test.go | 187 ++++++++++++++++++++-------------------- server/mock/store.go | 48 +++++------ 2 files changed, 117 insertions(+), 118 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 3fc8ce757e5d..30c5b9aa4450 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -24,7 +24,7 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" - storeTypes "github.com/cosmos/cosmos-sdk/store/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil" "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" sdk "github.com/cosmos/cosmos-sdk/types" @@ -59,11 +59,11 @@ type paramStore struct { } type setupConfig struct { - blocks uint64 - blockTxs int - snapshotInterval uint64 + blocks uint64 + blockTxs int + snapshotInterval uint64 snapshotKeepRecent uint32 - pruningOpts *storeTypes.PruningOptions + pruningOpts *storetypes.PruningOptions } func (ps *paramStore) Set(_ sdk.Context, key []byte, value interface{}) { @@ -300,7 +300,7 @@ func TestConsensusParamsNotNil(t *testing.T) { // Test that LoadLatestVersion actually does. func TestLoadVersion(t *testing.T) { logger := defaultLogger() - pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing)) + pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -309,7 +309,7 @@ func TestLoadVersion(t *testing.T) { err := app.LoadLatestVersion() // needed to make stores non-nil require.Nil(t, err) - emptyCommitID := storeTypes.CommitID{} + emptyCommitID := storetypes.CommitID{} // fresh store has zero/empty last commit lastHeight := app.LastBlockHeight() @@ -321,13 +321,13 @@ func TestLoadVersion(t *testing.T) { header := tmproto.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res := app.Commit() - commitID1 := storeTypes.CommitID{Version: 1, Hash: res.Data} + commitID1 := storetypes.CommitID{Version: 1, Hash: res.Data} // execute a block, collect commit ID header = tmproto.Header{Height: 2} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res = app.Commit() - commitID2 := storeTypes.CommitID{Version: 2, Hash: res.Data} + commitID2 := storetypes.CommitID{Version: 2, Hash: res.Data} // reload with LoadLatestVersion app = baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -353,15 +353,15 @@ func useDefaultLoader(app *baseapp.BaseApp) { func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { rs := rootmulti.NewStore(db, log.NewNopLogger()) - rs.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing)) + rs.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing)) key := sdk.NewKVStoreKey(storeKey) - rs.MountStoreWithDB(key, storeTypes.StoreTypeIAVL, nil) + rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() require.Nil(t, err) require.Equal(t, int64(0), rs.LastCommitID().Version) // write some data in substore - kv, _ := rs.GetStore(key).(storeTypes.KVStore) + kv, _ := rs.GetStore(key).(storetypes.KVStore) require.NotNil(t, kv) kv.Set(k, v) commitID := rs.Commit() @@ -370,15 +370,15 @@ func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) { rs := rootmulti.NewStore(db, log.NewNopLogger()) - rs.SetPruning(sdk.NewPruningOptions(storeTypes.PruningDefault)) + rs.SetPruning(sdk.NewPruningOptions(storetypes.PruningDefault)) key := sdk.NewKVStoreKey(storeKey) - rs.MountStoreWithDB(key, storeTypes.StoreTypeIAVL, nil) + rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() require.Nil(t, err) require.Equal(t, ver, rs.LastCommitID().Version) // query data in substore - kv, _ := rs.GetStore(key).(storeTypes.KVStore) + kv, _ := rs.GetStore(key).(storetypes.KVStore) require.NotNil(t, kv) require.Equal(t, v, kv.Get(k)) } @@ -413,7 +413,7 @@ func TestSetLoader(t *testing.T) { initStore(t, db, tc.origStoreKey, k, v) // load the app with the existing db - opts := []func(*baseapp.BaseApp){baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing))} + opts := []func(*baseapp.BaseApp){baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing))} if tc.setLoader != nil { opts = append(opts, tc.setLoader) } @@ -436,7 +436,7 @@ func TestSetLoader(t *testing.T) { func TestVersionSetterGetter(t *testing.T) { logger := defaultLogger() - pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningDefault)) + pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningDefault)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -456,7 +456,7 @@ func TestVersionSetterGetter(t *testing.T) { func TestLoadVersionInvalid(t *testing.T) { logger := log.NewNopLogger() - pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing)) + pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -471,7 +471,7 @@ func TestLoadVersionInvalid(t *testing.T) { header := tmproto.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res := app.Commit() - commitID1 := storeTypes.CommitID{Version: 1, Hash: res.Data} + commitID1 := storetypes.CommitID{Version: 1, Hash: res.Data} // create a new app with the stores mounted under the same cap key app = baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -506,7 +506,7 @@ func TestLoadVersionPruning(t *testing.T) { err = app.LoadLatestVersion() // needed to make stores non-nil require.Nil(t, err) - emptyCommitID := storeTypes.CommitID{} + emptyCommitID := storetypes.CommitID{} // fresh store has zero/empty last commit lastHeight := app.LastBlockHeight() @@ -514,14 +514,14 @@ func TestLoadVersionPruning(t *testing.T) { require.Equal(t, int64(0), lastHeight) require.Equal(t, emptyCommitID, lastID) - var lastCommitID storeTypes.CommitID + var lastCommitID storetypes.CommitID // Commit 15 blocks, of which 15 (latest) is kept in addition to 5-14 inclusive // (keep recent) and 3 (snapshot-interval). for i := int64(1); i <= 15; i++ { app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: i}}) res := app.Commit() - lastCommitID = storeTypes.CommitID{Version: i, Hash: res.Data} + lastCommitID = storetypes.CommitID{Version: i, Hash: res.Data} } for _, v := range []int64{1, 2, 3, 4} { @@ -543,7 +543,7 @@ func TestLoadVersionPruning(t *testing.T) { testLoadVersionHelper(t, app, int64(15), lastCommitID) } -func testLoadVersionHelper(t *testing.T, app *baseapp.BaseApp, expectedHeight int64, expectedID storeTypes.CommitID) { +func testLoadVersionHelper(t *testing.T, app *baseapp.BaseApp, expectedHeight int64, expectedID storetypes.CommitID) { lastHeight := app.LastBlockHeight() lastID := app.LastCommitID() require.Equal(t, expectedHeight, lastHeight) @@ -896,7 +896,7 @@ func testTxDecoder(cdc *codec.LegacyAmino) sdk.TxDecoder { } } -func customHandlerTxTest(t *testing.T, capKey storeTypes.StoreKey, storeKey []byte) handlerFun { +func customHandlerTxTest(t *testing.T, capKey storetypes.StoreKey, storeKey []byte) handlerFun { return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { store := ctx.KVStore(capKey) txTest := tx.(txTest) @@ -927,7 +927,7 @@ func counterEvent(evType string, msgCount int64) sdk.Events { } } -func handlerMsgCounter(t *testing.T, capKey storeTypes.StoreKey, deliverKey []byte) sdk.Handler { +func handlerMsgCounter(t *testing.T, capKey storetypes.StoreKey, deliverKey []byte) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) store := ctx.KVStore(capKey) @@ -1818,7 +1818,6 @@ func TestGRPCQuery(t *testing.T) { require.NoError(t, err) app.GRPCQueryRouter().SetInterfaceRegistry(codectypes.NewInterfaceRegistry()) - app.InitChain(abci.RequestInitChain{}) header := tmproto.Header{Height: app.LastBlockHeight() + 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) @@ -1932,11 +1931,11 @@ func TestGetMaximumBlockGas(t *testing.T) { func TestListSnapshots(t *testing.T) { setupConfig := &setupConfig{ - blocks: 5, - blockTxs: 4, - snapshotInterval: 2, + blocks: 5, + blockTxs: 4, + snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), } app, err := setupBaseAppWithSnapshots(t, setupConfig) @@ -1957,17 +1956,17 @@ func TestListSnapshots(t *testing.T) { func TestSnapshotWithPruning(t *testing.T) { testcases := map[string]struct { - config *setupConfig + config *setupConfig expectedSnapshots []*abci.Snapshot - expectedErr error - } { + expectedErr error + }{ "prune nothing with snapshot": { config: &setupConfig{ - blocks: 20, - blockTxs: 2, - snapshotInterval: 5, + blocks: 20, + blockTxs: 2, + snapshotInterval: 5, snapshotKeepRecent: 1, - pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), }, expectedSnapshots: []*abci.Snapshot{ {Height: 20, Format: 2, Chunks: 5}, @@ -1975,11 +1974,11 @@ func TestSnapshotWithPruning(t *testing.T) { }, "prune everything with snapshot": { config: &setupConfig{ - blocks: 20, - blockTxs: 2, - snapshotInterval: 5, + blocks: 20, + blockTxs: 2, + snapshotInterval: 5, snapshotKeepRecent: 1, - pruningOpts: sdk.NewPruningOptions(storeTypes.PruningEverything), + pruningOpts: sdk.NewPruningOptions(storetypes.PruningEverything), }, expectedSnapshots: []*abci.Snapshot{ {Height: 20, Format: 2, Chunks: 5}, @@ -1987,11 +1986,11 @@ func TestSnapshotWithPruning(t *testing.T) { }, "default pruning with snapshot": { config: &setupConfig{ - blocks: 20, - blockTxs: 2, - snapshotInterval: 5, + blocks: 20, + blockTxs: 2, + snapshotInterval: 5, snapshotKeepRecent: 1, - pruningOpts: sdk.NewPruningOptions(storeTypes.PruningDefault), + pruningOpts: sdk.NewPruningOptions(storetypes.PruningDefault), }, expectedSnapshots: []*abci.Snapshot{ {Height: 20, Format: 2, Chunks: 5}, @@ -1999,11 +1998,11 @@ func TestSnapshotWithPruning(t *testing.T) { }, "custom": { config: &setupConfig{ - blocks: 25, - blockTxs: 2, - snapshotInterval: 5, + blocks: 25, + blockTxs: 2, + snapshotInterval: 5, snapshotKeepRecent: 2, - pruningOpts: sdk.NewCustomPruningOptions(12, 12), + pruningOpts: sdk.NewCustomPruningOptions(12, 12), }, expectedSnapshots: []*abci.Snapshot{ {Height: 25, Format: 2, Chunks: 6}, @@ -2012,20 +2011,20 @@ func TestSnapshotWithPruning(t *testing.T) { }, "no snapshots": { config: &setupConfig{ - blocks: 10, - blockTxs: 2, + blocks: 10, + blockTxs: 2, snapshotInterval: 0, // 0 implies disable snapshots - pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), }, expectedSnapshots: []*abci.Snapshot{}, }, "keep all snapshots": { config: &setupConfig{ - blocks: 10, - blockTxs: 2, - snapshotInterval: 3, + blocks: 10, + blockTxs: 2, + snapshotInterval: 3, snapshotKeepRecent: 0, // 0 implies keep all snapshots - pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), }, expectedSnapshots: []*abci.Snapshot{ {Height: 9, Format: 2, Chunks: 2}, @@ -2058,17 +2057,17 @@ func TestSnapshotWithPruning(t *testing.T) { // Validate that heights were pruned correctly by querying the state at the last height that should be present relative to latest // and the first height that should be pruned. - // + // // Exceptions: // * Prune nothing: should be able to query all heights (we only test first and latest) // * Prune default: should be able to query all heights (we only test first and latest) // * The reason for default behaving this way is that we only commit 20 heights but default has 100_000 keep-recent var lastExistingHeight int64 - if tc.config.pruningOpts.GetPruningStrategy() == storeTypes.PruningNothing || tc.config.pruningOpts.GetPruningStrategy() == storeTypes.PruningDefault { + if tc.config.pruningOpts.GetPruningStrategy() == storetypes.PruningNothing || tc.config.pruningOpts.GetPruningStrategy() == storetypes.PruningDefault { lastExistingHeight = 1 } else { // Integer division rounds down so by multiplying back we get the last height at which we pruned - lastExistingHeight = int64((tc.config.blocks / tc.config.pruningOpts.Interval) * tc.config.pruningOpts.Interval - tc.config.pruningOpts.KeepRecent) + lastExistingHeight = int64((tc.config.blocks/tc.config.pruningOpts.Interval)*tc.config.pruningOpts.Interval - tc.config.pruningOpts.KeepRecent) } // Query 1 @@ -2078,10 +2077,10 @@ func TestSnapshotWithPruning(t *testing.T) { // Query 2 res = app.Query(abci.RequestQuery{Path: fmt.Sprintf("/store/%s/key", capKey2.Name()), Data: []byte("0"), Height: lastExistingHeight - 1}) - require.NotNil(t, res, "height: %d", lastExistingHeight - 1) - if tc.config.pruningOpts.GetPruningStrategy() == storeTypes.PruningNothing || tc.config.pruningOpts.GetPruningStrategy() == storeTypes.PruningDefault { + require.NotNil(t, res, "height: %d", lastExistingHeight-1) + if tc.config.pruningOpts.GetPruningStrategy() == storetypes.PruningNothing || tc.config.pruningOpts.GetPruningStrategy() == storetypes.PruningDefault { // With prune nothing or default, we query height 0 which translates to the latest height. - require.NotNil(t, res.Value, "height: %d", lastExistingHeight - 1) + require.NotNil(t, res.Value, "height: %d", lastExistingHeight-1) } }) } @@ -2089,11 +2088,11 @@ func TestSnapshotWithPruning(t *testing.T) { func TestLoadSnapshotChunk(t *testing.T) { setupConfig := &setupConfig{ - blocks: 2, - blockTxs: 5, - snapshotInterval: 2, + blocks: 2, + blockTxs: 5, + snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), } app, err := setupBaseAppWithSnapshots(t, setupConfig) require.NoError(t, err) @@ -2132,11 +2131,11 @@ func TestLoadSnapshotChunk(t *testing.T) { func TestOfferSnapshot_Errors(t *testing.T) { // Set up app before test cases, since it's fairly expensive. setupConfig := &setupConfig{ - blocks: 0, - blockTxs: 0, - snapshotInterval: 2, + blocks: 0, + blockTxs: 0, + snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), } app, err := setupBaseAppWithSnapshots(t, setupConfig) require.NoError(t, err) @@ -2194,21 +2193,21 @@ func TestOfferSnapshot_Errors(t *testing.T) { func TestApplySnapshotChunk(t *testing.T) { setupConfig1 := &setupConfig{ - blocks: 4, - blockTxs: 10, - snapshotInterval: 2, + blocks: 4, + blockTxs: 10, + snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), } source, err := setupBaseAppWithSnapshots(t, setupConfig1) require.NoError(t, err) setupConfig2 := &setupConfig{ - blocks: 0, - blockTxs: 0, - snapshotInterval: 2, + blocks: 0, + blockTxs: 0, + snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(storeTypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), } target, err := setupBaseAppWithSnapshots(t, setupConfig2) require.NoError(t, err) @@ -2359,41 +2358,41 @@ func TestBaseApp_Init(t *testing.T) { require.NoError(t, err) testCases := map[string]struct { - bapp *baseapp.BaseApp - expectedPruning *storeTypes.PruningOptions + bapp *baseapp.BaseApp + expectedPruning *storetypes.PruningOptions expectedSnapshot *snapshottypes.SnapshotOptions - expectedErr error + expectedErr error }{ "snapshot but no pruning": { baseapp.NewBaseApp(name, logger, db, baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(storeTypes.PruningNothing), + sdk.NewPruningOptions(storetypes.PruningNothing), sdk.NewSnapshotOptions(1500, 2), // if no pruning is set, the default is PruneNothing nil, }, "pruning everything only": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningEverything)), + baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningEverything)), ), - sdk.NewPruningOptions(storeTypes.PruningEverything), + sdk.NewPruningOptions(storetypes.PruningEverything), nil, nil, }, "pruning nothing only": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing)), + baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing)), ), - sdk.NewPruningOptions(storeTypes.PruningNothing), + sdk.NewPruningOptions(storetypes.PruningNothing), nil, nil, }, "pruning default only": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningDefault)), + baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningDefault)), ), - sdk.NewPruningOptions(storeTypes.PruningDefault), + sdk.NewPruningOptions(storetypes.PruningDefault), nil, nil, }, @@ -2407,28 +2406,28 @@ func TestBaseApp_Init(t *testing.T) { }, "pruning everything and snapshots": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningEverything)), + baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningEverything)), baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(storeTypes.PruningEverything), + sdk.NewPruningOptions(storetypes.PruningEverything), sdk.NewSnapshotOptions(1500, 2), nil, }, "pruning nothing and snapshots": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningNothing)), + baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing)), baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(storeTypes.PruningNothing), + sdk.NewPruningOptions(storetypes.PruningNothing), sdk.NewSnapshotOptions(1500, 2), nil, }, "pruning default and snapshots": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storeTypes.PruningDefault)), + baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningDefault)), baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(storeTypes.PruningDefault), + sdk.NewPruningOptions(storetypes.PruningDefault), sdk.NewSnapshotOptions(1500, 2), nil, }, diff --git a/server/mock/store.go b/server/mock/store.go index 2108d8eee072..9e5dcfc2bca2 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -8,14 +8,14 @@ import ( pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" snapshotypes "github.com/cosmos/cosmos-sdk/snapshots/types" - storeTypes "github.com/cosmos/cosmos-sdk/store/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" ) var _ sdk.MultiStore = multiStore{} type multiStore struct { - kv map[storeTypes.StoreKey]kvStore + kv map[storetypes.StoreKey]kvStore } func (ms multiStore) CacheMultiStore() sdk.CacheMultiStore { @@ -26,15 +26,15 @@ func (ms multiStore) CacheMultiStoreWithVersion(_ int64) (sdk.CacheMultiStore, e panic("not implemented") } -func (ms multiStore) CacheWrap() storeTypes.CacheWrap { +func (ms multiStore) CacheWrap() storetypes.CacheWrap { panic("not implemented") } -func (ms multiStore) CacheWrapWithTrace(_ io.Writer, _ sdk.TraceContext) storeTypes.CacheWrap { +func (ms multiStore) CacheWrapWithTrace(_ io.Writer, _ sdk.TraceContext) storetypes.CacheWrap { panic("not implemented") } -func (ms multiStore) CacheWrapWithListeners(_ storeTypes.StoreKey, _ []storeTypes.WriteListener) storeTypes.CacheWrap { +func (ms multiStore) CacheWrapWithListeners(_ storetypes.StoreKey, _ []storetypes.WriteListener) storetypes.CacheWrap { panic("not implemented") } @@ -50,19 +50,19 @@ func (ms multiStore) SetTracer(w io.Writer) sdk.MultiStore { panic("not implemented") } -func (ms multiStore) AddListeners(key storeTypes.StoreKey, listeners []storeTypes.WriteListener) { +func (ms multiStore) AddListeners(key storetypes.StoreKey, listeners []storetypes.WriteListener) { panic("not implemented") } -func (ms multiStore) ListeningEnabled(key storeTypes.StoreKey) bool { +func (ms multiStore) ListeningEnabled(key storetypes.StoreKey) bool { panic("not implemented") } -func (ms multiStore) Commit() storeTypes.CommitID { +func (ms multiStore) Commit() storetypes.CommitID { panic("not implemented") } -func (ms multiStore) LastCommitID() storeTypes.CommitID { +func (ms multiStore) LastCommitID() storetypes.CommitID { panic("not implemented") } @@ -74,19 +74,19 @@ func (ms multiStore) GetPruning() *pruningtypes.PruningOptions { panic("not implemented") } -func (ms multiStore) GetCommitKVStore(key storeTypes.StoreKey) storeTypes.CommitKVStore { +func (ms multiStore) GetCommitKVStore(key storetypes.StoreKey) storetypes.CommitKVStore { panic("not implemented") } -func (ms multiStore) GetCommitStore(key storeTypes.StoreKey) storeTypes.CommitStore { +func (ms multiStore) GetCommitStore(key storetypes.StoreKey) storetypes.CommitStore { panic("not implemented") } -func (ms multiStore) GetCommitKVStores() map[storeTypes.StoreKey]storeTypes.CommitKVStore { +func (ms multiStore) GetCommitKVStores() map[storetypes.StoreKey]storetypes.CommitKVStore { panic("not implemented") } -func (ms multiStore) MountStoreWithDB(key storeTypes.StoreKey, typ storeTypes.StoreType, db dbm.DB) { +func (ms multiStore) MountStoreWithDB(key storetypes.StoreKey, typ storetypes.StoreType, db dbm.DB) { ms.kv[key] = kvStore{store: make(map[string][]byte)} } @@ -94,11 +94,11 @@ func (ms multiStore) LoadLatestVersion() error { return nil } -func (ms multiStore) LoadLatestVersionAndUpgrade(upgrades *storeTypes.StoreUpgrades) error { +func (ms multiStore) LoadLatestVersionAndUpgrade(upgrades *storetypes.StoreUpgrades) error { return nil } -func (ms multiStore) LoadVersionAndUpgrade(ver int64, upgrades *storeTypes.StoreUpgrades) error { +func (ms multiStore) LoadVersionAndUpgrade(ver int64, upgrades *storetypes.StoreUpgrades) error { panic("not implemented") } @@ -106,15 +106,15 @@ func (ms multiStore) LoadVersion(ver int64) error { panic("not implemented") } -func (ms multiStore) GetKVStore(key storeTypes.StoreKey) sdk.KVStore { +func (ms multiStore) GetKVStore(key storetypes.StoreKey) sdk.KVStore { return ms.kv[key] } -func (ms multiStore) GetStore(key storeTypes.StoreKey) sdk.Store { +func (ms multiStore) GetStore(key storetypes.StoreKey) sdk.Store { panic("not implemented") } -func (ms multiStore) GetStoreType() storeTypes.StoreType { +func (ms multiStore) GetStoreType() storetypes.StoreType { panic("not implemented") } @@ -153,19 +153,19 @@ type kvStore struct { store map[string][]byte } -func (kv kvStore) CacheWrap() storeTypes.CacheWrap { +func (kv kvStore) CacheWrap() storetypes.CacheWrap { panic("not implemented") } -func (kv kvStore) CacheWrapWithTrace(w io.Writer, tc sdk.TraceContext) storeTypes.CacheWrap { +func (kv kvStore) CacheWrapWithTrace(w io.Writer, tc sdk.TraceContext) storetypes.CacheWrap { panic("not implemented") } -func (kv kvStore) CacheWrapWithListeners(_ storeTypes.StoreKey, _ []storeTypes.WriteListener) storeTypes.CacheWrap { +func (kv kvStore) CacheWrapWithListeners(_ storetypes.StoreKey, _ []storetypes.WriteListener) storetypes.CacheWrap { panic("not implemented") } -func (kv kvStore) GetStoreType() storeTypes.StoreType { +func (kv kvStore) GetStoreType() storetypes.StoreType { panic("not implemented") } @@ -183,7 +183,7 @@ func (kv kvStore) Has(key []byte) bool { } func (kv kvStore) Set(key, value []byte) { - storeTypes.AssertValidKey(key) + storetypes.AssertValidKey(key) kv.store[string(key)] = value } @@ -216,5 +216,5 @@ func (kv kvStore) ReverseSubspaceIterator(prefix []byte) sdk.Iterator { } func NewCommitMultiStore() sdk.CommitMultiStore { - return multiStore{kv: make(map[storeTypes.StoreKey]kvStore)} + return multiStore{kv: make(map[storetypes.StoreKey]kvStore)} } From 4e66ff36659ec6b2a0e13c7254e5392a97d9ef01 Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 14:49:23 -0400 Subject: [PATCH 13/58] snapshottypes --- baseapp/options.go | 6 +++--- server/mock/store.go | 4 ++-- store/types/store.go | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/baseapp/options.go b/baseapp/options.go index dddff27feaf6..5a4c6a73ee1d 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/snapshots" - snapshotypes "github.com/cosmos/cosmos-sdk/snapshots/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx" @@ -72,7 +72,7 @@ func SetInterBlockCache(cache sdk.MultiStorePersistentCache) func(*BaseApp) { } // SetSnapshot sets the snapshot store. -func SetSnapshot(snapshotStore *snapshots.Store, opts *snapshotypes.SnapshotOptions) func(*BaseApp) { +func SetSnapshot(snapshotStore *snapshots.Store, opts *snapshottypes.SnapshotOptions) func(*BaseApp) { return func(app *BaseApp) { app.SetSnapshot(snapshotStore, opts) } } @@ -194,7 +194,7 @@ func (app *BaseApp) SetStoreLoader(loader StoreLoader) { } // SetSnapshot sets the snapshot store and options. -func (app *BaseApp) SetSnapshot(snapshotStore *snapshots.Store, opts *snapshotypes.SnapshotOptions) { +func (app *BaseApp) SetSnapshot(snapshotStore *snapshots.Store, opts *snapshottypes.SnapshotOptions) { if app.sealed { panic("SetSnapshot() on sealed BaseApp") } diff --git a/server/mock/store.go b/server/mock/store.go index 9e5dcfc2bca2..5de875a83ee6 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -7,7 +7,7 @@ import ( dbm "github.com/tendermint/tm-db" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" - snapshotypes "github.com/cosmos/cosmos-sdk/snapshots/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -143,7 +143,7 @@ func (ms multiStore) Snapshot(height uint64, protoWriter protoio.Writer) error { func (ms multiStore) Restore( height uint64, format uint32, protoReader protoio.Reader, -) (snapshotypes.SnapshotItem, error) { +) (snapshottypes.SnapshotItem, error) { panic("not implemented") } diff --git a/store/types/store.go b/store/types/store.go index f7e86c62d80f..7cf2960e9050 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -9,7 +9,7 @@ import ( dbm "github.com/tendermint/tm-db" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" - snapshotypes "github.com/cosmos/cosmos-sdk/snapshots/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/types/kv" ) @@ -143,7 +143,7 @@ type CacheMultiStore interface { type CommitMultiStore interface { Committer MultiStore - snapshotypes.Snapshotter + snapshottypes.Snapshotter // Mount a store of type using the given db. // If db == nil, the new store will use the CommitMultiStore db. @@ -473,8 +473,8 @@ func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { return pruningtypes.NewCustomPruningOptions(keepRecent, interval) } -type SnapshotOptions = snapshotypes.SnapshotOptions +type SnapshotOptions = snapshottypes.SnapshotOptions func NewSnapshotOptions(interval uint64, keepRecent uint32) *SnapshotOptions { - return snapshotypes.NewSnapshotOptions(interval, keepRecent) + return snapshottypes.NewSnapshotOptions(interval, keepRecent) } From c31438145500c869a2f460d61ecebdf6afc81f47 Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 14:52:32 -0400 Subject: [PATCH 14/58] restore import order in abci_test.go --- baseapp/abci_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 4520fc04e7a0..182c1248a591 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -3,16 +3,16 @@ package baseapp_test import ( "testing" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + tmprototypes "github.com/tendermint/tendermint/proto/tendermint/types" + dbm "github.com/tendermint/tm-db" + "github.com/cosmos/cosmos-sdk/baseapp" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/snapshots" "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - dbm "github.com/tendermint/tm-db" ) func TestGetBlockRentionHeight(t *testing.T) { @@ -111,8 +111,8 @@ func TestGetBlockRentionHeight(t *testing.T) { tc.bapp.SetParamStore(¶mStore{db: dbm.NewMemDB()}) tc.bapp.InitChain(abci.RequestInitChain{ - ConsensusParams: &tmproto.ConsensusParams{ - Evidence: &tmproto.EvidenceParams{ + ConsensusParams: &tmprototypes.ConsensusParams{ + Evidence: &tmprototypes.EvidenceParams{ MaxAgeNumBlocks: tc.maxAgeBlocks, }, }, @@ -136,10 +136,10 @@ func TestBaseAppCreateQueryContext(t *testing.T) { name := t.Name() app := baseapp.NewBaseApp(name, logger, db) - app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 1}}) + app.BeginBlock(abci.RequestBeginBlock{Header: tmprototypes.Header{Height: 1}}) app.Commit() - app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 2}}) + app.BeginBlock(abci.RequestBeginBlock{Header: tmprototypes.Header{Height: 2}}) app.Commit() testCases := []struct { From fff18adbd8c73593dd182bfa82e66e1bc6fddc0b Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 14:58:22 -0400 Subject: [PATCH 15/58] import order in basepp_test.go --- baseapp/baseapp_test.go | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 30c5b9aa4450..38ad9681a6a0 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -13,6 +13,15 @@ import ( "testing" "time" + "github.com/gogo/protobuf/jsonpb" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" + "google.golang.org/protobuf/proto" + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + dbm "github.com/tendermint/tm-db" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/legacy" @@ -20,27 +29,17 @@ import ( "github.com/cosmos/cosmos-sdk/snapshots" "github.com/cosmos/cosmos-sdk/store/rootmulti" "github.com/cosmos/cosmos-sdk/testutil/testdata" - + "github.com/cosmos/cosmos-sdk/types/tx" + "github.com/cosmos/cosmos-sdk/x/auth/middleware" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" codectypes "github.com/cosmos/cosmos-sdk/codec/types" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" storetypes "github.com/cosmos/cosmos-sdk/store/types" - "github.com/cosmos/cosmos-sdk/testutil" - "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/cosmos/cosmos-sdk/x/auth/middleware" - "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" - - "github.com/gogo/protobuf/jsonpb" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - dbm "github.com/tendermint/tm-db" - "google.golang.org/protobuf/proto" ) var ( From 99c303a00d56040cdf2b05f7854267262fb8f6cb Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 15:00:01 -0400 Subject: [PATCH 16/58] import order in baseapp/options.go --- baseapp/options.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseapp/options.go b/baseapp/options.go index 5a4c6a73ee1d..6498281b4b95 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -7,12 +7,12 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec/types" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/snapshots" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) // File for storing in-package BaseApp optional functions, From 64b9f35d9890e14f99e238f8724e51d0a8799c4d Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 15:26:56 -0400 Subject: [PATCH 17/58] import order --- pruning/manager.go | 4 ++-- pruning/manager_test.go | 8 ++++---- server/config/config.go | 2 +- server/pruning.go | 2 +- server/start.go | 31 ++++++++++++++++--------------- snapshots/helpers_test.go | 4 ++-- snapshots/manager.go | 3 ++- store/iavl/store.go | 6 +++--- store/mem/store.go | 2 +- store/rootmulti/dbadapter.go | 3 ++- store/rootmulti/proof_test.go | 2 +- store/rootmulti/store.go | 21 ++++++++++----------- store/rootmulti/store_test.go | 8 ++++---- store/transient/store.go | 2 +- store/transient/store_test.go | 2 +- 15 files changed, 51 insertions(+), 49 deletions(-) diff --git a/pruning/manager.go b/pruning/manager.go index e2fdf4319ccd..8cc66f33c702 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -6,10 +6,10 @@ import ( "fmt" "sync" - "github.com/cosmos/cosmos-sdk/pruning/types" - "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/pruning/types" ) type Manager struct { diff --git a/pruning/manager_test.go b/pruning/manager_test.go index 783a0052c87b..49268c0f2c43 100644 --- a/pruning/manager_test.go +++ b/pruning/manager_test.go @@ -8,12 +8,12 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/pruning" - "github.com/cosmos/cosmos-sdk/pruning/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" db "github.com/tendermint/tm-db" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/pruning" + "github.com/cosmos/cosmos-sdk/pruning/types" ) func TestNewManager(t *testing.T) { diff --git a/server/config/config.go b/server/config/config.go index 2329018f8c04..834cae14becb 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -6,10 +6,10 @@ import ( "github.com/spf13/viper" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) const ( diff --git a/server/pruning.go b/server/pruning.go index ee9c36dcaa39..8cc02b8e4965 100644 --- a/server/pruning.go +++ b/server/pruning.go @@ -6,8 +6,8 @@ import ( "github.com/spf13/cast" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/server/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) // GetPruningOptionsFromFlags parses command flags and returns the correct diff --git a/server/start.go b/server/start.go index 1afee407b563..387a29b7bef0 100644 --- a/server/start.go +++ b/server/start.go @@ -10,28 +10,29 @@ import ( "runtime/pprof" "time" + "github.com/spf13/cobra" + "github.com/tendermint/tendermint/abci/server" + "github.com/tendermint/tendermint/node" + "github.com/tendermint/tendermint/rpc/client/local" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + abciclient "github.com/tendermint/tendermint/abci/client" + tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" + tmos "github.com/tendermint/tendermint/libs/os" + tmservice "github.com/tendermint/tendermint/libs/service" + tmtypes "github.com/tendermint/tendermint/types" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" - servergrpc "github.com/cosmos/cosmos-sdk/server/grpc" "github.com/cosmos/cosmos-sdk/server/rosetta" - crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server" "github.com/cosmos/cosmos-sdk/server/types" - - "github.com/spf13/cobra" - abciclient "github.com/tendermint/tendermint/abci/client" - "github.com/tendermint/tendermint/abci/server" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - tmos "github.com/tendermint/tendermint/libs/os" - tmservice "github.com/tendermint/tendermint/libs/service" - "github.com/tendermint/tendermint/node" - "github.com/tendermint/tendermint/rpc/client/local" - tmtypes "github.com/tendermint/tendermint/types" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" + servergrpc "github.com/cosmos/cosmos-sdk/server/grpc" + crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) const ( diff --git a/snapshots/helpers_test.go b/snapshots/helpers_test.go index d10381bf3315..54866e37865c 100644 --- a/snapshots/helpers_test.go +++ b/snapshots/helpers_test.go @@ -10,14 +10,14 @@ import ( "testing" "time" - protoio "github.com/gogo/protobuf/io" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" db "github.com/tendermint/tm-db" + protoio "github.com/gogo/protobuf/io" "github.com/cosmos/cosmos-sdk/snapshots" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/testutil" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) diff --git a/snapshots/manager.go b/snapshots/manager.go index 70530ec032d7..58e47bc4543b 100644 --- a/snapshots/manager.go +++ b/snapshots/manager.go @@ -10,9 +10,10 @@ import ( "sort" "sync" + "github.com/tendermint/tendermint/libs/log" + "github.com/cosmos/cosmos-sdk/snapshots/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/tendermint/tendermint/libs/log" ) // Manager manages snapshot and restore operations for an app, making sure only a single diff --git a/store/iavl/store.go b/store/iavl/store.go index fdcf3b96eda4..55ccda428eed 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -6,20 +6,20 @@ import ( "io" "time" - ics23 "github.com/confio/ics23/go" "github.com/cosmos/iavl" + ics23 "github.com/confio/ics23/go" abci "github.com/tendermint/tendermint/abci/types" tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" dbm "github.com/tendermint/tm-db" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/telemetry" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/kv" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( diff --git a/store/mem/store.go b/store/mem/store.go index b48a566c853b..6642da5c889a 100644 --- a/store/mem/store.go +++ b/store/mem/store.go @@ -5,12 +5,12 @@ import ( dbm "github.com/tendermint/tm-db" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var ( diff --git a/store/rootmulti/dbadapter.go b/store/rootmulti/dbadapter.go index b862375ae017..102c196e1cf7 100644 --- a/store/rootmulti/dbadapter.go +++ b/store/rootmulti/dbadapter.go @@ -1,9 +1,10 @@ package rootmulti import ( - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/types" + + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var commithash = []byte("FAKE_HASH") diff --git a/store/rootmulti/proof_test.go b/store/rootmulti/proof_test.go index d593732d4c66..3490351efc46 100644 --- a/store/rootmulti/proof_test.go +++ b/store/rootmulti/proof_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/iavl" diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index ef58d3b9169e..5b335d04d78f 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -8,10 +8,15 @@ import ( "strings" "sync" - "github.com/cosmos/cosmos-sdk/pruning" + "github.com/pkg/errors" + "github.com/tendermint/tendermint/libs/log" + abci "github.com/tendermint/tendermint/abci/types" + iavltree "github.com/cosmos/iavl" + protoio "github.com/gogo/protobuf/io" + gogotypes "github.com/gogo/protobuf/types" + dbm "github.com/tendermint/tm-db" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/pruning" "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/iavl" @@ -20,15 +25,9 @@ import ( "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/transient" "github.com/cosmos/cosmos-sdk/store/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - iavltree "github.com/cosmos/iavl" - protoio "github.com/gogo/protobuf/io" - gogotypes "github.com/gogo/protobuf/types" - "github.com/pkg/errors" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" ) const ( diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 4fe61b4b44ef..46f9c48fdd5f 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -7,18 +7,18 @@ import ( "time" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" + abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" - codecTypes "github.com/cosmos/cosmos-sdk/codec/types" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/iavl" - sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps" "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/types" + sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps" + codecTypes "github.com/cosmos/cosmos-sdk/codec/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) diff --git a/store/transient/store.go b/store/transient/store.go index 5c40c3b134f5..703419672ed3 100644 --- a/store/transient/store.go +++ b/store/transient/store.go @@ -3,9 +3,9 @@ package transient import ( dbm "github.com/tendermint/tm-db" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var _ types.Committer = (*Store)(nil) diff --git a/store/transient/store_test.go b/store/transient/store_test.go index 900e6cb7a918..f6c41d75d92c 100644 --- a/store/transient/store_test.go +++ b/store/transient/store_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/require" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/transient" types "github.com/cosmos/cosmos-sdk/store/v2alpha1" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var k, v = []byte("hello"), []byte("world") From 55bac3b0904b04c52a9e3fe562ea10f97023a853 Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 15:41:00 -0400 Subject: [PATCH 18/58] make format on changed files --- baseapp/baseapp_test.go | 20 +++++++-------- baseapp/options.go | 6 ++--- baseapp/util_test.go | 2 +- pruning/export_test.go | 4 +-- pruning/manager_test.go | 48 +++++++++++++++++------------------ pruning/types/options_test.go | 4 +-- server/config/config.go | 2 +- server/pruning.go | 2 +- server/start.go | 16 ++++++------ snapshots/helpers_test.go | 4 +-- snapshots/manager.go | 16 ++++++------ snapshots/manager_test.go | 2 +- store/iavl/store.go | 6 ++--- store/mem/store.go | 2 +- store/rootmulti/proof_test.go | 2 +- store/rootmulti/store.go | 28 ++++++++++---------- store/rootmulti/store_test.go | 8 +++--- store/transient/store.go | 2 +- store/transient/store_test.go | 2 +- store/v2alpha1/mem/store.go | 4 +-- store/v2alpha1/types.go | 18 ++++++------- 21 files changed, 99 insertions(+), 99 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 38ad9681a6a0..40e69667de59 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -16,30 +16,30 @@ import ( "github.com/gogo/protobuf/jsonpb" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" - "google.golang.org/protobuf/proto" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" + "google.golang.org/protobuf/proto" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/legacy" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/snapshots" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store/rootmulti" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/cosmos/cosmos-sdk/x/auth/middleware" - "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil/testdata" "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" - storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx" + "github.com/cosmos/cosmos-sdk/x/auth/middleware" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" ) var ( diff --git a/baseapp/options.go b/baseapp/options.go index 6498281b4b95..5a4c6a73ee1d 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -7,12 +7,12 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/types/tx" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + "github.com/cosmos/cosmos-sdk/snapshots" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx" ) // File for storing in-package BaseApp optional functions, diff --git a/baseapp/util_test.go b/baseapp/util_test.go index c4e5ae5b7199..3a26e5e5a093 100644 --- a/baseapp/util_test.go +++ b/baseapp/util_test.go @@ -1,8 +1,8 @@ package baseapp import ( - "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/snapshots" + "github.com/cosmos/cosmos-sdk/types" ) // TODO: Can be removed once we move all middleware tests into x/auth/middleware diff --git a/pruning/export_test.go b/pruning/export_test.go index c4bc2d432ef2..6a270b46eb82 100644 --- a/pruning/export_test.go +++ b/pruning/export_test.go @@ -3,10 +3,10 @@ package pruning const ErrNegativeHeightsFmt = errNegativeHeightsFmt var ( - PruneHeightsKey = pruneHeightsKey + PruneHeightsKey = pruneHeightsKey PruneSnapshotHeightsKey = pruneSnapshotHeightsKey // functions Int64SliceToBytes = int64SliceToBytes - ListToBytes = listToBytes + ListToBytes = listToBytes ) diff --git a/pruning/manager_test.go b/pruning/manager_test.go index 49268c0f2c43..23ddbce7e366 100644 --- a/pruning/manager_test.go +++ b/pruning/manager_test.go @@ -8,9 +8,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" db "github.com/tendermint/tm-db" - "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/pruning" "github.com/cosmos/cosmos-sdk/pruning/types" @@ -26,50 +26,50 @@ func TestNewManager(t *testing.T) { func TestStrategies(t *testing.T) { testcases := map[string]struct { - strategy *types.PruningOptions + strategy *types.PruningOptions snapshotInterval uint64 strategyToAssert types.PruningStrategy - isValid bool + isValid bool }{ "prune nothing - no snapshot": { - strategy: types.NewPruningOptions(types.PruningNothing), + strategy: types.NewPruningOptions(types.PruningNothing), strategyToAssert: types.PruningNothing, }, "prune nothing - snapshot": { - strategy: types.NewPruningOptions(types.PruningNothing), + strategy: types.NewPruningOptions(types.PruningNothing), strategyToAssert: types.PruningNothing, snapshotInterval: 100, }, "prune default - no snapshot": { - strategy: types.NewPruningOptions(types.PruningDefault), + strategy: types.NewPruningOptions(types.PruningDefault), strategyToAssert: types.PruningDefault, }, "prune default - snapshot": { - strategy: types.NewPruningOptions(types.PruningDefault), + strategy: types.NewPruningOptions(types.PruningDefault), strategyToAssert: types.PruningDefault, snapshotInterval: 100, }, "prune everything - no snapshot": { - strategy: types.NewPruningOptions(types.PruningEverything), + strategy: types.NewPruningOptions(types.PruningEverything), strategyToAssert: types.PruningEverything, }, "prune everything - snapshot": { - strategy: types.NewPruningOptions(types.PruningEverything), + strategy: types.NewPruningOptions(types.PruningEverything), strategyToAssert: types.PruningEverything, snapshotInterval: 100, }, "custom 100-10-15": { - strategy: types.NewCustomPruningOptions(100, 15), + strategy: types.NewCustomPruningOptions(100, 15), snapshotInterval: 10, strategyToAssert: types.PruningCustom, }, "custom 10-10-15": { - strategy: types.NewCustomPruningOptions(10, 15), + strategy: types.NewCustomPruningOptions(10, 15), snapshotInterval: 10, strategyToAssert: types.PruningCustom, }, "custom 100-0-15": { - strategy: types.NewCustomPruningOptions(100, 15), + strategy: types.NewCustomPruningOptions(100, 15), snapshotInterval: 0, strategyToAssert: types.PruningCustom, }, @@ -81,9 +81,9 @@ func TestStrategies(t *testing.T) { for name, tc := range testcases { t.Run(name, func(t *testing.T) { - curStrategy := tc.strategy + curStrategy := tc.strategy manager.SetSnapshotInterval(tc.snapshotInterval) - + pruneStrategy := curStrategy.GetPruningStrategy() require.Equal(t, tc.strategyToAssert, pruneStrategy) @@ -199,21 +199,21 @@ func TestFlushLoad(t *testing.T) { func TestLoadPruningHeights(t *testing.T) { var ( manager = pruning.NewManager(log.NewNopLogger()) - err error + err error ) require.NotNil(t, manager) // must not be PruningNothing manager.SetOptions(types.NewPruningOptions(types.PruningDefault)) - - testcases := map[string]struct{ - flushedPruningHeights[]int64 - getFlushedPruningSnapshotHeights func () *list.List - expectedResult error - } { + + testcases := map[string]struct { + flushedPruningHeights []int64 + getFlushedPruningSnapshotHeights func() *list.List + expectedResult error + }{ "negative pruningHeight - error": { flushedPruningHeights: []int64{10, 0, -1}, - expectedResult: fmt.Errorf(pruning.ErrNegativeHeightsFmt, -1), + expectedResult: fmt.Errorf(pruning.ErrNegativeHeightsFmt, -1), }, "negative snapshotPruningHeight - error": { getFlushedPruningSnapshotHeights: func() *list.List { @@ -260,7 +260,7 @@ func TestLoadPruningHeights(t *testing.T) { err = db.Set(pruning.PruneSnapshotHeightsKey, pruning.ListToBytes(tc.getFlushedPruningSnapshotHeights())) require.NoError(t, err) } - + err = manager.LoadPruningHeights(db) require.Equal(t, tc.expectedResult, err) }) @@ -272,7 +272,7 @@ func TestWithSnapshot(t *testing.T) { require.NotNil(t, manager) curStrategy := types.NewCustomPruningOptions(10, 10) - + snapshotInterval := uint64(15) manager.SetSnapshotInterval(snapshotInterval) diff --git a/pruning/types/options_test.go b/pruning/types/options_test.go index c2d4e93e5ccd..75edb2f6f850 100644 --- a/pruning/types/options_test.go +++ b/pruning/types/options_test.go @@ -8,8 +8,8 @@ import ( func TestPruningOptions_Validate(t *testing.T) { testCases := []struct { - opts *PruningOptions - expectErr error + opts *PruningOptions + expectErr error }{ {NewPruningOptions(PruningDefault), nil}, {NewPruningOptions(PruningEverything), nil}, diff --git a/server/config/config.go b/server/config/config.go index 834cae14becb..2329018f8c04 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -6,10 +6,10 @@ import ( "github.com/spf13/viper" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) const ( diff --git a/server/pruning.go b/server/pruning.go index 8cc02b8e4965..ee9c36dcaa39 100644 --- a/server/pruning.go +++ b/server/pruning.go @@ -6,8 +6,8 @@ import ( "github.com/spf13/cast" - "github.com/cosmos/cosmos-sdk/server/types" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + "github.com/cosmos/cosmos-sdk/server/types" ) // GetPruningOptionsFromFlags parses command flags and returns the correct diff --git a/server/start.go b/server/start.go index 387a29b7bef0..f5cb5cb18bd6 100644 --- a/server/start.go +++ b/server/start.go @@ -11,28 +11,28 @@ import ( "time" "github.com/spf13/cobra" - "github.com/tendermint/tendermint/abci/server" - "github.com/tendermint/tendermint/node" - "github.com/tendermint/tendermint/rpc/client/local" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" abciclient "github.com/tendermint/tendermint/abci/client" + "github.com/tendermint/tendermint/abci/server" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" tmos "github.com/tendermint/tendermint/libs/os" tmservice "github.com/tendermint/tendermint/libs/service" + "github.com/tendermint/tendermint/node" + "github.com/tendermint/tendermint/rpc/client/local" tmtypes "github.com/tendermint/tendermint/types" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" - "github.com/cosmos/cosmos-sdk/server/rosetta" - "github.com/cosmos/cosmos-sdk/server/types" servergrpc "github.com/cosmos/cosmos-sdk/server/grpc" + "github.com/cosmos/cosmos-sdk/server/rosetta" crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + "github.com/cosmos/cosmos-sdk/server/types" ) const ( diff --git a/snapshots/helpers_test.go b/snapshots/helpers_test.go index 54866e37865c..d10381bf3315 100644 --- a/snapshots/helpers_test.go +++ b/snapshots/helpers_test.go @@ -10,14 +10,14 @@ import ( "testing" "time" + protoio "github.com/gogo/protobuf/io" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" db "github.com/tendermint/tm-db" - protoio "github.com/gogo/protobuf/io" "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/cosmos/cosmos-sdk/testutil" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/testutil" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) diff --git a/snapshots/manager.go b/snapshots/manager.go index 58e47bc4543b..b0ddf04bd46b 100644 --- a/snapshots/manager.go +++ b/snapshots/manager.go @@ -3,8 +3,8 @@ package snapshots import ( "bytes" "crypto/sha256" - "fmt" "errors" + "fmt" "io" "math" "sort" @@ -32,11 +32,11 @@ import ( type Manager struct { extensions map[string]types.ExtensionSnapshotter // store is the snapshot store where all completed snapshots are persisted. - store *Store - opts *types.SnapshotOptions + store *Store + opts *types.SnapshotOptions // multistore is the store from which snapshots are taken. multistore types.Snapshotter - logger log.Logger + logger log.Logger mtx sync.Mutex operation operation @@ -74,11 +74,11 @@ var ( func NewManager(store *Store, opts *types.SnapshotOptions, multistore types.Snapshotter, extensions map[string]types.ExtensionSnapshotter, logger log.Logger) *Manager { multistore.SetSnapshotInterval(opts.Interval) return &Manager{ - store: store, - opts: opts, + store: store, + opts: opts, multistore: multistore, extensions: extensions, - logger: logger, + logger: logger, } } @@ -412,7 +412,7 @@ func IsFormatSupported(snapshotter types.ExtensionSnapshotter, format uint32) bo return false } -// SnapshotIfApplicable takes a snapshot of the current state if we are on a snapshot height. +// SnapshotIfApplicable takes a snapshot of the current state if we are on a snapshot height. // It also prunes any old snapshots. The snapshotting and pruning happen in separate goroutines. func (m *Manager) SnapshotIfApplicable(height int64) { if m == nil { diff --git a/snapshots/manager_test.go b/snapshots/manager_test.go index ecaff9578b30..01e654c8bfed 100644 --- a/snapshots/manager_test.go +++ b/snapshots/manager_test.go @@ -64,7 +64,7 @@ func TestManager_Take(t *testing.T) { {7, 8, 9}, } snapshotter := &mockSnapshotter{ - items: items, + items: items, prunedHeights: make(map[int64]struct{}), } expectChunks := snapshotItems(items) diff --git a/store/iavl/store.go b/store/iavl/store.go index 55ccda428eed..fdcf3b96eda4 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -6,20 +6,20 @@ import ( "io" "time" - "github.com/cosmos/iavl" ics23 "github.com/confio/ics23/go" + "github.com/cosmos/iavl" abci "github.com/tendermint/tendermint/abci/types" tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" dbm "github.com/tendermint/tm-db" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/telemetry" - "github.com/cosmos/cosmos-sdk/types/kv" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/kv" ) const ( diff --git a/store/mem/store.go b/store/mem/store.go index 6642da5c889a..b48a566c853b 100644 --- a/store/mem/store.go +++ b/store/mem/store.go @@ -5,12 +5,12 @@ import ( dbm "github.com/tendermint/tm-db" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var ( diff --git a/store/rootmulti/proof_test.go b/store/rootmulti/proof_test.go index 3490351efc46..d593732d4c66 100644 --- a/store/rootmulti/proof_test.go +++ b/store/rootmulti/proof_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/iavl" diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 5b335d04d78f..47409a3fd52d 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -8,15 +8,17 @@ import ( "strings" "sync" - "github.com/pkg/errors" - "github.com/tendermint/tendermint/libs/log" - abci "github.com/tendermint/tendermint/abci/types" iavltree "github.com/cosmos/iavl" protoio "github.com/gogo/protobuf/io" gogotypes "github.com/gogo/protobuf/types" + "github.com/pkg/errors" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/pruning" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/iavl" @@ -25,8 +27,6 @@ import ( "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/transient" "github.com/cosmos/cosmos-sdk/store/types" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -40,7 +40,7 @@ const ( // the CommitMultiStore interface. type Store struct { db dbm.DB - logger log.Logger + logger log.Logger lastCommitInfo *types.CommitInfo pruningManager *pruning.Manager iavlCacheSize int @@ -71,14 +71,14 @@ var ( // LoadVersion must be called. func NewStore(db dbm.DB, logger log.Logger) *Store { return &Store{ - db: db, + db: db, logger: logger, - iavlCacheSize: iavl.DefaultIAVLCacheSize, - storesParams: make(map[types.StoreKey]storeParams), - stores: make(map[types.StoreKey]types.CommitKVStore), - keysByName: make(map[string]types.StoreKey), - listeners: make(map[types.StoreKey][]types.WriteListener), - removalMap: make(map[types.StoreKey]bool), + iavlCacheSize: iavl.DefaultIAVLCacheSize, + storesParams: make(map[types.StoreKey]storeParams), + stores: make(map[types.StoreKey]types.CommitKVStore), + keysByName: make(map[string]types.StoreKey), + listeners: make(map[types.StoreKey][]types.WriteListener), + removalMap: make(map[types.StoreKey]bool), pruningManager: pruning.NewManager(logger), } } @@ -968,7 +968,7 @@ func (rs *Store) flushMetadata(db dbm.DB, version int64, cInfo *types.CommitInfo } else { rs.logger.Debug("commitInfo is nil, not flushed", "height", version) } - + flushLatestVersion(batch, version) rs.pruningManager.FlushPruningHeights(batch) diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 46f9c48fdd5f..4fe61b4b44ef 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -7,18 +7,18 @@ import ( "time" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/libs/log" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/codec" + codecTypes "github.com/cosmos/cosmos-sdk/codec/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/iavl" + sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps" "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/types" - sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps" - codecTypes "github.com/cosmos/cosmos-sdk/codec/types" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) diff --git a/store/transient/store.go b/store/transient/store.go index 703419672ed3..5c40c3b134f5 100644 --- a/store/transient/store.go +++ b/store/transient/store.go @@ -3,9 +3,9 @@ package transient import ( dbm "github.com/tendermint/tm-db" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/types" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var _ types.Committer = (*Store)(nil) diff --git a/store/transient/store_test.go b/store/transient/store_test.go index f6c41d75d92c..900e6cb7a918 100644 --- a/store/transient/store_test.go +++ b/store/transient/store_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/require" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/transient" types "github.com/cosmos/cosmos-sdk/store/v2alpha1" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var k, v = []byte("hello"), []byte("world") diff --git a/store/v2alpha1/mem/store.go b/store/v2alpha1/mem/store.go index 4f9ec299f44e..4ff6396aa92f 100644 --- a/store/v2alpha1/mem/store.go +++ b/store/v2alpha1/mem/store.go @@ -38,7 +38,7 @@ func (s *Store) Commit() (id types.CommitID) { return } -func (s *Store) SetPruning(*types.PruningOptions) {} -func (s *Store) GetPruning() *types.PruningOptions { return &types.PruningOptions{} } +func (s *Store) SetPruning(*types.PruningOptions) {} +func (s *Store) GetPruning() *types.PruningOptions { return &types.PruningOptions{} } func (s Store) LastCommitID() (id types.CommitID) { return } diff --git a/store/v2alpha1/types.go b/store/v2alpha1/types.go index 91f75088d649..3e55f7261927 100644 --- a/store/v2alpha1/types.go +++ b/store/v2alpha1/types.go @@ -9,13 +9,13 @@ import ( // Re-export relevant original store types type ( - StoreKey = v1.StoreKey - StoreType = v1.StoreType - CommitID = v1.CommitID - StoreUpgrades = v1.StoreUpgrades - StoreRename = v1.StoreRename - Iterator = v1.Iterator - PruningOptions = v1.PruningOptions + StoreKey = v1.StoreKey + StoreType = v1.StoreType + CommitID = v1.CommitID + StoreUpgrades = v1.StoreUpgrades + StoreRename = v1.StoreRename + Iterator = v1.Iterator + PruningOptions = v1.PruningOptions PruningStrategy = v1.PruningStrategy TraceContext = v1.TraceContext @@ -116,10 +116,10 @@ type CacheMultiStore interface { // TODO: placeholder. Implement and redefine this type MultiStorePersistentCache = v1.MultiStorePersistentCache -func NewPruningOptions(pruningStrategy PruningStrategy) *PruningOptions { +func NewPruningOptions(pruningStrategy PruningStrategy) *PruningOptions { return v1.NewPruningOptions(pruningStrategy) } -func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { +func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { return v1.NewCustomPruningOptions(keepRecent, interval) } From a54fd344ebb091958d9a8c701b1cb29dfaa434a8 Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 16:28:39 -0400 Subject: [PATCH 19/58] add unit test for NewPruningOptionsFromString --- pruning/types/options_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pruning/types/options_test.go b/pruning/types/options_test.go index 75edb2f6f850..949b01489ae0 100644 --- a/pruning/types/options_test.go +++ b/pruning/types/options_test.go @@ -27,3 +27,20 @@ func TestPruningOptions_Validate(t *testing.T) { require.Equal(t, tc.expectErr, err, "options: %v, err: %s", tc.opts, err) } } + +func TestNewPruningOptionsFromString(t *testing.T) { + testCases := []struct { + optString string + expect *PruningOptions + }{ + {PruningOptionDefault, NewPruningOptions(PruningDefault)}, + {PruningOptionEverything, NewPruningOptions(PruningEverything)}, + {PruningOptionNothing, NewPruningOptions(PruningNothing)}, + {"invalid", NewPruningOptions(PruningDefault)}, + } + + for _, tc := range testCases { + actual := NewPruningOptionsFromString(tc.optString) + require.Equal(t, tc.expect, actual) + } +} From 1751e81e14576ab1135b4b4210d6b0026d5fd872 Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 16:31:38 -0400 Subject: [PATCH 20/58] add TestLoadPruningHeights_PruneNothing --- pruning/manager_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pruning/manager_test.go b/pruning/manager_test.go index 23ddbce7e366..914a717313b9 100644 --- a/pruning/manager_test.go +++ b/pruning/manager_test.go @@ -267,6 +267,15 @@ func TestLoadPruningHeights(t *testing.T) { } } +func TestLoadPruningHeights_PruneNothing(t *testing.T) { + var manager = pruning.NewManager(log.NewNopLogger()) + require.NotNil(t, manager) + + manager.SetOptions(types.NewPruningOptions(types.PruningNothing)) + + require.Nil(t, manager.LoadPruningHeights(db.NewMemDB())) +} + func TestWithSnapshot(t *testing.T) { manager := pruning.NewManager(log.NewNopLogger()) require.NotNil(t, manager) From ecde568d3723dd1391a5b92441ecf0e078cbfc26 Mon Sep 17 00:00:00 2001 From: Roman Date: Fri, 8 Apr 2022 18:15:47 -0400 Subject: [PATCH 21/58] address previousHeight == 0 guard and nits --- pruning/manager.go | 2 +- server/start.go | 1 - store/rootmulti/store.go | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pruning/manager.go b/pruning/manager.go index 8cc66f33c702..37c8788b73d8 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -64,7 +64,7 @@ func (m *Manager) ResetPruningHeights() { // HandleHeight determines if pruneHeight height needs to be kept for pruning at the right interval prescribed by // the pruning strategy. Returns true if the given height was kept to be pruned at the next call to Prune(), false otherwise func (m *Manager) HandleHeight(previousHeight int64) int64 { - if m.opts.GetPruningStrategy() == types.PruningNothing { + if m.opts.GetPruningStrategy() == types.PruningNothing || previousHeight == 0 { return 0 } diff --git a/server/start.go b/server/start.go index f5cb5cb18bd6..63ed31fe82e4 100644 --- a/server/start.go +++ b/server/start.go @@ -25,7 +25,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 47409a3fd52d..dc6a8232fda0 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -943,8 +943,7 @@ func (rs *Store) RollbackToVersion(target int64) int64 { for ; current > target; current-- { rs.pruningManager.HandleHeight(current) } - err := rs.pruneStores() - if err != nil { + if err := rs.pruneStores(); err != nil { panic(err) } From 17bcbbd9b8acd8b5b3ff72514b6077b4bd5819cd Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 9 Apr 2022 12:02:27 -0400 Subject: [PATCH 22/58] fix snapshot height must be positive check --- snapshots/manager.go | 2 +- x/genutil/config/priv_validator_key.json | 11 +++++++++++ x/genutil/data/priv_validator_state.json | 5 +++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 x/genutil/config/priv_validator_key.json create mode 100644 x/genutil/data/priv_validator_state.json diff --git a/snapshots/manager.go b/snapshots/manager.go index b0ddf04bd46b..0defd623bd51 100644 --- a/snapshots/manager.go +++ b/snapshots/manager.go @@ -433,7 +433,7 @@ func (m *Manager) shouldTakeSnapshot(height int64) bool { func (m *Manager) snapshot(height int64) { m.logger.Info("creating state snapshot", "height", height) - if height < 0 { + if height <= 0 { m.logger.Error("snapshot height must be positive", "height", height) return } diff --git a/x/genutil/config/priv_validator_key.json b/x/genutil/config/priv_validator_key.json new file mode 100644 index 000000000000..4f66d79b3376 --- /dev/null +++ b/x/genutil/config/priv_validator_key.json @@ -0,0 +1,11 @@ +{ + "address": "275D129B1E2A5C4063E42C4E7910B11735510B0A", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "7c8cTnfgfhbsr5UZnSxT3IpP70tgHtKFCbKb7B2IKFo=" + }, + "priv_key": { + "type": "tendermint/PrivKeyEd25519", + "value": "3P9fwMdm03oSPwrWGHO240AgqVCPf3rAARgq1MhUSlHtzxxOd+B+FuyvlRmdLFPcik/vS2Ae0oUJspvsHYgoWg==" + } +} \ No newline at end of file diff --git a/x/genutil/data/priv_validator_state.json b/x/genutil/data/priv_validator_state.json new file mode 100644 index 000000000000..48f3b67e3f85 --- /dev/null +++ b/x/genutil/data/priv_validator_state.json @@ -0,0 +1,5 @@ +{ + "height": "0", + "round": 0, + "step": 0 +} \ No newline at end of file From f6462e18292b0cbc1aa56a136f947eb436d01b74 Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 11 Apr 2022 09:42:54 -0400 Subject: [PATCH 23/58] godoc for init --- baseapp/baseapp.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 062b003c57a6..429321f9dcf5 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -295,6 +295,10 @@ func (app *BaseApp) LastBlockHeight() int64 { return app.cms.LastCommitID().Version } +// Init initializes the app. It seals the app, preventing any +// further modifications. In addition, it validates the app against +// the earlier provided settings. Returns an error if validation fails. +// nil otherwise. Panics if the app is already sealed. func (app *BaseApp) Init() error { if app.sealed { panic("cannot call initFromMainStore: baseapp already sealed") From 20e865120ee998c3068602b12760f3092c5343ff Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 11 Apr 2022 16:02:23 -0400 Subject: [PATCH 24/58] return 0 if negative previousVersion is given to the pruning manager.HandleHeight, add unit tests --- pruning/manager.go | 6 +++-- pruning/manager_test.go | 55 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/pruning/manager.go b/pruning/manager.go index 37c8788b73d8..935bb73d2779 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -62,9 +62,11 @@ func (m *Manager) ResetPruningHeights() { } // HandleHeight determines if pruneHeight height needs to be kept for pruning at the right interval prescribed by -// the pruning strategy. Returns true if the given height was kept to be pruned at the next call to Prune(), false otherwise +// the pruning strategy. Returns previousHeight, if it was kept to be pruned at the next call to Prune(), 0 otherwise. +// previousHeight must be greater than 0 for the handling to take effect since valid heights start at 1 and 0 represents +// the latest height. The latest height cannot be pruned. As a result, if previousHeight is less than or equal to 0, 0 is returned. func (m *Manager) HandleHeight(previousHeight int64) int64 { - if m.opts.GetPruningStrategy() == types.PruningNothing || previousHeight == 0 { + if m.opts.GetPruningStrategy() == types.PruningNothing || previousHeight <= 0 { return 0 } diff --git a/pruning/manager_test.go b/pruning/manager_test.go index 914a717313b9..49ca9a35ece5 100644 --- a/pruning/manager_test.go +++ b/pruning/manager_test.go @@ -142,6 +142,61 @@ func TestStrategies(t *testing.T) { } } +func TestHandleHeight_Inputs(t *testing.T) { + var keepRecent int64 = int64(types.NewPruningOptions(types.PruningEverything).KeepRecent) + + testcases := map[string]struct { + height int64 + expectedResult int64 + strategy types.PruningStrategy + expectedHeights []int64 + }{ + "previousHeight is negative - prune everything - invalid previousHeight": { + -1, + 0, + types.PruningEverything, + []int64{}, + }, + "previousHeight is zero - prune everything - invalid previousHeight": { + 0, + 0, + types.PruningEverything, + []int64{}, + }, + "previousHeight is positive but within keep recent- prune everything - not kept": { + keepRecent, + 0, + types.PruningEverything, + []int64{}, + }, + "previousHeight is positive and greater than keep recent - kept": { + keepRecent + 1, + keepRecent + 1 - keepRecent, + types.PruningEverything, + []int64{keepRecent + 1 - keepRecent}, + }, + "pruning nothing, previousHeight is positive and greater than keep recent - not kept": { + keepRecent + 1, + 0, + types.PruningNothing, + []int64{}, + }, + } + + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + manager := pruning.NewManager(log.NewNopLogger()) + require.NotNil(t, manager) + manager.SetOptions(types.NewPruningOptions(tc.strategy)) + + handleHeightActual := manager.HandleHeight(tc.height) + require.Equal(t, tc.expectedResult, handleHeightActual) + + require.Equal(t, tc.expectedHeights, manager.GetPruningHeights()) + }) + } +} + func TestFlushLoad(t *testing.T) { manager := pruning.NewManager(log.NewNopLogger()) require.NotNil(t, manager) From d915e890e35cfd6351950b39f6a4652feb8e14b5 Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 11 Apr 2022 16:12:48 -0400 Subject: [PATCH 25/58] remove GetCommitKVStores --- server/mock/store.go | 4 ---- store/rootmulti/store.go | 5 ----- store/types/store.go | 3 --- 3 files changed, 12 deletions(-) diff --git a/server/mock/store.go b/server/mock/store.go index 5de875a83ee6..abe3e0f45e84 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -82,10 +82,6 @@ func (ms multiStore) GetCommitStore(key storetypes.StoreKey) storetypes.CommitSt panic("not implemented") } -func (ms multiStore) GetCommitKVStores() map[storetypes.StoreKey]storetypes.CommitKVStore { - panic("not implemented") -} - func (ms multiStore) MountStoreWithDB(key storetypes.StoreKey, typ storetypes.StoreType, db dbm.DB) { ms.kv[key] = kvStore{store: make(map[string][]byte)} } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index dc6a8232fda0..25b8933c4a11 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -160,11 +160,6 @@ func (rs *Store) StoreKeysByName() map[string]types.StoreKey { return rs.keysByName } -// GetCommitKVStores get all kv stores associated wit the multistore. -func (rs *Store) GetCommitKVStores() map[types.StoreKey]types.CommitKVStore { - return rs.stores -} - // LoadLatestVersionAndUpgrade implements CommitMultiStore func (rs *Store) LoadLatestVersionAndUpgrade(upgrades *types.StoreUpgrades) error { ver := getLatestVersion(rs.db) diff --git a/store/types/store.go b/store/types/store.go index 7cf2960e9050..6a1d47def98a 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -155,9 +155,6 @@ type CommitMultiStore interface { // Panics on a nil key. GetCommitKVStore(key StoreKey) CommitKVStore - // GetCommitKVStores get all kv stores associated with the multistore. - GetCommitKVStores() map[StoreKey]CommitKVStore - // Load the latest persisted version. Called once after all calls to // Mount*Store() are complete. LoadLatestVersion() error From 2ec8fad8ad2d74ffa9d07011d708e1ac5fd192e2 Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 11 Apr 2022 18:48:15 -0400 Subject: [PATCH 26/58] remove type aliases from store types --- baseapp/baseapp_test.go | 66 +++++++++++++-------------- store/reexport.go | 1 - store/rootmulti/store_test.go | 2 +- store/types/store.go | 35 +------------- store/v2alpha1/mem/store.go | 5 +- store/v2alpha1/multi/snapshot_test.go | 3 +- store/v2alpha1/multi/store.go | 11 +++-- store/v2alpha1/multi/store_test.go | 25 +++++----- store/v2alpha1/transient/store.go | 5 +- store/v2alpha1/types.go | 14 ------ types/store.go | 14 +++--- 11 files changed, 71 insertions(+), 110 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 40e69667de59..e393b34e9f02 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -62,7 +62,7 @@ type setupConfig struct { blockTxs int snapshotInterval uint64 snapshotKeepRecent uint32 - pruningOpts *storetypes.PruningOptions + pruningOpts *pruningtypes.PruningOptions } func (ps *paramStore) Set(_ sdk.Context, key []byte, value interface{}) { @@ -299,7 +299,7 @@ func TestConsensusParamsNotNil(t *testing.T) { // Test that LoadLatestVersion actually does. func TestLoadVersion(t *testing.T) { logger := defaultLogger() - pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing)) + pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -352,7 +352,7 @@ func useDefaultLoader(app *baseapp.BaseApp) { func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { rs := rootmulti.NewStore(db, log.NewNopLogger()) - rs.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing)) + rs.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)) key := sdk.NewKVStoreKey(storeKey) rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() @@ -369,7 +369,7 @@ func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) { rs := rootmulti.NewStore(db, log.NewNopLogger()) - rs.SetPruning(sdk.NewPruningOptions(storetypes.PruningDefault)) + rs.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningDefault)) key := sdk.NewKVStoreKey(storeKey) rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() @@ -412,7 +412,7 @@ func TestSetLoader(t *testing.T) { initStore(t, db, tc.origStoreKey, k, v) // load the app with the existing db - opts := []func(*baseapp.BaseApp){baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing))} + opts := []func(*baseapp.BaseApp){baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing))} if tc.setLoader != nil { opts = append(opts, tc.setLoader) } @@ -435,7 +435,7 @@ func TestSetLoader(t *testing.T) { func TestVersionSetterGetter(t *testing.T) { logger := defaultLogger() - pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningDefault)) + pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningDefault)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -455,7 +455,7 @@ func TestVersionSetterGetter(t *testing.T) { func TestLoadVersionInvalid(t *testing.T) { logger := log.NewNopLogger() - pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing)) + pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -1934,7 +1934,7 @@ func TestListSnapshots(t *testing.T) { blockTxs: 4, snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), } app, err := setupBaseAppWithSnapshots(t, setupConfig) @@ -1965,7 +1965,7 @@ func TestSnapshotWithPruning(t *testing.T) { blockTxs: 2, snapshotInterval: 5, snapshotKeepRecent: 1, - pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), }, expectedSnapshots: []*abci.Snapshot{ {Height: 20, Format: 2, Chunks: 5}, @@ -1977,7 +1977,7 @@ func TestSnapshotWithPruning(t *testing.T) { blockTxs: 2, snapshotInterval: 5, snapshotKeepRecent: 1, - pruningOpts: sdk.NewPruningOptions(storetypes.PruningEverything), + pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningEverything), }, expectedSnapshots: []*abci.Snapshot{ {Height: 20, Format: 2, Chunks: 5}, @@ -1989,7 +1989,7 @@ func TestSnapshotWithPruning(t *testing.T) { blockTxs: 2, snapshotInterval: 5, snapshotKeepRecent: 1, - pruningOpts: sdk.NewPruningOptions(storetypes.PruningDefault), + pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningDefault), }, expectedSnapshots: []*abci.Snapshot{ {Height: 20, Format: 2, Chunks: 5}, @@ -2013,7 +2013,7 @@ func TestSnapshotWithPruning(t *testing.T) { blocks: 10, blockTxs: 2, snapshotInterval: 0, // 0 implies disable snapshots - pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), }, expectedSnapshots: []*abci.Snapshot{}, }, @@ -2023,7 +2023,7 @@ func TestSnapshotWithPruning(t *testing.T) { blockTxs: 2, snapshotInterval: 3, snapshotKeepRecent: 0, // 0 implies keep all snapshots - pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), }, expectedSnapshots: []*abci.Snapshot{ {Height: 9, Format: 2, Chunks: 2}, @@ -2062,7 +2062,7 @@ func TestSnapshotWithPruning(t *testing.T) { // * Prune default: should be able to query all heights (we only test first and latest) // * The reason for default behaving this way is that we only commit 20 heights but default has 100_000 keep-recent var lastExistingHeight int64 - if tc.config.pruningOpts.GetPruningStrategy() == storetypes.PruningNothing || tc.config.pruningOpts.GetPruningStrategy() == storetypes.PruningDefault { + if tc.config.pruningOpts.GetPruningStrategy() == pruningtypes.PruningNothing || tc.config.pruningOpts.GetPruningStrategy() == pruningtypes.PruningDefault { lastExistingHeight = 1 } else { // Integer division rounds down so by multiplying back we get the last height at which we pruned @@ -2077,7 +2077,7 @@ func TestSnapshotWithPruning(t *testing.T) { // Query 2 res = app.Query(abci.RequestQuery{Path: fmt.Sprintf("/store/%s/key", capKey2.Name()), Data: []byte("0"), Height: lastExistingHeight - 1}) require.NotNil(t, res, "height: %d", lastExistingHeight-1) - if tc.config.pruningOpts.GetPruningStrategy() == storetypes.PruningNothing || tc.config.pruningOpts.GetPruningStrategy() == storetypes.PruningDefault { + if tc.config.pruningOpts.GetPruningStrategy() == pruningtypes.PruningNothing || tc.config.pruningOpts.GetPruningStrategy() == pruningtypes.PruningDefault { // With prune nothing or default, we query height 0 which translates to the latest height. require.NotNil(t, res.Value, "height: %d", lastExistingHeight-1) } @@ -2091,7 +2091,7 @@ func TestLoadSnapshotChunk(t *testing.T) { blockTxs: 5, snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), } app, err := setupBaseAppWithSnapshots(t, setupConfig) require.NoError(t, err) @@ -2134,7 +2134,7 @@ func TestOfferSnapshot_Errors(t *testing.T) { blockTxs: 0, snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), } app, err := setupBaseAppWithSnapshots(t, setupConfig) require.NoError(t, err) @@ -2196,7 +2196,7 @@ func TestApplySnapshotChunk(t *testing.T) { blockTxs: 10, snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), } source, err := setupBaseAppWithSnapshots(t, setupConfig1) require.NoError(t, err) @@ -2206,7 +2206,7 @@ func TestApplySnapshotChunk(t *testing.T) { blockTxs: 0, snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(storetypes.PruningNothing), + pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), } target, err := setupBaseAppWithSnapshots(t, setupConfig2) require.NoError(t, err) @@ -2358,7 +2358,7 @@ func TestBaseApp_Init(t *testing.T) { testCases := map[string]struct { bapp *baseapp.BaseApp - expectedPruning *storetypes.PruningOptions + expectedPruning *pruningtypes.PruningOptions expectedSnapshot *snapshottypes.SnapshotOptions expectedErr error }{ @@ -2366,32 +2366,32 @@ func TestBaseApp_Init(t *testing.T) { baseapp.NewBaseApp(name, logger, db, baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(storetypes.PruningNothing), + sdk.NewPruningOptions(pruningtypes.PruningNothing), sdk.NewSnapshotOptions(1500, 2), // if no pruning is set, the default is PruneNothing nil, }, "pruning everything only": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningEverything)), + baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningEverything)), ), - sdk.NewPruningOptions(storetypes.PruningEverything), + sdk.NewPruningOptions(pruningtypes.PruningEverything), nil, nil, }, "pruning nothing only": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing)), + baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)), ), - sdk.NewPruningOptions(storetypes.PruningNothing), + sdk.NewPruningOptions(pruningtypes.PruningNothing), nil, nil, }, "pruning default only": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningDefault)), + baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningDefault)), ), - sdk.NewPruningOptions(storetypes.PruningDefault), + sdk.NewPruningOptions(pruningtypes.PruningDefault), nil, nil, }, @@ -2405,28 +2405,28 @@ func TestBaseApp_Init(t *testing.T) { }, "pruning everything and snapshots": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningEverything)), + baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningEverything)), baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(storetypes.PruningEverything), + sdk.NewPruningOptions(pruningtypes.PruningEverything), sdk.NewSnapshotOptions(1500, 2), nil, }, "pruning nothing and snapshots": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningNothing)), + baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)), baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(storetypes.PruningNothing), + sdk.NewPruningOptions(pruningtypes.PruningNothing), sdk.NewSnapshotOptions(1500, 2), nil, }, "pruning default and snapshots": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(storetypes.PruningDefault)), + baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningDefault)), baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(storetypes.PruningDefault), + sdk.NewPruningOptions(pruningtypes.PruningDefault), sdk.NewSnapshotOptions(1500, 2), nil, }, diff --git a/store/reexport.go b/store/reexport.go index 8a365ab758fd..5b101b4ac30f 100644 --- a/store/reexport.go +++ b/store/reexport.go @@ -6,7 +6,6 @@ import ( // Import cosmos-sdk/types/store.go for convenience. type ( - PruningOptions = types.PruningOptions Store = types.Store Committer = types.Committer CommitStore = types.CommitStore diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 4fe61b4b44ef..bba5776cd9af 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -685,7 +685,7 @@ func TestCacheWraps(t *testing.T) { func TestTraceConcurrency(t *testing.T) { db := dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, types.NewPruningOptions(types.PruningNothing)) + multi := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err := multi.LoadLatestVersion() require.NoError(t, err) diff --git a/store/types/store.go b/store/types/store.go index 6a1d47def98a..2f26a1029806 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -23,8 +23,8 @@ type Committer interface { Commit() CommitID LastCommitID() CommitID - SetPruning(*PruningOptions) - GetPruning() *PruningOptions + SetPruning(*pruningtypes.PruningOptions) + GetPruning() *pruningtypes.PruningOptions } // Stores of MultiStore must implement CommitStore. @@ -444,34 +444,3 @@ type StoreWithInitialVersion interface { // starting a new chain at an arbitrary height. SetInitialVersion(version int64) } - -type ( - PruningOptions = pruningtypes.PruningOptions - PruningStrategy = pruningtypes.PruningStrategy -) - -const ( - PruningOptionDefault = pruningtypes.PruningOptionDefault - PruningOptionEverything = pruningtypes.PruningOptionEverything - PruningOptionNothing = pruningtypes.PruningOptionNothing - PruningOptionCustom = pruningtypes.PruningOptionCustom - - PruningDefault = pruningtypes.PruningDefault - PruningEverything = pruningtypes.PruningEverything - PruningNothing = pruningtypes.PruningNothing - PruningCustom = pruningtypes.PruningCustom -) - -func NewPruningOptions(pruningStrategy PruningStrategy) *PruningOptions { - return pruningtypes.NewPruningOptions(pruningStrategy) -} - -func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { - return pruningtypes.NewCustomPruningOptions(keepRecent, interval) -} - -type SnapshotOptions = snapshottypes.SnapshotOptions - -func NewSnapshotOptions(interval uint64, keepRecent uint32) *SnapshotOptions { - return snapshottypes.NewSnapshotOptions(interval, keepRecent) -} diff --git a/store/v2alpha1/mem/store.go b/store/v2alpha1/mem/store.go index 4ff6396aa92f..32e31e7b42ad 100644 --- a/store/v2alpha1/mem/store.go +++ b/store/v2alpha1/mem/store.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/db/memdb" "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/store/v2alpha1/dbadapter" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var ( @@ -38,7 +39,7 @@ func (s *Store) Commit() (id types.CommitID) { return } -func (s *Store) SetPruning(*types.PruningOptions) {} -func (s *Store) GetPruning() *types.PruningOptions { return &types.PruningOptions{} } +func (s *Store) SetPruning(*pruningtypes.PruningOptions) {} +func (s *Store) GetPruning() *pruningtypes.PruningOptions { return &pruningtypes.PruningOptions{} } func (s Store) LastCommitID() (id types.CommitID) { return } diff --git a/store/v2alpha1/multi/snapshot_test.go b/store/v2alpha1/multi/snapshot_test.go index 6242928c0c01..48b8b4160875 100644 --- a/store/v2alpha1/multi/snapshot_test.go +++ b/store/v2alpha1/multi/snapshot_test.go @@ -19,12 +19,13 @@ import ( "github.com/cosmos/cosmos-sdk/db/memdb" "github.com/cosmos/cosmos-sdk/snapshots" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/types" ) func multiStoreConfig(t *testing.T, stores int) StoreConfig { opts := DefaultStoreConfig() - opts.Pruning = types.NewPruningOptions(types.PruningNothing) + opts.Pruning = pruningtypes.NewPruningOptions(pruningtypes.PruningNothing) for i := 0; i < stores; i++ { sKey := types.NewKVStoreKey(fmt.Sprintf("store%d", i)) diff --git a/store/v2alpha1/multi/store.go b/store/v2alpha1/multi/store.go index e50022e8b984..736c2c32f3fe 100644 --- a/store/v2alpha1/multi/store.go +++ b/store/v2alpha1/multi/store.go @@ -22,6 +22,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/v2alpha1/smt" "github.com/cosmos/cosmos-sdk/store/v2alpha1/transient" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/types/kv" ) @@ -56,7 +57,7 @@ func ErrStoreNotFound(skey string) error { // StoreConfig is used to define a schema and other options and pass them to the MultiStore constructor. type StoreConfig struct { // Version pruning options for backing DBs. - Pruning *types.PruningOptions + Pruning *pruningtypes.PruningOptions // The minimum allowed version number. InitialVersion uint64 // The backing DB to use for the state commitment Merkle tree data. @@ -92,7 +93,7 @@ type Store struct { mtx sync.RWMutex // Copied from StoreConfig - Pruning *types.PruningOptions + Pruning *pruningtypes.PruningOptions InitialVersion uint64 // if *traceListenMixin @@ -152,7 +153,7 @@ func newTraceListenMixin() *traceListenMixin { // pruning with PruneDefault, no listeners and no tracer. func DefaultStoreConfig() StoreConfig { return StoreConfig{ - Pruning: types.NewPruningOptions(types.PruneDefault), + Pruning: pruningtypes.NewPruningOptions(pruningtypes.PruningDefault), prefixRegistry: prefixRegistry{ StoreSchema: StoreSchema{}, }, @@ -908,5 +909,5 @@ func (tlm *traceListenMixin) wrapTraceListen(store types.KVStore, skey types.Sto return store } -func (s *Store) GetPruning() *types.PruningOptions { return s.Pruning } -func (s *Store) SetPruning(po *types.PruningOptions) { s.Pruning = po } +func (s *Store) GetPruning() *pruningtypes.PruningOptions { return s.Pruning } +func (s *Store) SetPruning(po *pruningtypes.PruningOptions) { s.Pruning = po } diff --git a/store/v2alpha1/multi/store_test.go b/store/v2alpha1/multi/store_test.go index f03f5b9f5d25..094dd8762549 100644 --- a/store/v2alpha1/multi/store_test.go +++ b/store/v2alpha1/multi/store_test.go @@ -14,6 +14,7 @@ import ( dbm "github.com/cosmos/cosmos-sdk/db" "github.com/cosmos/cosmos-sdk/db/memdb" types "github.com/cosmos/cosmos-sdk/store/v2alpha1" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/types/kv" ) @@ -39,7 +40,7 @@ func simpleStoreConfig(t *testing.T) StoreConfig { func storeConfig123(t *testing.T) StoreConfig { opts := DefaultStoreConfig() - opts.Pruning = types.NewPruningOptions(types.PruneNothing) + opts.Pruning = pruningtypes.NewPruningOptions(pruningtypes.PruningNothing) require.NoError(t, opts.RegisterSubstore(skey_1.Name(), types.StoreTypePersistent)) require.NoError(t, opts.RegisterSubstore(skey_2.Name(), types.StoreTypePersistent)) require.NoError(t, opts.RegisterSubstore(skey_3.Name(), types.StoreTypePersistent)) @@ -100,7 +101,7 @@ func TestConstructors(t *testing.T) { require.NoError(t, store.Close()) t.Run("fail to load if InitialVersion > lowest existing version", func(t *testing.T) { - opts := StoreConfig{InitialVersion: 5, Pruning: types.NewPruningOptions(types.PruneNothing)} + opts := StoreConfig{InitialVersion: 5, Pruning: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)} store, err = NewStore(db, opts) require.Error(t, err) db.Close() @@ -246,7 +247,7 @@ func TestCommit(t *testing.T) { } } basicOpts := simpleStoreConfig(t) - basicOpts.Pruning = types.NewPruningOptions(types.PruneNothing) + basicOpts.Pruning = pruningtypes.NewPruningOptions(pruningtypes.PruningNothing) t.Run("sanity tests for Merkle hashing", func(t *testing.T) { testBasic(basicOpts) }) @@ -285,7 +286,7 @@ func TestCommit(t *testing.T) { } opts := simpleStoreConfig(t) - opts.Pruning = types.NewPruningOptions(types.PruneNothing) + opts.Pruning = pruningtypes.NewPruningOptions(pruningtypes.PruningNothing) // Ensure Store's commit is rolled back in each failure case... t.Run("recover after failed Commit", func(t *testing.T) { @@ -348,7 +349,7 @@ func TestCommit(t *testing.T) { t.Run("height overflow triggers failure", func(t *testing.T) { opts.StateCommitmentDB = nil opts.InitialVersion = math.MaxInt64 - opts.Pruning = types.NewPruningOptions(types.PruneNothing) + opts.Pruning = pruningtypes.NewPruningOptions(pruningtypes.PruningNothing) store, err := NewStore(memdb.NewDB(), opts) require.NoError(t, err) require.Equal(t, int64(math.MaxInt64), store.Commit().Version) @@ -359,7 +360,7 @@ func TestCommit(t *testing.T) { t.Run("first commit version matches InitialVersion", func(t *testing.T) { opts = simpleStoreConfig(t) opts.InitialVersion = 5 - opts.Pruning = types.NewPruningOptions(types.PruneNothing) + opts.Pruning = pruningtypes.NewPruningOptions(pruningtypes.PruningNothing) opts.StateCommitmentDB = memdb.NewDB() store, err := NewStore(memdb.NewDB(), opts) require.NoError(t, err) @@ -394,13 +395,13 @@ func sliceToSet(slice []uint64) map[uint64]struct{} { func TestPruning(t *testing.T) { // Save versions up to 10 and verify pruning at final commit testCases := []struct { - *types.PruningOptions + *pruningtypes.PruningOptions kept []uint64 }{ - {types.NewCustomPruningOptions(2, 10), []uint64{8, 9, 10}}, - {types.NewCustomPruningOptions(0, 10), []uint64{10}}, - {types.NewPruningOptions(types.PruneEverything), []uint64{8, 9, 10}}, - {types.NewPruningOptions(types.PruneNothing), []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, + {pruningtypes.NewCustomPruningOptions(2, 10), []uint64{8, 9, 10}}, + {pruningtypes.NewCustomPruningOptions(0, 10), []uint64{10}}, + {pruningtypes.NewPruningOptions(pruningtypes.PruningEverything), []uint64{8, 9, 10}}, + {pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, } for tci, tc := range testCases { @@ -442,7 +443,7 @@ func TestPruning(t *testing.T) { db := memdb.NewDB() opts := simpleStoreConfig(t) - opts.Pruning = types.NewCustomPruningOptions(0, 10) + opts.Pruning = pruningtypes.NewCustomPruningOptions(0, 10) store, err := NewStore(db, opts) require.NoError(t, err) diff --git a/store/v2alpha1/transient/store.go b/store/v2alpha1/transient/store.go index d62956368e44..596af3f16a2c 100644 --- a/store/v2alpha1/transient/store.go +++ b/store/v2alpha1/transient/store.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/db/memdb" "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/store/v2alpha1/dbadapter" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var ( @@ -40,7 +41,7 @@ func (ts *Store) Commit() (id types.CommitID) { return } -func (ts *Store) SetPruning(*types.PruningOptions) {} -func (ts *Store) GetPruning() *types.PruningOptions { return &types.PruningOptions{} } +func (ts *Store) SetPruning(*pruningtypes.PruningOptions) {} +func (ts *Store) GetPruning() *pruningtypes.PruningOptions { return &pruningtypes.PruningOptions{} } func (ts *Store) LastCommitID() (id types.CommitID) { return } diff --git a/store/v2alpha1/types.go b/store/v2alpha1/types.go index 3e55f7261927..176e314c5a8f 100644 --- a/store/v2alpha1/types.go +++ b/store/v2alpha1/types.go @@ -15,8 +15,6 @@ type ( StoreUpgrades = v1.StoreUpgrades StoreRename = v1.StoreRename Iterator = v1.Iterator - PruningOptions = v1.PruningOptions - PruningStrategy = v1.PruningStrategy TraceContext = v1.TraceContext WriteListener = v1.WriteListener @@ -47,10 +45,6 @@ const ( ) var ( - PruneDefault = v1.PruningDefault - PruneEverything = v1.PruningEverything - PruneNothing = v1.PruningNothing - NewKVStoreKey = v1.NewKVStoreKey PrefixEndBytes = v1.PrefixEndBytes KVStorePrefixIterator = v1.KVStorePrefixIterator @@ -115,11 +109,3 @@ type CacheMultiStore interface { // MultiStorePersistentCache provides inter-block (persistent) caching capabilities for a CommitMultiStore. // TODO: placeholder. Implement and redefine this type MultiStorePersistentCache = v1.MultiStorePersistentCache - -func NewPruningOptions(pruningStrategy PruningStrategy) *PruningOptions { - return v1.NewPruningOptions(pruningStrategy) -} - -func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { - return v1.NewCustomPruningOptions(keepRecent, interval) -} diff --git a/types/store.go b/types/store.go index a9604da8baa2..ff2b6b4b280b 100644 --- a/types/store.go +++ b/types/store.go @@ -6,6 +6,8 @@ import ( "strings" "github.com/cosmos/cosmos-sdk/store/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/types/kv" ) @@ -164,14 +166,14 @@ func NewInfiniteGasMeter() GasMeter { return types.NewInfiniteGasMeter() } -func NewSnapshotOptions(interval uint64, keepRecent uint32) *types.SnapshotOptions { - return types.NewSnapshotOptions(interval, keepRecent) +func NewSnapshotOptions(interval uint64, keepRecent uint32) *snapshottypes.SnapshotOptions { + return snapshottypes.NewSnapshotOptions(interval, keepRecent) } -func NewPruningOptions(pruningStrategy types.PruningStrategy) *types.PruningOptions { - return types.NewPruningOptions(pruningStrategy) +func NewPruningOptions(pruningStrategy pruningtypes.PruningStrategy) *pruningtypes.PruningOptions { + return pruningtypes.NewPruningOptions(pruningStrategy) } -func NewCustomPruningOptions(keepRecent, interval uint64) *types.PruningOptions { - return types.NewCustomPruningOptions(keepRecent, interval) +func NewCustomPruningOptions(keepRecent, interval uint64) *pruningtypes.PruningOptions { + return pruningtypes.NewCustomPruningOptions(keepRecent, interval) } From 950ab26ce3e3d0229d8d3c3ae1bcaf83ca74b92d Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 11 Apr 2022 19:26:46 -0400 Subject: [PATCH 27/58] revert pruning options pointer --- baseapp/baseapp_test.go | 4 ++-- baseapp/options.go | 2 +- pruning/manager.go | 6 +++--- pruning/manager_test.go | 2 +- pruning/types/options.go | 18 +++++++++--------- pruning/types/options_test.go | 4 ++-- server/mock/store.go | 4 ++-- server/pruning.go | 4 ++-- server/pruning_test.go | 2 +- store/iavl/store.go | 4 ++-- store/mem/store.go | 4 ++-- store/rootmulti/dbadapter.go | 4 ++-- store/rootmulti/store.go | 4 ++-- store/rootmulti/store_test.go | 6 +++--- store/transient/store.go | 4 ++-- store/types/store.go | 4 ++-- store/v2alpha1/mem/store.go | 4 ++-- store/v2alpha1/multi/store.go | 8 ++++---- store/v2alpha1/multi/store_test.go | 2 +- store/v2alpha1/transient/store.go | 4 ++-- types/store.go | 4 ++-- 21 files changed, 49 insertions(+), 49 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index e393b34e9f02..74b33cb50ba6 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -62,7 +62,7 @@ type setupConfig struct { blockTxs int snapshotInterval uint64 snapshotKeepRecent uint32 - pruningOpts *pruningtypes.PruningOptions + pruningOpts pruningtypes.PruningOptions } func (ps *paramStore) Set(_ sdk.Context, key []byte, value interface{}) { @@ -2358,7 +2358,7 @@ func TestBaseApp_Init(t *testing.T) { testCases := map[string]struct { bapp *baseapp.BaseApp - expectedPruning *pruningtypes.PruningOptions + expectedPruning pruningtypes.PruningOptions expectedSnapshot *snapshottypes.SnapshotOptions expectedErr error }{ diff --git a/baseapp/options.go b/baseapp/options.go index 5a4c6a73ee1d..90b59ed13827 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -19,7 +19,7 @@ import ( // for options that need access to non-exported fields of the BaseApp // SetPruning sets a pruning option on the multistore associated with the app -func SetPruning(opts *pruningtypes.PruningOptions) func(*BaseApp) { +func SetPruning(opts pruningtypes.PruningOptions) func(*BaseApp) { return func(bapp *BaseApp) { bapp.cms.SetPruning(opts) } } diff --git a/pruning/manager.go b/pruning/manager.go index 935bb73d2779..2b4b6309b85b 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -14,7 +14,7 @@ import ( type Manager struct { logger log.Logger - opts *types.PruningOptions + opts types.PruningOptions snapshotInterval uint64 pruneHeights []int64 pruneSnapshotHeights *list.List @@ -41,12 +41,12 @@ func NewManager(logger log.Logger) *Manager { } // SetOptions sets the pruning strategy on the manager. -func (m *Manager) SetOptions(opts *types.PruningOptions) { +func (m *Manager) SetOptions(opts types.PruningOptions) { m.opts = opts } // GetOptions fetches the pruning strategy from the manager. -func (m *Manager) GetOptions() *types.PruningOptions { +func (m *Manager) GetOptions() types.PruningOptions { return m.opts } diff --git a/pruning/manager_test.go b/pruning/manager_test.go index 49ca9a35ece5..e6a696b7f025 100644 --- a/pruning/manager_test.go +++ b/pruning/manager_test.go @@ -26,7 +26,7 @@ func TestNewManager(t *testing.T) { func TestStrategies(t *testing.T) { testcases := map[string]struct { - strategy *types.PruningOptions + strategy types.PruningOptions snapshotInterval uint64 strategyToAssert types.PruningStrategy isValid bool diff --git a/pruning/types/options.go b/pruning/types/options.go index bfb1dc814184..a8479e97ffc5 100644 --- a/pruning/types/options.go +++ b/pruning/types/options.go @@ -58,39 +58,39 @@ var ( ErrPruningKeepRecentTooSmall = fmt.Errorf("'pruning-keep-recent' must not be less than %d. For the most aggressive pruning, select pruning = \"everything\"", pruneEverythingKeepRecent) ) -func NewPruningOptions(pruningStrategy PruningStrategy) *PruningOptions { +func NewPruningOptions(pruningStrategy PruningStrategy) PruningOptions { switch pruningStrategy { case PruningDefault: - return &PruningOptions{ + return PruningOptions{ KeepRecent: 362880, Interval: 10, Strategy: PruningDefault, } case PruningEverything: - return &PruningOptions{ + return PruningOptions{ KeepRecent: pruneEverythingKeepRecent, Interval: pruneEverythingInterval, Strategy: PruningEverything, } case PruningNothing: - return &PruningOptions{ + return PruningOptions{ KeepRecent: 0, Interval: 0, Strategy: PruningNothing, } case PruningCustom: - return &PruningOptions{ + return PruningOptions{ Strategy: PruningCustom, } default: - return &PruningOptions{ + return PruningOptions{ Strategy: PruningUndefined, } } } -func NewCustomPruningOptions(keepRecent, interval uint64) *PruningOptions { - return &PruningOptions{ +func NewCustomPruningOptions(keepRecent, interval uint64) PruningOptions { + return PruningOptions{ KeepRecent: keepRecent, Interval: interval, Strategy: PruningCustom, @@ -117,7 +117,7 @@ func (po PruningOptions) Validate() error { return nil } -func NewPruningOptionsFromString(strategy string) *PruningOptions { +func NewPruningOptionsFromString(strategy string) PruningOptions { switch strategy { case PruningOptionEverything: return NewPruningOptions(PruningEverything) diff --git a/pruning/types/options_test.go b/pruning/types/options_test.go index 949b01489ae0..6fb0dbf8da59 100644 --- a/pruning/types/options_test.go +++ b/pruning/types/options_test.go @@ -8,7 +8,7 @@ import ( func TestPruningOptions_Validate(t *testing.T) { testCases := []struct { - opts *PruningOptions + opts PruningOptions expectErr error }{ {NewPruningOptions(PruningDefault), nil}, @@ -31,7 +31,7 @@ func TestPruningOptions_Validate(t *testing.T) { func TestNewPruningOptionsFromString(t *testing.T) { testCases := []struct { optString string - expect *PruningOptions + expect PruningOptions }{ {PruningOptionDefault, NewPruningOptions(PruningDefault)}, {PruningOptionEverything, NewPruningOptions(PruningEverything)}, diff --git a/server/mock/store.go b/server/mock/store.go index abe3e0f45e84..745ea44e49dc 100644 --- a/server/mock/store.go +++ b/server/mock/store.go @@ -66,11 +66,11 @@ func (ms multiStore) LastCommitID() storetypes.CommitID { panic("not implemented") } -func (ms multiStore) SetPruning(opts *pruningtypes.PruningOptions) { +func (ms multiStore) SetPruning(opts pruningtypes.PruningOptions) { panic("not implemented") } -func (ms multiStore) GetPruning() *pruningtypes.PruningOptions { +func (ms multiStore) GetPruning() pruningtypes.PruningOptions { panic("not implemented") } diff --git a/server/pruning.go b/server/pruning.go index ee9c36dcaa39..2e21579032c1 100644 --- a/server/pruning.go +++ b/server/pruning.go @@ -13,7 +13,7 @@ import ( // GetPruningOptionsFromFlags parses command flags and returns the correct // PruningOptions. If a pruning strategy is provided, that will be parsed and // returned, otherwise, it is assumed custom pruning options are provided. -func GetPruningOptionsFromFlags(appOpts types.AppOptions) (*pruningtypes.PruningOptions, error) { +func GetPruningOptionsFromFlags(appOpts types.AppOptions) (pruningtypes.PruningOptions, error) { strategy := strings.ToLower(cast.ToString(appOpts.Get(FlagPruning))) switch strategy { @@ -33,6 +33,6 @@ func GetPruningOptionsFromFlags(appOpts types.AppOptions) (*pruningtypes.Pruning return opts, nil default: - return nil, fmt.Errorf("unknown pruning strategy %s", strategy) + return pruningtypes.PruningOptions{}, fmt.Errorf("unknown pruning strategy %s", strategy) } } diff --git a/server/pruning_test.go b/server/pruning_test.go index 2321476b548f..2d7bc976d92e 100644 --- a/server/pruning_test.go +++ b/server/pruning_test.go @@ -13,7 +13,7 @@ func TestGetPruningOptionsFromFlags(t *testing.T) { tests := []struct { name string initParams func() *viper.Viper - expectedOptions *pruningtypes.PruningOptions + expectedOptions pruningtypes.PruningOptions wantErr bool }{ { diff --git a/store/iavl/store.go b/store/iavl/store.go index fdcf3b96eda4..3b961e0ab1c3 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -129,13 +129,13 @@ func (st *Store) LastCommitID() types.CommitID { // SetPruning panics as pruning options should be provided at initialization // since IAVl accepts pruning options directly. -func (st *Store) SetPruning(_ *pruningtypes.PruningOptions) { +func (st *Store) SetPruning(_ pruningtypes.PruningOptions) { panic("cannot set pruning options on an initialized IAVL store") } // SetPruning panics as pruning options should be provided at initialization // since IAVl accepts pruning options directly. -func (st *Store) GetPruning() *pruningtypes.PruningOptions { +func (st *Store) GetPruning() pruningtypes.PruningOptions { panic("cannot get pruning options on an initialized IAVL store") } diff --git a/store/mem/store.go b/store/mem/store.go index b48a566c853b..06d7b63f5506 100644 --- a/store/mem/store.go +++ b/store/mem/store.go @@ -55,11 +55,11 @@ func (s Store) CacheWrapWithListeners(storeKey types.StoreKey, listeners []types // Commit performs a no-op as entries are persistent between commitments. func (s *Store) Commit() (id types.CommitID) { return } -func (s *Store) SetPruning(pruning *pruningtypes.PruningOptions) {} +func (s *Store) SetPruning(pruning pruningtypes.PruningOptions) {} // GetPruning is a no-op as pruning options cannot be directly set on this store. // They must be set on the root commit multi-store. -func (s *Store) GetPruning() *pruningtypes.PruningOptions { +func (s *Store) GetPruning() pruningtypes.PruningOptions { return pruningtypes.NewPruningOptions(pruningtypes.PruningUndefined) } diff --git a/store/rootmulti/dbadapter.go b/store/rootmulti/dbadapter.go index 102c196e1cf7..00ca37553823 100644 --- a/store/rootmulti/dbadapter.go +++ b/store/rootmulti/dbadapter.go @@ -32,10 +32,10 @@ func (cdsa commitDBStoreAdapter) LastCommitID() types.CommitID { } } -func (cdsa commitDBStoreAdapter) SetPruning(_ *pruningtypes.PruningOptions) {} +func (cdsa commitDBStoreAdapter) SetPruning(_ pruningtypes.PruningOptions) {} // GetPruning is a no-op as pruning options cannot be directly set on this store. // They must be set on the root commit multi-store. -func (cdsa commitDBStoreAdapter) GetPruning() *pruningtypes.PruningOptions { +func (cdsa commitDBStoreAdapter) GetPruning() pruningtypes.PruningOptions { return pruningtypes.NewPruningOptions(pruningtypes.PruningUndefined) } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 25b8933c4a11..fe720240c464 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -84,14 +84,14 @@ func NewStore(db dbm.DB, logger log.Logger) *Store { } // GetPruning fetches the pruning strategy from the root store. -func (rs *Store) GetPruning() *pruningtypes.PruningOptions { +func (rs *Store) GetPruning() pruningtypes.PruningOptions { return rs.pruningManager.GetOptions() } // SetPruning sets the pruning strategy on the root store and all the sub-stores. // Note, calling SetPruning on the root store prior to LoadVersion or // LoadLatestVersion performs a no-op as the stores aren't mounted yet. -func (rs *Store) SetPruning(pruningOpts *pruningtypes.PruningOptions) { +func (rs *Store) SetPruning(pruningOpts pruningtypes.PruningOptions) { rs.pruningManager.SetOptions(pruningOpts) } diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index bba5776cd9af..930361600dca 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -472,7 +472,7 @@ func TestMultiStore_Pruning(t *testing.T) { testCases := []struct { name string numVersions int64 - po *pruningtypes.PruningOptions + po pruningtypes.PruningOptions deleted []int64 saved []int64 }{ @@ -742,7 +742,7 @@ var ( testStoreKey3 = types.NewKVStoreKey("store3") ) -func newMultiStoreWithMounts(db dbm.DB, pruningOpts *pruningtypes.PruningOptions) *Store { +func newMultiStoreWithMounts(db dbm.DB, pruningOpts pruningtypes.PruningOptions) *Store { store := NewStore(db, log.NewNopLogger()) store.SetPruning(pruningOpts) @@ -753,7 +753,7 @@ func newMultiStoreWithMounts(db dbm.DB, pruningOpts *pruningtypes.PruningOptions return store } -func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts *pruningtypes.PruningOptions) (*Store, *types.StoreUpgrades) { +func newMultiStoreWithModifiedMounts(db dbm.DB, pruningOpts pruningtypes.PruningOptions) (*Store, *types.StoreUpgrades) { store := NewStore(db, log.NewNopLogger()) store.SetPruning(pruningOpts) diff --git a/store/transient/store.go b/store/transient/store.go index 5c40c3b134f5..b9723b56efd5 100644 --- a/store/transient/store.go +++ b/store/transient/store.go @@ -28,11 +28,11 @@ func (ts *Store) Commit() (id types.CommitID) { return } -func (ts *Store) SetPruning(_ *pruningtypes.PruningOptions) {} +func (ts *Store) SetPruning(_ pruningtypes.PruningOptions) {} // GetPruning is a no-op as pruning options cannot be directly set on this store. // They must be set on the root commit multi-store. -func (ts *Store) GetPruning() *pruningtypes.PruningOptions { +func (ts *Store) GetPruning() pruningtypes.PruningOptions { return pruningtypes.NewPruningOptions(pruningtypes.PruningUndefined) } diff --git a/store/types/store.go b/store/types/store.go index 2f26a1029806..5554e1e1389e 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -23,8 +23,8 @@ type Committer interface { Commit() CommitID LastCommitID() CommitID - SetPruning(*pruningtypes.PruningOptions) - GetPruning() *pruningtypes.PruningOptions + SetPruning(pruningtypes.PruningOptions) + GetPruning() pruningtypes.PruningOptions } // Stores of MultiStore must implement CommitStore. diff --git a/store/v2alpha1/mem/store.go b/store/v2alpha1/mem/store.go index 32e31e7b42ad..1b7fca28e043 100644 --- a/store/v2alpha1/mem/store.go +++ b/store/v2alpha1/mem/store.go @@ -39,7 +39,7 @@ func (s *Store) Commit() (id types.CommitID) { return } -func (s *Store) SetPruning(*pruningtypes.PruningOptions) {} -func (s *Store) GetPruning() *pruningtypes.PruningOptions { return &pruningtypes.PruningOptions{} } +func (s *Store) SetPruning(pruningtypes.PruningOptions) {} +func (s *Store) GetPruning() pruningtypes.PruningOptions { return pruningtypes.PruningOptions{} } func (s Store) LastCommitID() (id types.CommitID) { return } diff --git a/store/v2alpha1/multi/store.go b/store/v2alpha1/multi/store.go index 736c2c32f3fe..983f132fcc1a 100644 --- a/store/v2alpha1/multi/store.go +++ b/store/v2alpha1/multi/store.go @@ -57,7 +57,7 @@ func ErrStoreNotFound(skey string) error { // StoreConfig is used to define a schema and other options and pass them to the MultiStore constructor. type StoreConfig struct { // Version pruning options for backing DBs. - Pruning *pruningtypes.PruningOptions + Pruning pruningtypes.PruningOptions // The minimum allowed version number. InitialVersion uint64 // The backing DB to use for the state commitment Merkle tree data. @@ -93,7 +93,7 @@ type Store struct { mtx sync.RWMutex // Copied from StoreConfig - Pruning *pruningtypes.PruningOptions + Pruning pruningtypes.PruningOptions InitialVersion uint64 // if *traceListenMixin @@ -909,5 +909,5 @@ func (tlm *traceListenMixin) wrapTraceListen(store types.KVStore, skey types.Sto return store } -func (s *Store) GetPruning() *pruningtypes.PruningOptions { return s.Pruning } -func (s *Store) SetPruning(po *pruningtypes.PruningOptions) { s.Pruning = po } +func (s *Store) GetPruning() pruningtypes.PruningOptions { return s.Pruning } +func (s *Store) SetPruning(po pruningtypes.PruningOptions) { s.Pruning = po } diff --git a/store/v2alpha1/multi/store_test.go b/store/v2alpha1/multi/store_test.go index 094dd8762549..0598b1f035bc 100644 --- a/store/v2alpha1/multi/store_test.go +++ b/store/v2alpha1/multi/store_test.go @@ -395,7 +395,7 @@ func sliceToSet(slice []uint64) map[uint64]struct{} { func TestPruning(t *testing.T) { // Save versions up to 10 and verify pruning at final commit testCases := []struct { - *pruningtypes.PruningOptions + pruningtypes.PruningOptions kept []uint64 }{ {pruningtypes.NewCustomPruningOptions(2, 10), []uint64{8, 9, 10}}, diff --git a/store/v2alpha1/transient/store.go b/store/v2alpha1/transient/store.go index 596af3f16a2c..7a3286989ee9 100644 --- a/store/v2alpha1/transient/store.go +++ b/store/v2alpha1/transient/store.go @@ -41,7 +41,7 @@ func (ts *Store) Commit() (id types.CommitID) { return } -func (ts *Store) SetPruning(*pruningtypes.PruningOptions) {} -func (ts *Store) GetPruning() *pruningtypes.PruningOptions { return &pruningtypes.PruningOptions{} } +func (ts *Store) SetPruning(pruningtypes.PruningOptions) {} +func (ts *Store) GetPruning() pruningtypes.PruningOptions { return pruningtypes.PruningOptions{} } func (ts *Store) LastCommitID() (id types.CommitID) { return } diff --git a/types/store.go b/types/store.go index ff2b6b4b280b..9968d4118cf2 100644 --- a/types/store.go +++ b/types/store.go @@ -170,10 +170,10 @@ func NewSnapshotOptions(interval uint64, keepRecent uint32) *snapshottypes.Snaps return snapshottypes.NewSnapshotOptions(interval, keepRecent) } -func NewPruningOptions(pruningStrategy pruningtypes.PruningStrategy) *pruningtypes.PruningOptions { +func NewPruningOptions(pruningStrategy pruningtypes.PruningStrategy) pruningtypes.PruningOptions { return pruningtypes.NewPruningOptions(pruningStrategy) } -func NewCustomPruningOptions(keepRecent, interval uint64) *pruningtypes.PruningOptions { +func NewCustomPruningOptions(keepRecent, interval uint64) pruningtypes.PruningOptions { return pruningtypes.NewCustomPruningOptions(keepRecent, interval) } From 1c7b5a9fa262d9134b2b590cd23acb06f9f03093 Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 11 Apr 2022 19:58:34 -0400 Subject: [PATCH 28/58] revert snapshot options pointer --- baseapp/baseapp_test.go | 16 ++++++++-------- baseapp/options.go | 6 +++--- snapshots/manager.go | 4 ++-- snapshots/types/options.go | 8 ++++++-- types/store.go | 2 +- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 74b33cb50ba6..f70f8ad81dbb 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -2359,7 +2359,7 @@ func TestBaseApp_Init(t *testing.T) { testCases := map[string]struct { bapp *baseapp.BaseApp expectedPruning pruningtypes.PruningOptions - expectedSnapshot *snapshottypes.SnapshotOptions + expectedSnapshot snapshottypes.SnapshotOptions expectedErr error }{ "snapshot but no pruning": { @@ -2376,7 +2376,7 @@ func TestBaseApp_Init(t *testing.T) { baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningEverything)), ), sdk.NewPruningOptions(pruningtypes.PruningEverything), - nil, + sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), nil, }, "pruning nothing only": { @@ -2384,7 +2384,7 @@ func TestBaseApp_Init(t *testing.T) { baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)), ), sdk.NewPruningOptions(pruningtypes.PruningNothing), - nil, + sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), nil, }, "pruning default only": { @@ -2392,7 +2392,7 @@ func TestBaseApp_Init(t *testing.T) { baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningDefault)), ), sdk.NewPruningOptions(pruningtypes.PruningDefault), - nil, + sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), nil, }, "pruning custom only": { @@ -2400,7 +2400,7 @@ func TestBaseApp_Init(t *testing.T) { baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 10)), ), sdk.NewCustomPruningOptions(10, 10), - nil, + sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), nil, }, "pruning everything and snapshots": { @@ -2469,10 +2469,10 @@ func TestBaseApp_Init(t *testing.T) { "snapshot zero interval - manager not set": { baseapp.NewBaseApp(name, logger, db, baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 10)), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(0, 2)), + baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 2)), ), sdk.NewCustomPruningOptions(10, 10), - nil, // the snapshot manager is not set when interval is 0 + sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), nil, }, "snapshot zero keep recent - allowed": { @@ -2498,7 +2498,7 @@ func TestBaseApp_Init(t *testing.T) { require.Equal(t, tc.expectedPruning, actualPruning) snapshotManager := tc.bapp.GetSnapshotManager() - if tc.expectedSnapshot == nil { + if tc.expectedSnapshot.Interval == snapshottypes.SnapshotIntervalOff { require.Nil(t, snapshotManager) continue } diff --git a/baseapp/options.go b/baseapp/options.go index 90b59ed13827..ecaa6fc4f293 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -72,7 +72,7 @@ func SetInterBlockCache(cache sdk.MultiStorePersistentCache) func(*BaseApp) { } // SetSnapshot sets the snapshot store. -func SetSnapshot(snapshotStore *snapshots.Store, opts *snapshottypes.SnapshotOptions) func(*BaseApp) { +func SetSnapshot(snapshotStore *snapshots.Store, opts snapshottypes.SnapshotOptions) func(*BaseApp) { return func(app *BaseApp) { app.SetSnapshot(snapshotStore, opts) } } @@ -194,11 +194,11 @@ func (app *BaseApp) SetStoreLoader(loader StoreLoader) { } // SetSnapshot sets the snapshot store and options. -func (app *BaseApp) SetSnapshot(snapshotStore *snapshots.Store, opts *snapshottypes.SnapshotOptions) { +func (app *BaseApp) SetSnapshot(snapshotStore *snapshots.Store, opts snapshottypes.SnapshotOptions) { if app.sealed { panic("SetSnapshot() on sealed BaseApp") } - if snapshotStore == nil || opts.Interval == 0 { + if snapshotStore == nil || opts.Interval == snapshottypes.SnapshotIntervalOff { app.snapshotManager = nil return } diff --git a/snapshots/manager.go b/snapshots/manager.go index 0defd623bd51..e614be076977 100644 --- a/snapshots/manager.go +++ b/snapshots/manager.go @@ -33,7 +33,7 @@ type Manager struct { extensions map[string]types.ExtensionSnapshotter // store is the snapshot store where all completed snapshots are persisted. store *Store - opts *types.SnapshotOptions + opts types.SnapshotOptions // multistore is the store from which snapshots are taken. multistore types.Snapshotter logger log.Logger @@ -71,7 +71,7 @@ var ( ) // NewManager creates a new manager. -func NewManager(store *Store, opts *types.SnapshotOptions, multistore types.Snapshotter, extensions map[string]types.ExtensionSnapshotter, logger log.Logger) *Manager { +func NewManager(store *Store, opts types.SnapshotOptions, multistore types.Snapshotter, extensions map[string]types.ExtensionSnapshotter, logger log.Logger) *Manager { multistore.SetSnapshotInterval(opts.Interval) return &Manager{ store: store, diff --git a/snapshots/types/options.go b/snapshots/types/options.go index c419c019e4e8..3a0e05a5a068 100644 --- a/snapshots/types/options.go +++ b/snapshots/types/options.go @@ -10,8 +10,12 @@ type SnapshotOptions struct { KeepRecent uint32 } -func NewSnapshotOptions(interval uint64, keepRecent uint32) *SnapshotOptions { - return &SnapshotOptions{ +// SnapshotIntervalOff represents the snapshot inerval, at which +// no snapshots are taken. +const SnapshotIntervalOff uint64 = 0 + +func NewSnapshotOptions(interval uint64, keepRecent uint32) SnapshotOptions { + return SnapshotOptions{ Interval: interval, KeepRecent: keepRecent, } diff --git a/types/store.go b/types/store.go index 9968d4118cf2..d654ef3e5d21 100644 --- a/types/store.go +++ b/types/store.go @@ -166,7 +166,7 @@ func NewInfiniteGasMeter() GasMeter { return types.NewInfiniteGasMeter() } -func NewSnapshotOptions(interval uint64, keepRecent uint32) *snapshottypes.SnapshotOptions { +func NewSnapshotOptions(interval uint64, keepRecent uint32) snapshottypes.SnapshotOptions { return snapshottypes.NewSnapshotOptions(interval, keepRecent) } From fdf35158af197084752b50f757b0848ddf2aed1f Mon Sep 17 00:00:00 2001 From: Roman <34196718+p0mvn@users.noreply.github.com> Date: Wed, 13 Apr 2022 11:18:42 -0400 Subject: [PATCH 29/58] refactor: syncronize pruning manager (#187) * progress * refactor pruning manager to have no data races; flush heights immediately when updated in memory; unit tests * typo in TestMultiStore_PruningRestart * fmt * improve comments * avoid mutex init, move comments to struct declaration, return nil with error, fix logs --- pruning/export_test.go | 6 +- pruning/manager.go | 173 ++++++++++++--------- pruning/manager_test.go | 283 +++++++++++++++++++++------------- store/rootmulti/store.go | 13 +- store/rootmulti/store_test.go | 70 ++++++++- 5 files changed, 355 insertions(+), 190 deletions(-) diff --git a/pruning/export_test.go b/pruning/export_test.go index 6a270b46eb82..51b1c10462a9 100644 --- a/pruning/export_test.go +++ b/pruning/export_test.go @@ -7,6 +7,8 @@ var ( PruneSnapshotHeightsKey = pruneSnapshotHeightsKey // functions - Int64SliceToBytes = int64SliceToBytes - ListToBytes = listToBytes + Int64SliceToBytes = int64SliceToBytes + ListToBytes = listToBytes + LoadPruningHeights = loadPruningHeights + LoadPruningSnapshotHeights = loadPruningSnapshotHeights ) diff --git a/pruning/manager.go b/pruning/manager.go index 2b4b6309b85b..cd13365f1962 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -13,12 +13,21 @@ import ( ) type Manager struct { - logger log.Logger - opts types.PruningOptions - snapshotInterval uint64 - pruneHeights []int64 - pruneSnapshotHeights *list.List - mx sync.Mutex + db dbm.DB + logger log.Logger + opts types.PruningOptions + snapshotInterval uint64 + pruneHeights []int64 + // Although pruneHeights happen in the same goroutine with the normal execution, + // we sync access to them to avoid soundness issues in the future if concurrency pattern changes. + pruneHeightsMx sync.Mutex + // These are the heights that are multiples of snapshotInterval and kept for state sync snapshots. + // The heights are added to this list to be pruned when a snapshot is complete. + pruneSnapshotHeights *list.List + // Snapshots are taken in a separate goroutine fromt the regular execution + // and can be delivered asynchrounously via HandleHeightSnapshot. + // Therefore, we sync access to pruneSnapshotHeights with this mutex. + pruneSnapshotHeightsMx sync.Mutex } const errNegativeHeightsFmt = "failed to get pruned heights: %d" @@ -28,15 +37,13 @@ var ( pruneSnapshotHeightsKey = []byte("s/pruneSnheights") ) -func NewManager(logger log.Logger) *Manager { +func NewManager(db dbm.DB, logger log.Logger) *Manager { return &Manager{ - logger: logger, - opts: types.NewPruningOptions(types.PruningNothing), - pruneHeights: []int64{}, - // These are the heights that are multiples of snapshotInterval and kept for state sync snapshots. - // The heights are added to this list to be pruned when a snapshot is complete. - pruneSnapshotHeights: list.New(), - mx: sync.Mutex{}, + db: db, + logger: logger, + opts: types.NewPruningOptions(types.PruningNothing), + pruneHeights: []int64{}, + pruneSnapshotHeights: list.New(), } } @@ -50,15 +57,25 @@ func (m *Manager) GetOptions() types.PruningOptions { return m.opts } -// GetPruningHeights returns all heights to be pruned during the next call to Prune(). -func (m *Manager) GetPruningHeights() []int64 { - return m.pruneHeights -} +// GetFlushAndResetPruningHeights returns all heights to be pruned during the next call to Prune(). +// It also flushes and resets the pruning heights. +func (m *Manager) GetFlushAndResetPruningHeights() ([]int64, error) { + if m.opts.GetPruningStrategy() == types.PruningNothing { + return []int64{}, nil + } + m.pruneHeightsMx.Lock() + defer m.pruneHeightsMx.Unlock() + + pruningHeights := m.pruneHeights + + // flush the updates to disk so that it is not lost if crash happens. + if err := m.db.SetSync(pruneHeightsKey, int64SliceToBytes(pruningHeights)); err != nil { + return nil, err + } -// ResetPruningHeights resets the heights to be pruned. -func (m *Manager) ResetPruningHeights() { - // reuse previously allocated memory. - m.pruneHeights = m.pruneHeights[:0] + m.pruneHeights = make([]int64, 0, m.opts.Interval) + + return pruningHeights, nil } // HandleHeight determines if pruneHeight height needs to be kept for pruning at the right interval prescribed by @@ -71,9 +88,14 @@ func (m *Manager) HandleHeight(previousHeight int64) int64 { } defer func() { - // handle persisted snapshot heights - m.mx.Lock() - defer m.mx.Unlock() + m.pruneHeightsMx.Lock() + defer m.pruneHeightsMx.Unlock() + + m.pruneSnapshotHeightsMx.Lock() + defer m.pruneSnapshotHeightsMx.Unlock() + + // move persisted snapshot heights to pruneHeights which + // represent the heights to be pruned at the next pruning interval. var next *list.Element for e := m.pruneSnapshotHeights.Front(); e != nil; e = next { snHeight := e.Value.(int64) @@ -87,6 +109,11 @@ func (m *Manager) HandleHeight(previousHeight int64) int64 { next = e.Next() } } + + // flush the updates to disk so that they are not lost if crash happens. + if err := m.db.SetSync(pruneHeightsKey, int64SliceToBytes(m.pruneHeights)); err != nil { + panic(err) + } }() if int64(m.opts.KeepRecent) < previousHeight { @@ -97,21 +124,38 @@ func (m *Manager) HandleHeight(previousHeight int64) int64 { // - snapshotInterval % (height - KeepRecent) != 0 as that means the height is not // a 'snapshot' height. if m.snapshotInterval == 0 || pruneHeight%int64(m.snapshotInterval) != 0 { + m.pruneHeightsMx.Lock() + defer m.pruneHeightsMx.Unlock() + m.pruneHeights = append(m.pruneHeights, pruneHeight) + + // flush the updates to disk so that they are not lost if crash happens. + if err := m.db.SetSync(pruneHeightsKey, int64SliceToBytes(m.pruneHeights)); err != nil { + panic(err) + } return pruneHeight } } return 0 } +// HandleHeightSnapshot persists the snapshot height to be pruned at the next appropriate +// height defined by the pruning strategy. Flushes the update to disk and panics if the flush fails +// The input height must be greater than 0 and pruning strategy any but pruning nothing. +// If one of these conditions is not met, this function does nothing. func (m *Manager) HandleHeightSnapshot(height int64) { - if m.opts.GetPruningStrategy() == types.PruningNothing { + if m.opts.GetPruningStrategy() == types.PruningNothing || height <= 0 { return } - m.mx.Lock() - defer m.mx.Unlock() + m.pruneSnapshotHeightsMx.Lock() + defer m.pruneSnapshotHeightsMx.Unlock() m.logger.Debug("HandleHeightSnapshot", "height", height) m.pruneSnapshotHeights.PushBack(height) + + // flush the updates to disk so that they are not lost if crash happens. + if err := m.db.SetSync(pruneSnapshotHeightsKey, listToBytes(m.pruneSnapshotHeights)); err != nil { + panic(err) + } } // SetSnapshotInterval sets the interval at which the snapshots are taken. @@ -124,33 +168,43 @@ func (m *Manager) ShouldPruneAtHeight(height int64) bool { return m.opts.Interval > 0 && m.opts.GetPruningStrategy() != types.PruningNothing && height%int64(m.opts.Interval) == 0 } -// FlushPruningHeights flushes the pruning heights to the database for crash recovery. -func (m *Manager) FlushPruningHeights(batch dbm.Batch) { - if m.opts.GetPruningStrategy() == types.PruningNothing { - return - } - m.flushPruningHeights(batch) - m.flushPruningSnapshotHeights(batch) -} - // LoadPruningHeights loads the pruning heights from the database as a crash recovery. func (m *Manager) LoadPruningHeights(db dbm.DB) error { if m.opts.GetPruningStrategy() == types.PruningNothing { return nil } - if err := m.loadPruningHeights(db); err != nil { + loadedPruneHeights, err := loadPruningHeights(db) + if err != nil { + return err + } + + if len(loadedPruneHeights) > 0 { + m.pruneHeightsMx.Lock() + defer m.pruneHeightsMx.Unlock() + m.pruneHeights = loadedPruneHeights + } + + loadedPruneSnapshotHeights, err := loadPruningSnapshotHeights(db) + if err != nil { return err } - return m.loadPruningSnapshotHeights(db) + + if loadedPruneSnapshotHeights.Len() > 0 { + m.pruneSnapshotHeightsMx.Lock() + defer m.pruneSnapshotHeightsMx.Unlock() + m.pruneSnapshotHeights = loadedPruneSnapshotHeights + } + + return nil } -func (m *Manager) loadPruningHeights(db dbm.DB) error { +func loadPruningHeights(db dbm.DB) ([]int64, error) { bz, err := db.Get(pruneHeightsKey) if err != nil { - return fmt.Errorf("failed to get pruned heights: %w", err) + return nil, fmt.Errorf("failed to get pruned heights: %w", err) } if len(bz) == 0 { - return nil + return []int64{}, nil } prunedHeights := make([]int64, len(bz)/8) @@ -158,7 +212,7 @@ func (m *Manager) loadPruningHeights(db dbm.DB) error { for offset < len(bz) { h := int64(binary.BigEndian.Uint64(bz[offset : offset+8])) if h < 0 { - return fmt.Errorf(errNegativeHeightsFmt, h) + return []int64{}, fmt.Errorf(errNegativeHeightsFmt, h) } prunedHeights[i] = h @@ -166,28 +220,24 @@ func (m *Manager) loadPruningHeights(db dbm.DB) error { offset += 8 } - if len(prunedHeights) > 0 { - m.pruneHeights = prunedHeights - } - - return nil + return prunedHeights, nil } -func (m *Manager) loadPruningSnapshotHeights(db dbm.DB) error { +func loadPruningSnapshotHeights(db dbm.DB) (*list.List, error) { bz, err := db.Get(pruneSnapshotHeightsKey) + pruneSnapshotHeights := list.New() if err != nil { - return fmt.Errorf("failed to get post-snapshot pruned heights: %w", err) + return nil, fmt.Errorf("failed to get post-snapshot pruned heights: %w", err) } if len(bz) == 0 { - return nil + return pruneSnapshotHeights, nil } - pruneSnapshotHeights := list.New() i, offset := 0, 0 for offset < len(bz) { h := int64(binary.BigEndian.Uint64(bz[offset : offset+8])) if h < 0 { - return fmt.Errorf(errNegativeHeightsFmt, h) + return pruneSnapshotHeights, fmt.Errorf(errNegativeHeightsFmt, h) } pruneSnapshotHeights.PushBack(h) @@ -195,24 +245,9 @@ func (m *Manager) loadPruningSnapshotHeights(db dbm.DB) error { offset += 8 } - m.mx.Lock() - defer m.mx.Unlock() - m.pruneSnapshotHeights = pruneSnapshotHeights - - return nil -} - -func (m *Manager) flushPruningHeights(batch dbm.Batch) { - batch.Set(pruneHeightsKey, int64SliceToBytes(m.pruneHeights)) -} - -func (m *Manager) flushPruningSnapshotHeights(batch dbm.Batch) { - m.mx.Lock() - defer m.mx.Unlock() - batch.Set(pruneSnapshotHeightsKey, listToBytes(m.pruneSnapshotHeights)) + return pruneSnapshotHeights, nil } -// TODO: convert to a generic version with Go 1.18. func int64SliceToBytes(slice []int64) []byte { bz := make([]byte, 0, len(slice)*8) for _, ph := range slice { diff --git a/pruning/manager_test.go b/pruning/manager_test.go index e6a696b7f025..f00171c673f4 100644 --- a/pruning/manager_test.go +++ b/pruning/manager_test.go @@ -4,9 +4,7 @@ import ( "container/list" "fmt" - "sync" "testing" - "time" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" @@ -17,10 +15,12 @@ import ( ) func TestNewManager(t *testing.T) { - manager := pruning.NewManager(log.NewNopLogger()) + manager := pruning.NewManager(db.NewMemDB(), log.NewNopLogger()) require.NotNil(t, manager) - require.NotNil(t, manager.GetPruningHeights()) + heights, err := manager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.NotNil(t, heights) require.Equal(t, types.PruningNothing, manager.GetOptions().GetPruningStrategy()) } @@ -75,7 +75,7 @@ func TestStrategies(t *testing.T) { }, } - manager := pruning.NewManager(log.NewNopLogger()) + manager := pruning.NewManager(db.NewMemDB(), log.NewNopLogger()) require.NotNil(t, manager) @@ -112,7 +112,8 @@ func TestStrategies(t *testing.T) { handleHeightActual := manager.HandleHeight(curHeight) shouldPruneAtHeightActual := manager.ShouldPruneAtHeight(curHeight) - curPruningHeihts := manager.GetPruningHeights() + curPruningHeihts, err := manager.GetFlushAndResetPruningHeights() + require.Nil(t, err) curHeightStr := fmt.Sprintf("height: %d", curHeight) @@ -121,7 +122,9 @@ func TestStrategies(t *testing.T) { require.Equal(t, int64(0), handleHeightActual, curHeightStr) require.False(t, shouldPruneAtHeightActual, curHeightStr) - require.Equal(t, 0, len(manager.GetPruningHeights())) + heights, err := manager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.Equal(t, 0, len(heights)) default: if curHeight > int64(curKeepRecent) && (tc.snapshotInterval != 0 && (curHeight-int64(curKeepRecent))%int64(tc.snapshotInterval) != 0 || tc.snapshotInterval == 0) { expectedHeight := curHeight - int64(curKeepRecent) @@ -131,12 +134,15 @@ func TestStrategies(t *testing.T) { } else { require.Equal(t, int64(0), handleHeightActual, curHeightStr) - require.Equal(t, 0, len(manager.GetPruningHeights())) + heights, err := manager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.Equal(t, 0, len(heights)) } require.Equal(t, curHeight%int64(curInterval) == 0, shouldPruneAtHeightActual, curHeightStr) } - manager.ResetPruningHeights() - require.Equal(t, 0, len(manager.GetPruningHeights())) + heights, err := manager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.Equal(t, 0, len(heights)) } }) } @@ -146,9 +152,9 @@ func TestHandleHeight_Inputs(t *testing.T) { var keepRecent int64 = int64(types.NewPruningOptions(types.PruningEverything).KeepRecent) testcases := map[string]struct { - height int64 - expectedResult int64 - strategy types.PruningStrategy + height int64 + expectedResult int64 + strategy types.PruningStrategy expectedHeights []int64 }{ "previousHeight is negative - prune everything - invalid previousHeight": { @@ -185,23 +191,158 @@ func TestHandleHeight_Inputs(t *testing.T) { for name, tc := range testcases { t.Run(name, func(t *testing.T) { - manager := pruning.NewManager(log.NewNopLogger()) + manager := pruning.NewManager(db.NewMemDB(), log.NewNopLogger()) require.NotNil(t, manager) manager.SetOptions(types.NewPruningOptions(tc.strategy)) handleHeightActual := manager.HandleHeight(tc.height) require.Equal(t, tc.expectedResult, handleHeightActual) - require.Equal(t, tc.expectedHeights, manager.GetPruningHeights()) + actualHeights, err := manager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.Equal(t, len(tc.expectedHeights), len(actualHeights)) + require.Equal(t, tc.expectedHeights, actualHeights) }) } } -func TestFlushLoad(t *testing.T) { - manager := pruning.NewManager(log.NewNopLogger()) +func TestHandleHeight_FlushLoadFromDisk(t *testing.T) { + testcases := map[string]struct { + previousHeight int64 + keepRecent uint64 + snapshotInterval uint64 + movedSnapshotHeights []int64 + expectedHandleHeightResult int64 + expectedLoadPruningHeightsResult error + expectedLoadedHeights []int64 + }{ + "simple flush occurs": { + previousHeight: 11, + keepRecent: 10, + snapshotInterval: 0, + movedSnapshotHeights: []int64{}, + expectedHandleHeightResult: 11 - 10, + expectedLoadPruningHeightsResult: nil, + expectedLoadedHeights: []int64{11 - 10}, + }, + "previous height <= keep recent - no update and no flush": { + previousHeight: 9, + keepRecent: 10, + snapshotInterval: 0, + movedSnapshotHeights: []int64{}, + expectedHandleHeightResult: 0, + expectedLoadPruningHeightsResult: nil, + expectedLoadedHeights: []int64{}, + }, + "previous height alligns with snapshot interval - no update and no flush": { + previousHeight: 12, + keepRecent: 10, + snapshotInterval: 2, + movedSnapshotHeights: []int64{}, + expectedHandleHeightResult: 0, + expectedLoadPruningHeightsResult: nil, + expectedLoadedHeights: []int64{}, + }, + "previous height does not align with snapshot interval - flush": { + previousHeight: 12, + keepRecent: 10, + snapshotInterval: 3, + movedSnapshotHeights: []int64{}, + expectedHandleHeightResult: 2, + expectedLoadPruningHeightsResult: nil, + expectedLoadedHeights: []int64{2}, + }, + "moved snapshot heights - flushed": { + previousHeight: 32, + keepRecent: 10, + snapshotInterval: 5, + movedSnapshotHeights: []int64{15, 20, 25}, + expectedHandleHeightResult: 22, + expectedLoadPruningHeightsResult: nil, + expectedLoadedHeights: []int64{15, 20, 22}, + }, + "previous height alligns with snapshot interval - no update but flush snapshot heights": { + previousHeight: 30, + keepRecent: 10, + snapshotInterval: 5, + movedSnapshotHeights: []int64{15, 20, 25}, + expectedHandleHeightResult: 0, + expectedLoadPruningHeightsResult: nil, + expectedLoadedHeights: []int64{15}, + }, + } + + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + // Setup + db := db.NewMemDB() + manager := pruning.NewManager(db, log.NewNopLogger()) + require.NotNil(t, manager) + + manager.SetSnapshotInterval(tc.snapshotInterval) + manager.SetOptions(types.NewCustomPruningOptions(uint64(tc.keepRecent), uint64(10))) + + for _, snapshotHeight := range tc.movedSnapshotHeights { + manager.HandleHeightSnapshot(snapshotHeight) + } + + // Test HandleHeight and flush + handleHeightActual := manager.HandleHeight(tc.previousHeight) + require.Equal(t, tc.expectedHandleHeightResult, handleHeightActual) + + loadedPruneHeights, err := pruning.LoadPruningHeights(db) + require.NoError(t, err) + require.Equal(t, len(loadedPruneHeights), len(loadedPruneHeights)) + + // Test load back + err = manager.LoadPruningHeights(db) + require.NoError(t, err) + + heights, err := manager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.Equal(t, len(tc.expectedLoadedHeights), len(heights)) + require.ElementsMatch(t, tc.expectedLoadedHeights, heights) + }) + } +} + +func TestHandleHeightSnapshot_FlushLoadFromDisk(t *testing.T) { + loadedHeightsMirror := []int64{} + + // Setup + db := db.NewMemDB() + manager := pruning.NewManager(db, log.NewNopLogger()) require.NotNil(t, manager) + manager.SetOptions(types.NewPruningOptions(types.PruningEverything)) + + for snapshotHeight := int64(-1); snapshotHeight < 100; snapshotHeight++ { + // Test flush + manager.HandleHeightSnapshot(snapshotHeight) + + // Post test + if snapshotHeight > 0 { + loadedHeightsMirror = append(loadedHeightsMirror, snapshotHeight) + } + + loadedSnapshotHeights, err := pruning.LoadPruningSnapshotHeights(db) + require.NoError(t, err) + require.Equal(t, len(loadedHeightsMirror), loadedSnapshotHeights.Len()) + + // Test load back + err = manager.LoadPruningHeights(db) + require.NoError(t, err) + + loadedSnapshotHeights, err = pruning.LoadPruningSnapshotHeights(db) + require.NoError(t, err) + require.Equal(t, len(loadedHeightsMirror), loadedSnapshotHeights.Len()) + } +} + +func TestFlushLoad(t *testing.T) { db := db.NewMemDB() + manager := pruning.NewManager(db, log.NewNopLogger()) + require.NotNil(t, manager) curStrategy := types.NewCustomPruningOptions(100, 15) @@ -228,32 +369,28 @@ func TestFlushLoad(t *testing.T) { require.Equal(t, int64(0), handleHeightActual, curHeightStr) } - if manager.ShouldPruneAtHeight(curHeight) { - manager.ResetPruningHeights() - heightsToPruneMirror = make([]int64, 0) - } - - // N.B.: There is no reason behind the choice of 3. - if curHeight%3 == 0 { - require.Equal(t, heightsToPruneMirror, manager.GetPruningHeights(), curHeightStr) - batch := db.NewBatch() - manager.FlushPruningHeights(batch) - require.NoError(t, batch.Write()) - require.NoError(t, batch.Close()) + if manager.ShouldPruneAtHeight(curHeight) && curHeight > int64(keepRecent) { + actualHeights, err := manager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.Equal(t, len(heightsToPruneMirror), len(actualHeights)) + require.Equal(t, heightsToPruneMirror, actualHeights) - manager.ResetPruningHeights() - require.Equal(t, make([]int64, 0), manager.GetPruningHeights(), curHeightStr) + err = manager.LoadPruningHeights(db) + require.NoError(t, err) - err := manager.LoadPruningHeights(db) + actualHeights, err = manager.GetFlushAndResetPruningHeights() require.NoError(t, err) - require.Equal(t, heightsToPruneMirror, manager.GetPruningHeights(), curHeightStr) + require.Equal(t, len(heightsToPruneMirror), len(actualHeights)) + require.Equal(t, heightsToPruneMirror, actualHeights) + + heightsToPruneMirror = make([]int64, 0) } } } func TestLoadPruningHeights(t *testing.T) { var ( - manager = pruning.NewManager(log.NewNopLogger()) + manager = pruning.NewManager(db.NewMemDB(), log.NewNopLogger()) err error ) require.NotNil(t, manager) @@ -323,86 +460,10 @@ func TestLoadPruningHeights(t *testing.T) { } func TestLoadPruningHeights_PruneNothing(t *testing.T) { - var manager = pruning.NewManager(log.NewNopLogger()) + var manager = pruning.NewManager(db.NewMemDB(), log.NewNopLogger()) require.NotNil(t, manager) manager.SetOptions(types.NewPruningOptions(types.PruningNothing)) require.Nil(t, manager.LoadPruningHeights(db.NewMemDB())) } - -func TestWithSnapshot(t *testing.T) { - manager := pruning.NewManager(log.NewNopLogger()) - require.NotNil(t, manager) - - curStrategy := types.NewCustomPruningOptions(10, 10) - - snapshotInterval := uint64(15) - manager.SetSnapshotInterval(snapshotInterval) - - manager.SetOptions(curStrategy) - require.Equal(t, curStrategy, manager.GetOptions()) - - keepRecent := curStrategy.KeepRecent - - heightsToPruneMirror := make([]int64, 0) - - mx := sync.Mutex{} - snapshotHeightsToPruneMirror := list.New() - - wg := sync.WaitGroup{} - defer wg.Wait() - - for curHeight := int64(1); curHeight < 100000; curHeight++ { - mx.Lock() - handleHeightActual := manager.HandleHeight(curHeight) - - curHeightStr := fmt.Sprintf("height: %d", curHeight) - - if curHeight > int64(keepRecent) && (curHeight-int64(keepRecent))%int64(snapshotInterval) != 0 { - expectedHandleHeight := curHeight - int64(keepRecent) - require.Equal(t, expectedHandleHeight, handleHeightActual, curHeightStr) - heightsToPruneMirror = append(heightsToPruneMirror, expectedHandleHeight) - } else { - require.Equal(t, int64(0), handleHeightActual, curHeightStr) - } - - actualHeightsToPrune := manager.GetPruningHeights() - - var next *list.Element - for e := snapshotHeightsToPruneMirror.Front(); e != nil; e = next { - snapshotHeight := e.Value.(int64) - if snapshotHeight < curHeight-int64(keepRecent) { - heightsToPruneMirror = append(heightsToPruneMirror, snapshotHeight) - - // We must get next before removing to be able to continue iterating. - next = e.Next() - snapshotHeightsToPruneMirror.Remove(e) - } else { - next = e.Next() - } - } - - require.Equal(t, heightsToPruneMirror, actualHeightsToPrune, curHeightStr) - mx.Unlock() - - if manager.ShouldPruneAtHeight(curHeight) { - manager.ResetPruningHeights() - heightsToPruneMirror = make([]int64, 0) - } - - // Mimic taking snapshots in the background - if curHeight%int64(snapshotInterval) == 0 { - wg.Add(1) - go func(curHeightCp int64) { - time.Sleep(time.Nanosecond * 500) - - mx.Lock() - manager.HandleHeightSnapshot(curHeightCp) - snapshotHeightsToPruneMirror.PushBack(curHeightCp) - mx.Unlock() - wg.Done() - }(curHeight) - } - } -} diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index fe720240c464..48ab06a0f554 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -79,7 +79,7 @@ func NewStore(db dbm.DB, logger log.Logger) *Store { keysByName: make(map[string]types.StoreKey), listeners: make(map[types.StoreKey][]types.WriteListener), removalMap: make(map[types.StoreKey]bool), - pruningManager: pruning.NewManager(logger), + pruningManager: pruning.NewManager(db, logger), } } @@ -550,13 +550,18 @@ func (rs *Store) handlePruning(version int64) error { } func (rs *Store) pruneStores() error { - pruningHeights := rs.pruningManager.GetPruningHeights() - rs.logger.Debug(fmt.Sprintf("pruning the following heights: %v\n", pruningHeights)) + pruningHeights, err := rs.pruningManager.GetFlushAndResetPruningHeights() + if err != nil { + return err + } if len(pruningHeights) == 0 { + rs.logger.Debug("pruning skipped; no heights to prune") return nil } + rs.logger.Debug("pruning heights", "heights", pruningHeights) + for key, store := range rs.stores { // If the store is wrapped with an inter-block cache, we must first unwrap // it to get the underlying IAVL store. @@ -575,7 +580,6 @@ func (rs *Store) pruneStores() error { return err } } - rs.pruningManager.ResetPruningHeights() return nil } @@ -964,7 +968,6 @@ func (rs *Store) flushMetadata(db dbm.DB, version int64, cInfo *types.CommitInfo } flushLatestVersion(batch, version) - rs.pruningManager.FlushPruningHeights(batch) if err := batch.WriteSync(); err != nil { panic(fmt.Errorf("error on batch write %w", err)) diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 930361600dca..f2b1bc82ed0a 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -508,6 +508,60 @@ func TestMultiStore_Pruning(t *testing.T) { } } +func TestMultiStore_Pruning_SameHeightsTwice(t *testing.T) { + const ( + numVersions int64 = 10 + keepRecent uint64 = 2 + interval uint64 = 10 + ) + + expectedHeights := []int64{} + for i := int64(1); i < numVersions-int64(keepRecent); i++ { + expectedHeights = append(expectedHeights, i) + } + + db := dbm.NewMemDB() + + ms := newMultiStoreWithMounts(db, pruningtypes.NewCustomPruningOptions(keepRecent, interval)) + require.NoError(t, ms.LoadLatestVersion()) + + var lastCommitInfo types.CommitID + for i := int64(0); i < numVersions; i++ { + lastCommitInfo = ms.Commit() + } + + require.Equal(t, numVersions, lastCommitInfo.Version) + + for v := int64(1); v < numVersions-int64(keepRecent); v++ { + err := ms.LoadVersion(v) + require.Error(t, err, "expected error when loading pruned height: %d", v) + } + + for v := int64(numVersions - int64(keepRecent)); v < numVersions; v++ { + err := ms.LoadVersion(v) + require.NoError(t, err, "expected no error when loading height: %d", v) + } + + // Get latest + err := ms.LoadVersion(numVersions - 1) + require.NoError(t, err) + + // Ensure already pruned heights were loaded + heights, err := ms.pruningManager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.Equal(t, expectedHeights, heights) + + require.NoError(t, ms.pruningManager.LoadPruningHeights(db)) + + // Test pruning the same heights again + lastCommitInfo = ms.Commit() + require.Equal(t, numVersions, lastCommitInfo.Version) + + // Ensure that can commit one more height with no panic + lastCommitInfo = ms.Commit() + require.Equal(t, numVersions+1, lastCommitInfo.Version) +} + func TestMultiStore_PruningRestart(t *testing.T) { db := dbm.NewMemDB() ms := newMultiStoreWithMounts(db, pruningtypes.NewCustomPruningOptions(2, 11)) @@ -525,18 +579,28 @@ func TestMultiStore_PruningRestart(t *testing.T) { // ensure we've persisted the current batch of heights to prune to the store's DB err := ms.pruningManager.LoadPruningHeights(ms.db) require.NoError(t, err) - require.Equal(t, pruneHeights, ms.pruningManager.GetPruningHeights()) + + actualHeightsToPrune, err := ms.pruningManager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.Equal(t, len(pruneHeights), len(actualHeightsToPrune)) + require.Equal(t, pruneHeights, actualHeightsToPrune) // "restart" ms = newMultiStoreWithMounts(db, pruningtypes.NewCustomPruningOptions(2, 11)) ms.SetSnapshotInterval(3) err = ms.LoadLatestVersion() require.NoError(t, err) - require.Equal(t, pruneHeights, ms.pruningManager.GetPruningHeights()) + + actualHeightsToPrune, err = ms.pruningManager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.Equal(t, pruneHeights, actualHeightsToPrune) // commit one more block and ensure the heights have been pruned ms.Commit() - require.Empty(t, ms.pruningManager.GetPruningHeights()) + + actualHeightsToPrune, err = ms.pruningManager.GetFlushAndResetPruningHeights() + require.NoError(t, err) + require.Empty(t, actualHeightsToPrune) for _, v := range pruneHeights { _, err := ms.CacheMultiStoreWithVersion(v) From d9eb77c9e8b246957a0d066b6b71e9ba33bc5222 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 13 Apr 2022 12:40:08 -0400 Subject: [PATCH 30/58] fix rebase problem in tests --- baseapp/baseapp_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index f70f8ad81dbb..5616c2352b3d 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -291,7 +291,7 @@ func TestConsensusParamsNotNil(t *testing.T) { app.EndBlock(abci.RequestEndBlock{Height: header.Height}) app.CheckTx(abci.RequestCheckTx{}) app.DeliverTx(abci.RequestDeliverTx{}) - _, _, err := app.Simulate([]byte{}) + _, _, err = app.Simulate([]byte{}) require.NoError(t, err) } From cd5ed77fc6f2bae5d61b4e611159aae885a4b123 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 13 Apr 2022 14:46:43 -0400 Subject: [PATCH 31/58] increase code coverage by covering panics in pruning manager unit tests --- pruning/manager.go | 7 +- pruning/manager_test.go | 68 +++++++ pruning/mock/db_mock.go | 420 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 489 insertions(+), 6 deletions(-) create mode 100644 pruning/mock/db_mock.go diff --git a/pruning/manager.go b/pruning/manager.go index cd13365f1962..019c11f38be8 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -128,11 +128,6 @@ func (m *Manager) HandleHeight(previousHeight int64) int64 { defer m.pruneHeightsMx.Unlock() m.pruneHeights = append(m.pruneHeights, pruneHeight) - - // flush the updates to disk so that they are not lost if crash happens. - if err := m.db.SetSync(pruneHeightsKey, int64SliceToBytes(m.pruneHeights)); err != nil { - panic(err) - } return pruneHeight } } @@ -225,10 +220,10 @@ func loadPruningHeights(db dbm.DB) ([]int64, error) { func loadPruningSnapshotHeights(db dbm.DB) (*list.List, error) { bz, err := db.Get(pruneSnapshotHeightsKey) - pruneSnapshotHeights := list.New() if err != nil { return nil, fmt.Errorf("failed to get post-snapshot pruned heights: %w", err) } + pruneSnapshotHeights := list.New() if len(bz) == 0 { return pruneSnapshotHeights, nil } diff --git a/pruning/manager_test.go b/pruning/manager_test.go index f00171c673f4..fc73e65b480f 100644 --- a/pruning/manager_test.go +++ b/pruning/manager_test.go @@ -2,18 +2,23 @@ package pruning_test import ( "container/list" + "errors" "fmt" "testing" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" db "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/pruning" + "github.com/cosmos/cosmos-sdk/pruning/mock" "github.com/cosmos/cosmos-sdk/pruning/types" ) +const dbErr = "db error" + func TestNewManager(t *testing.T) { manager := pruning.NewManager(db.NewMemDB(), log.NewNopLogger()) @@ -306,6 +311,29 @@ func TestHandleHeight_FlushLoadFromDisk(t *testing.T) { } } +func TestHandleHeight_DbErr_Panic(t *testing.T) { + + ctrl := gomock.NewController(t) + + // Setup + dbMock := mock.NewMockDB(ctrl) + + dbMock.EXPECT().SetSync(gomock.Any(), gomock.Any()).Return(errors.New(dbErr)).Times(1) + + manager := pruning.NewManager(dbMock, log.NewNopLogger()) + manager.SetOptions(types.NewPruningOptions(types.PruningEverything)) + require.NotNil(t, manager) + + defer func() { + if r := recover(); r == nil { + t.Fail() + } + }() + + manager.HandleHeight(10) +} + + func TestHandleHeightSnapshot_FlushLoadFromDisk(t *testing.T) { loadedHeightsMirror := []int64{} @@ -339,6 +367,28 @@ func TestHandleHeightSnapshot_FlushLoadFromDisk(t *testing.T) { } } +func TestHandleHeightSnapshot_DbErr_Panic(t *testing.T) { + + ctrl := gomock.NewController(t) + + // Setup + dbMock := mock.NewMockDB(ctrl) + + dbMock.EXPECT().SetSync(gomock.Any(), gomock.Any()).Return(errors.New(dbErr)).Times(1) + + manager := pruning.NewManager(dbMock, log.NewNopLogger()) + manager.SetOptions(types.NewPruningOptions(types.PruningEverything)) + require.NotNil(t, manager) + + defer func() { + if r := recover(); r == nil { + t.Fail() + } + }() + + manager.HandleHeightSnapshot(10) +} + func TestFlushLoad(t *testing.T) { db := db.NewMemDB() manager := pruning.NewManager(db, log.NewNopLogger()) @@ -467,3 +517,21 @@ func TestLoadPruningHeights_PruneNothing(t *testing.T) { require.Nil(t, manager.LoadPruningHeights(db.NewMemDB())) } + +func TestGetFlushAndResetPruningHeights_DbErr_Panic(t *testing.T) { + + ctrl := gomock.NewController(t) + + // Setup + dbMock := mock.NewMockDB(ctrl) + + dbMock.EXPECT().SetSync(gomock.Any(), gomock.Any()).Return(errors.New(dbErr)).Times(1) + + manager := pruning.NewManager(dbMock, log.NewNopLogger()) + manager.SetOptions(types.NewPruningOptions(types.PruningEverything)) + require.NotNil(t, manager) + + heights, err := manager.GetFlushAndResetPruningHeights() + require.Error(t, err) + require.Nil(t, heights) +} diff --git a/pruning/mock/db_mock.go b/pruning/mock/db_mock.go new file mode 100644 index 000000000000..c8d2e2c343a1 --- /dev/null +++ b/pruning/mock/db_mock.go @@ -0,0 +1,420 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: /home/roman/projects/cosmos-sdk/vendor/github.com/tendermint/tm-db/types.go + +// Package mock_db is a generated GoMock package. +package mock + +import ( + reflect "reflect" + + db "github.com/tendermint/tm-db" + gomock "github.com/golang/mock/gomock" +) + +// MockDB is a mock of DB interface. +type MockDB struct { + ctrl *gomock.Controller + recorder *MockDBMockRecorder +} + +// MockDBMockRecorder is the mock recorder for MockDB. +type MockDBMockRecorder struct { + mock *MockDB +} + +// NewMockDB creates a new mock instance. +func NewMockDB(ctrl *gomock.Controller) *MockDB { + mock := &MockDB{ctrl: ctrl} + mock.recorder = &MockDBMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDB) EXPECT() *MockDBMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockDB) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockDBMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockDB)(nil).Close)) +} + +// Delete mocks base method. +func (m *MockDB) Delete(arg0 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockDBMockRecorder) Delete(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDB)(nil).Delete), arg0) +} + +// DeleteSync mocks base method. +func (m *MockDB) DeleteSync(arg0 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteSync", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteSync indicates an expected call of DeleteSync. +func (mr *MockDBMockRecorder) DeleteSync(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSync", reflect.TypeOf((*MockDB)(nil).DeleteSync), arg0) +} + +// Get mocks base method. +func (m *MockDB) Get(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockDBMockRecorder) Get(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDB)(nil).Get), arg0) +} + +// Has mocks base method. +func (m *MockDB) Has(key []byte) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Has", key) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Has indicates an expected call of Has. +func (mr *MockDBMockRecorder) Has(key interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Has", reflect.TypeOf((*MockDB)(nil).Has), key) +} + +// Iterator mocks base method. +func (m *MockDB) Iterator(start, end []byte) (db.Iterator, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Iterator", start, end) + ret0, _ := ret[0].(db.Iterator) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Iterator indicates an expected call of Iterator. +func (mr *MockDBMockRecorder) Iterator(start, end interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterator", reflect.TypeOf((*MockDB)(nil).Iterator), start, end) +} + +// NewBatch mocks base method. +func (m *MockDB) NewBatch() db.Batch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewBatch") + ret0, _ := ret[0].(db.Batch) + return ret0 +} + +// NewBatch indicates an expected call of NewBatch. +func (mr *MockDBMockRecorder) NewBatch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBatch", reflect.TypeOf((*MockDB)(nil).NewBatch)) +} + +// Print mocks base method. +func (m *MockDB) Print() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Print") + ret0, _ := ret[0].(error) + return ret0 +} + +// Print indicates an expected call of Print. +func (mr *MockDBMockRecorder) Print() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Print", reflect.TypeOf((*MockDB)(nil).Print)) +} + +// ReverseIterator mocks base method. +func (m *MockDB) ReverseIterator(start, end []byte) (db.Iterator, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReverseIterator", start, end) + ret0, _ := ret[0].(db.Iterator) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReverseIterator indicates an expected call of ReverseIterator. +func (mr *MockDBMockRecorder) ReverseIterator(start, end interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReverseIterator", reflect.TypeOf((*MockDB)(nil).ReverseIterator), start, end) +} + +// Set mocks base method. +func (m *MockDB) Set(arg0, arg1 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Set", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Set indicates an expected call of Set. +func (mr *MockDBMockRecorder) Set(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockDB)(nil).Set), arg0, arg1) +} + +// SetSync mocks base method. +func (m *MockDB) SetSync(arg0, arg1 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetSync", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetSync indicates an expected call of SetSync. +func (mr *MockDBMockRecorder) SetSync(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSync", reflect.TypeOf((*MockDB)(nil).SetSync), arg0, arg1) +} + +// Stats mocks base method. +func (m *MockDB) Stats() map[string]string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stats") + ret0, _ := ret[0].(map[string]string) + return ret0 +} + +// Stats indicates an expected call of Stats. +func (mr *MockDBMockRecorder) Stats() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stats", reflect.TypeOf((*MockDB)(nil).Stats)) +} + +// MockBatch is a mock of Batch interface. +type MockBatch struct { + ctrl *gomock.Controller + recorder *MockBatchMockRecorder +} + +// MockBatchMockRecorder is the mock recorder for MockBatch. +type MockBatchMockRecorder struct { + mock *MockBatch +} + +// NewMockBatch creates a new mock instance. +func NewMockBatch(ctrl *gomock.Controller) *MockBatch { + mock := &MockBatch{ctrl: ctrl} + mock.recorder = &MockBatchMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBatch) EXPECT() *MockBatchMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockBatch) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockBatchMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockBatch)(nil).Close)) +} + +// Delete mocks base method. +func (m *MockBatch) Delete(key []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", key) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockBatchMockRecorder) Delete(key interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockBatch)(nil).Delete), key) +} + +// Set mocks base method. +func (m *MockBatch) Set(key, value []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Set", key, value) + ret0, _ := ret[0].(error) + return ret0 +} + +// Set indicates an expected call of Set. +func (mr *MockBatchMockRecorder) Set(key, value interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockBatch)(nil).Set), key, value) +} + +// Write mocks base method. +func (m *MockBatch) Write() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Write") + ret0, _ := ret[0].(error) + return ret0 +} + +// Write indicates an expected call of Write. +func (mr *MockBatchMockRecorder) Write() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockBatch)(nil).Write)) +} + +// WriteSync mocks base method. +func (m *MockBatch) WriteSync() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WriteSync") + ret0, _ := ret[0].(error) + return ret0 +} + +// WriteSync indicates an expected call of WriteSync. +func (mr *MockBatchMockRecorder) WriteSync() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteSync", reflect.TypeOf((*MockBatch)(nil).WriteSync)) +} + +// MockIterator is a mock of Iterator interface. +type MockIterator struct { + ctrl *gomock.Controller + recorder *MockIteratorMockRecorder +} + +// MockIteratorMockRecorder is the mock recorder for MockIterator. +type MockIteratorMockRecorder struct { + mock *MockIterator +} + +// NewMockIterator creates a new mock instance. +func NewMockIterator(ctrl *gomock.Controller) *MockIterator { + mock := &MockIterator{ctrl: ctrl} + mock.recorder = &MockIteratorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockIterator) EXPECT() *MockIteratorMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockIterator) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockIteratorMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockIterator)(nil).Close)) +} + +// Domain mocks base method. +func (m *MockIterator) Domain() ([]byte, []byte) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Domain") + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].([]byte) + return ret0, ret1 +} + +// Domain indicates an expected call of Domain. +func (mr *MockIteratorMockRecorder) Domain() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Domain", reflect.TypeOf((*MockIterator)(nil).Domain)) +} + +// Error mocks base method. +func (m *MockIterator) Error() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Error") + ret0, _ := ret[0].(error) + return ret0 +} + +// Error indicates an expected call of Error. +func (mr *MockIteratorMockRecorder) Error() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockIterator)(nil).Error)) +} + +// Key mocks base method. +func (m *MockIterator) Key() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Key") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// Key indicates an expected call of Key. +func (mr *MockIteratorMockRecorder) Key() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Key", reflect.TypeOf((*MockIterator)(nil).Key)) +} + +// Next mocks base method. +func (m *MockIterator) Next() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Next") +} + +// Next indicates an expected call of Next. +func (mr *MockIteratorMockRecorder) Next() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Next", reflect.TypeOf((*MockIterator)(nil).Next)) +} + +// Valid mocks base method. +func (m *MockIterator) Valid() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Valid") + ret0, _ := ret[0].(bool) + return ret0 +} + +// Valid indicates an expected call of Valid. +func (mr *MockIteratorMockRecorder) Valid() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Valid", reflect.TypeOf((*MockIterator)(nil).Valid)) +} + +// Value mocks base method. +func (m *MockIterator) Value() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Value") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// Value indicates an expected call of Value. +func (mr *MockIteratorMockRecorder) Value() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Value", reflect.TypeOf((*MockIterator)(nil).Value)) +} From 1a6243548f9b74fb7253fdc6d893276152fceb77 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 13 Apr 2022 15:33:32 -0400 Subject: [PATCH 32/58] increase coverage in pruning options --- pruning/types/options.go | 6 +----- pruning/types/options_test.go | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pruning/types/options.go b/pruning/types/options.go index a8479e97ffc5..229dbed984d5 100644 --- a/pruning/types/options.go +++ b/pruning/types/options.go @@ -78,13 +78,9 @@ func NewPruningOptions(pruningStrategy PruningStrategy) PruningOptions { Interval: 0, Strategy: PruningNothing, } - case PruningCustom: - return PruningOptions{ - Strategy: PruningCustom, - } default: return PruningOptions{ - Strategy: PruningUndefined, + Strategy: PruningCustom, } } } diff --git a/pruning/types/options_test.go b/pruning/types/options_test.go index 6fb0dbf8da59..3e82320c8701 100644 --- a/pruning/types/options_test.go +++ b/pruning/types/options_test.go @@ -14,6 +14,7 @@ func TestPruningOptions_Validate(t *testing.T) { {NewPruningOptions(PruningDefault), nil}, {NewPruningOptions(PruningEverything), nil}, {NewPruningOptions(PruningNothing), nil}, + {NewPruningOptions(PruningCustom), ErrPruningIntervalZero}, {NewCustomPruningOptions(2, 10), nil}, {NewCustomPruningOptions(100, 15), nil}, {NewCustomPruningOptions(1, 10), ErrPruningKeepRecentTooSmall}, @@ -28,6 +29,24 @@ func TestPruningOptions_Validate(t *testing.T) { } } +func TestPruningOptions_GetStrategy(t *testing.T) { + testCases := []struct { + opts PruningOptions + expectedStrategy PruningStrategy + }{ + {NewPruningOptions(PruningDefault), PruningDefault}, + {NewPruningOptions(PruningEverything), PruningEverything}, + {NewPruningOptions(PruningNothing), PruningNothing}, + {NewPruningOptions(PruningCustom), PruningCustom}, + {NewCustomPruningOptions(2, 10), PruningCustom}, + } + + for _, tc := range testCases { + actualStrategy := tc.opts.GetPruningStrategy() + require.Equal(t, tc.expectedStrategy, actualStrategy) + } +} + func TestNewPruningOptionsFromString(t *testing.T) { testCases := []struct { optString string From 94001868efb1132d614ab7e31da0a7b6fb8c8be2 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 13 Apr 2022 19:40:31 -0400 Subject: [PATCH 33/58] NegativeHeightsError implementation and format --- pruning/export_test.go | 2 -- pruning/manager.go | 44 ++++++++++++++++----------- pruning/manager_test.go | 7 ++--- pruning/mock/db_mock.go | 2 +- pruning/types/options_test.go | 4 +-- store/v2alpha1/mem/store.go | 2 +- store/v2alpha1/multi/snapshot_test.go | 2 +- store/v2alpha1/multi/store.go | 2 +- store/v2alpha1/multi/store_test.go | 2 +- store/v2alpha1/transient/store.go | 2 +- store/v2alpha1/types.go | 12 ++++---- types/store.go | 2 +- 12 files changed, 44 insertions(+), 39 deletions(-) diff --git a/pruning/export_test.go b/pruning/export_test.go index 51b1c10462a9..7856e02139a3 100644 --- a/pruning/export_test.go +++ b/pruning/export_test.go @@ -1,7 +1,5 @@ package pruning -const ErrNegativeHeightsFmt = errNegativeHeightsFmt - var ( PruneHeightsKey = pruneHeightsKey PruneSnapshotHeightsKey = pruneSnapshotHeightsKey diff --git a/pruning/manager.go b/pruning/manager.go index 019c11f38be8..a8f9e9e628a5 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -13,24 +13,33 @@ import ( ) type Manager struct { - db dbm.DB - logger log.Logger - opts types.PruningOptions - snapshotInterval uint64 - pruneHeights []int64 + db dbm.DB + logger log.Logger + opts types.PruningOptions + snapshotInterval uint64 + pruneHeights []int64 // Although pruneHeights happen in the same goroutine with the normal execution, // we sync access to them to avoid soundness issues in the future if concurrency pattern changes. - pruneHeightsMx sync.Mutex + pruneHeightsMx sync.Mutex // These are the heights that are multiples of snapshotInterval and kept for state sync snapshots. // The heights are added to this list to be pruned when a snapshot is complete. - pruneSnapshotHeights *list.List + pruneSnapshotHeights *list.List // Snapshots are taken in a separate goroutine fromt the regular execution // and can be delivered asynchrounously via HandleHeightSnapshot. - // Therefore, we sync access to pruneSnapshotHeights with this mutex. + // Therefore, we sync access to pruneSnapshotHeights with this mutex. pruneSnapshotHeightsMx sync.Mutex } -const errNegativeHeightsFmt = "failed to get pruned heights: %d" +// NegativeHeightsError is returned when a negative height is provided to the manager. +type NegativeHeightsError struct { + Height int64 +} + +var _ error = &NegativeHeightsError{} + +func (e *NegativeHeightsError) Error() string { + return fmt.Sprintf("failed to get pruned heights: %d", e.Height) +} var ( pruneHeightsKey = []byte("s/pruneheights") @@ -39,11 +48,11 @@ var ( func NewManager(db dbm.DB, logger log.Logger) *Manager { return &Manager{ - db: db, - logger: logger, - opts: types.NewPruningOptions(types.PruningNothing), - pruneHeights: []int64{}, - pruneSnapshotHeights: list.New(), + db: db, + logger: logger, + opts: types.NewPruningOptions(types.PruningNothing), + pruneHeights: []int64{}, + pruneSnapshotHeights: list.New(), } } @@ -136,7 +145,7 @@ func (m *Manager) HandleHeight(previousHeight int64) int64 { // HandleHeightSnapshot persists the snapshot height to be pruned at the next appropriate // height defined by the pruning strategy. Flushes the update to disk and panics if the flush fails -// The input height must be greater than 0 and pruning strategy any but pruning nothing. +// The input height must be greater than 0 and pruning strategy any but pruning nothing. // If one of these conditions is not met, this function does nothing. func (m *Manager) HandleHeightSnapshot(height int64) { if m.opts.GetPruningStrategy() == types.PruningNothing || height <= 0 { @@ -207,7 +216,7 @@ func loadPruningHeights(db dbm.DB) ([]int64, error) { for offset < len(bz) { h := int64(binary.BigEndian.Uint64(bz[offset : offset+8])) if h < 0 { - return []int64{}, fmt.Errorf(errNegativeHeightsFmt, h) + return []int64{}, &NegativeHeightsError{Height: h} } prunedHeights[i] = h @@ -232,9 +241,8 @@ func loadPruningSnapshotHeights(db dbm.DB) (*list.List, error) { for offset < len(bz) { h := int64(binary.BigEndian.Uint64(bz[offset : offset+8])) if h < 0 { - return pruneSnapshotHeights, fmt.Errorf(errNegativeHeightsFmt, h) + return nil, &NegativeHeightsError{Height: h} } - pruneSnapshotHeights.PushBack(h) i++ offset += 8 diff --git a/pruning/manager_test.go b/pruning/manager_test.go index fc73e65b480f..1bb712a8a369 100644 --- a/pruning/manager_test.go +++ b/pruning/manager_test.go @@ -333,7 +333,6 @@ func TestHandleHeight_DbErr_Panic(t *testing.T) { manager.HandleHeight(10) } - func TestHandleHeightSnapshot_FlushLoadFromDisk(t *testing.T) { loadedHeightsMirror := []int64{} @@ -455,7 +454,7 @@ func TestLoadPruningHeights(t *testing.T) { }{ "negative pruningHeight - error": { flushedPruningHeights: []int64{10, 0, -1}, - expectedResult: fmt.Errorf(pruning.ErrNegativeHeightsFmt, -1), + expectedResult: &pruning.NegativeHeightsError{Height: -1}, }, "negative snapshotPruningHeight - error": { getFlushedPruningSnapshotHeights: func() *list.List { @@ -465,7 +464,7 @@ func TestLoadPruningHeights(t *testing.T) { l.PushBack(int64(3)) return l }, - expectedResult: fmt.Errorf(pruning.ErrNegativeHeightsFmt, -2), + expectedResult: &pruning.NegativeHeightsError{Height: -2}, }, "both have negative - pruningHeight error": { flushedPruningHeights: []int64{10, 0, -1}, @@ -476,7 +475,7 @@ func TestLoadPruningHeights(t *testing.T) { l.PushBack(int64(3)) return l }, - expectedResult: fmt.Errorf(pruning.ErrNegativeHeightsFmt, -1), + expectedResult: &pruning.NegativeHeightsError{Height: -1}, }, "both non-negative - success": { flushedPruningHeights: []int64{10, 0, 3}, diff --git a/pruning/mock/db_mock.go b/pruning/mock/db_mock.go index c8d2e2c343a1..fb6ee740b972 100644 --- a/pruning/mock/db_mock.go +++ b/pruning/mock/db_mock.go @@ -7,8 +7,8 @@ package mock import ( reflect "reflect" - db "github.com/tendermint/tm-db" gomock "github.com/golang/mock/gomock" + db "github.com/tendermint/tm-db" ) // MockDB is a mock of DB interface. diff --git a/pruning/types/options_test.go b/pruning/types/options_test.go index 3e82320c8701..abc6bf39e2a3 100644 --- a/pruning/types/options_test.go +++ b/pruning/types/options_test.go @@ -31,7 +31,7 @@ func TestPruningOptions_Validate(t *testing.T) { func TestPruningOptions_GetStrategy(t *testing.T) { testCases := []struct { - opts PruningOptions + opts PruningOptions expectedStrategy PruningStrategy }{ {NewPruningOptions(PruningDefault), PruningDefault}, @@ -50,7 +50,7 @@ func TestPruningOptions_GetStrategy(t *testing.T) { func TestNewPruningOptionsFromString(t *testing.T) { testCases := []struct { optString string - expect PruningOptions + expect PruningOptions }{ {PruningOptionDefault, NewPruningOptions(PruningDefault)}, {PruningOptionEverything, NewPruningOptions(PruningEverything)}, diff --git a/store/v2alpha1/mem/store.go b/store/v2alpha1/mem/store.go index 1b7fca28e043..3c8fa82bbaba 100644 --- a/store/v2alpha1/mem/store.go +++ b/store/v2alpha1/mem/store.go @@ -3,9 +3,9 @@ package mem import ( dbm "github.com/cosmos/cosmos-sdk/db" "github.com/cosmos/cosmos-sdk/db/memdb" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/store/v2alpha1/dbadapter" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var ( diff --git a/store/v2alpha1/multi/snapshot_test.go b/store/v2alpha1/multi/snapshot_test.go index 48b8b4160875..77637910e768 100644 --- a/store/v2alpha1/multi/snapshot_test.go +++ b/store/v2alpha1/multi/snapshot_test.go @@ -17,9 +17,9 @@ import ( dbm "github.com/cosmos/cosmos-sdk/db" "github.com/cosmos/cosmos-sdk/db/memdb" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/snapshots" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/types" ) diff --git a/store/v2alpha1/multi/store.go b/store/v2alpha1/multi/store.go index 983f132fcc1a..3bf6c73096ab 100644 --- a/store/v2alpha1/multi/store.go +++ b/store/v2alpha1/multi/store.go @@ -13,6 +13,7 @@ import ( dbm "github.com/cosmos/cosmos-sdk/db" prefixdb "github.com/cosmos/cosmos-sdk/db/prefix" util "github.com/cosmos/cosmos-sdk/internal" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps" "github.com/cosmos/cosmos-sdk/store/listenkv" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -22,7 +23,6 @@ import ( "github.com/cosmos/cosmos-sdk/store/v2alpha1/smt" "github.com/cosmos/cosmos-sdk/store/v2alpha1/transient" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/types/kv" ) diff --git a/store/v2alpha1/multi/store_test.go b/store/v2alpha1/multi/store_test.go index 0598b1f035bc..cdcbbd2fb98b 100644 --- a/store/v2alpha1/multi/store_test.go +++ b/store/v2alpha1/multi/store_test.go @@ -13,8 +13,8 @@ import ( codecTypes "github.com/cosmos/cosmos-sdk/codec/types" dbm "github.com/cosmos/cosmos-sdk/db" "github.com/cosmos/cosmos-sdk/db/memdb" - types "github.com/cosmos/cosmos-sdk/store/v2alpha1" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + types "github.com/cosmos/cosmos-sdk/store/v2alpha1" "github.com/cosmos/cosmos-sdk/types/kv" ) diff --git a/store/v2alpha1/transient/store.go b/store/v2alpha1/transient/store.go index 7a3286989ee9..586cc4e9d36e 100644 --- a/store/v2alpha1/transient/store.go +++ b/store/v2alpha1/transient/store.go @@ -3,9 +3,9 @@ package transient import ( dbm "github.com/cosmos/cosmos-sdk/db" "github.com/cosmos/cosmos-sdk/db/memdb" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/store/v2alpha1/dbadapter" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" ) var ( diff --git a/store/v2alpha1/types.go b/store/v2alpha1/types.go index 176e314c5a8f..44c97ff4f52d 100644 --- a/store/v2alpha1/types.go +++ b/store/v2alpha1/types.go @@ -9,12 +9,12 @@ import ( // Re-export relevant original store types type ( - StoreKey = v1.StoreKey - StoreType = v1.StoreType - CommitID = v1.CommitID - StoreUpgrades = v1.StoreUpgrades - StoreRename = v1.StoreRename - Iterator = v1.Iterator + StoreKey = v1.StoreKey + StoreType = v1.StoreType + CommitID = v1.CommitID + StoreUpgrades = v1.StoreUpgrades + StoreRename = v1.StoreRename + Iterator = v1.Iterator TraceContext = v1.TraceContext WriteListener = v1.WriteListener diff --git a/types/store.go b/types/store.go index d654ef3e5d21..2fafdae29531 100644 --- a/types/store.go +++ b/types/store.go @@ -5,9 +5,9 @@ import ( "sort" "strings" - "github.com/cosmos/cosmos-sdk/store/types" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/types/kv" ) From 94739dc4b06fb58416d0a58e4b721c6231967624 Mon Sep 17 00:00:00 2001 From: Roman <34196718+p0mvn@users.noreply.github.com> Date: Wed, 13 Apr 2022 16:41:53 -0700 Subject: [PATCH 34/58] Update pruning/README.md Co-authored-by: Peter Bourgon --- pruning/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pruning/README.md b/pruning/README.md index 91b9435bec2b..3382b17d828c 100644 --- a/pruning/README.md +++ b/pruning/README.md @@ -15,7 +15,7 @@ pruning = "< strategy >" # where the options are: - `everything`: 2 latest states will be kept; pruning at 10 block intervals. - `custom`: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' -If no strategy is given to `Baseapp`, `nothing` is selected. However, we perform validation on the cli layer to require these to be always set in the config file. +If no strategy is given to the BaseApp, `nothing` is selected. However, we perform validation on the CLI layer to require these to be always set in the config file. ## Custom Pruning From 631a756b9a307854d60644222d1a6e0b14c0ef1b Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 13 Apr 2022 19:44:40 -0400 Subject: [PATCH 35/58] update order of declarations in pruning manager --- pruning/manager.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pruning/manager.go b/pruning/manager.go index a8f9e9e628a5..d894cdf462fb 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -17,17 +17,17 @@ type Manager struct { logger log.Logger opts types.PruningOptions snapshotInterval uint64 - pruneHeights []int64 // Although pruneHeights happen in the same goroutine with the normal execution, // we sync access to them to avoid soundness issues in the future if concurrency pattern changes. - pruneHeightsMx sync.Mutex - // These are the heights that are multiples of snapshotInterval and kept for state sync snapshots. - // The heights are added to this list to be pruned when a snapshot is complete. - pruneSnapshotHeights *list.List + pruneHeightsMx sync.Mutex + pruneHeights []int64 // Snapshots are taken in a separate goroutine fromt the regular execution // and can be delivered asynchrounously via HandleHeightSnapshot. - // Therefore, we sync access to pruneSnapshotHeights with this mutex. + // Therefore, we sync access to pruneSnapshotHeights with this mutex. pruneSnapshotHeightsMx sync.Mutex + // These are the heights that are multiples of snapshotInterval and kept for state sync snapshots. + // The heights are added to this list to be pruned when a snapshot is complete. + pruneSnapshotHeights *list.List } // NegativeHeightsError is returned when a negative height is provided to the manager. From 5a504afeb1c5ffafb0a9c04f6eda12dd5c4f3b96 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 13 Apr 2022 19:54:00 -0400 Subject: [PATCH 36/58] new goroutine is handled by SnapshotIfApplicable caller --- baseapp/abci.go | 2 +- snapshots/manager.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index 1732abdc3e73..9061170862d2 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -338,7 +338,7 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { app.halt() } - app.snapshotManager.SnapshotIfApplicable(header.Height) + go app.snapshotManager.SnapshotIfApplicable(header.Height) return abci.ResponseCommit{ Data: commitID.Hash, diff --git a/snapshots/manager.go b/snapshots/manager.go index e614be076977..72f1c15b4b76 100644 --- a/snapshots/manager.go +++ b/snapshots/manager.go @@ -413,7 +413,7 @@ func IsFormatSupported(snapshotter types.ExtensionSnapshotter, format uint32) bo } // SnapshotIfApplicable takes a snapshot of the current state if we are on a snapshot height. -// It also prunes any old snapshots. The snapshotting and pruning happen in separate goroutines. +// It also prunes any old snapshots. func (m *Manager) SnapshotIfApplicable(height int64) { if m == nil { return @@ -422,7 +422,7 @@ func (m *Manager) SnapshotIfApplicable(height int64) { m.logger.Debug("snapshot is skipped", "height", height) return } - go m.snapshot(height) + m.snapshot(height) } // shouldTakeSnapshot returns true is snapshot should be taken at height. From 2893b32bd6d933a646208863589ae11e82c4cf0e Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 13 Apr 2022 21:33:09 -0400 Subject: [PATCH 37/58] synchronous SnapshotIfApplicable --- baseapp/abci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index 9061170862d2..1732abdc3e73 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -338,7 +338,7 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { app.halt() } - go app.snapshotManager.SnapshotIfApplicable(header.Height) + app.snapshotManager.SnapshotIfApplicable(header.Height) return abci.ResponseCommit{ Data: commitID.Hash, From 25b4bd1f17c04137dfb26a341451ca0cd7897053 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 13 Apr 2022 22:16:23 -0400 Subject: [PATCH 38/58] return a copy of pruneHeights in GetFlushAndResetPruningHeights --- pruning/manager.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pruning/manager.go b/pruning/manager.go index d894cdf462fb..af0fd60be8ce 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -75,14 +75,15 @@ func (m *Manager) GetFlushAndResetPruningHeights() ([]int64, error) { m.pruneHeightsMx.Lock() defer m.pruneHeightsMx.Unlock() - pruningHeights := m.pruneHeights - // flush the updates to disk so that it is not lost if crash happens. - if err := m.db.SetSync(pruneHeightsKey, int64SliceToBytes(pruningHeights)); err != nil { + if err := m.db.SetSync(pruneHeightsKey, int64SliceToBytes(m.pruneHeights)); err != nil { return nil, err } - m.pruneHeights = make([]int64, 0, m.opts.Interval) + // Return a copy to prevent data races. + pruningHeights := make([]int64, len(m.pruneHeights)) + copy(pruningHeights, m.pruneHeights) + m.pruneHeights = m.pruneHeights[:0] return pruningHeights, nil } From 7f610e1aaa22bfc0b40cf5b519ab208c737a724d Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 13 Apr 2022 22:24:24 -0400 Subject: [PATCH 39/58] godoc for pruning manager --- pruning/manager.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pruning/manager.go b/pruning/manager.go index af0fd60be8ce..8a69429af9ec 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -12,6 +12,9 @@ import ( "github.com/cosmos/cosmos-sdk/pruning/types" ) +// Manager is an abstraction to handle the logic needed for +// determinging when to prune old heights of the store +// based on the strategy described by the pruning options. type Manager struct { db dbm.DB logger log.Logger @@ -46,6 +49,10 @@ var ( pruneSnapshotHeightsKey = []byte("s/pruneSnheights") ) +// NewManager returns a new Manager with the given db and logger. +// The retuned manager uses a pruning strategy of "nothing" which +// keeps all heights. Users of the Manager may change the strategy +// by calling SetOptions. func NewManager(db dbm.DB, logger log.Logger) *Manager { return &Manager{ db: db, From 9c92dc47ee018287c8b38be603e9c447654c8a42 Mon Sep 17 00:00:00 2001 From: Roman <34196718+p0mvn@users.noreply.github.com> Date: Thu, 14 Apr 2022 06:18:38 -0700 Subject: [PATCH 40/58] Update error message in baseapp/baseapp.go Co-authored-by: Aleksandr Bezobchuk --- baseapp/baseapp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 429321f9dcf5..fb90abd924dc 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -310,7 +310,7 @@ func (app *BaseApp) Init() error { rms, ok := app.cms.(*rootmulti.Store) if !ok { - return errors.New("rootmulti store is required") + return fmt.Errorf("invalid commit multi-store; expected %T, got: %T", &rootmulti.Store{}, app.cms) } return rms.GetPruning().Validate() } From 8ef356b80e580e88c57cd1b7cf339f2d6a710c81 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 14 Apr 2022 09:21:54 -0400 Subject: [PATCH 41/58] sdk import in util_test.go --- store/types/utils_test.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/store/types/utils_test.go b/store/types/utils_test.go index 7af25af15f95..a13a2d9a5a55 100644 --- a/store/types/utils_test.go +++ b/store/types/utils_test.go @@ -9,17 +9,17 @@ import ( dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/store/rootmulti" - "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/store/types" ) -func initTestStores(t *testing.T) (types.KVStore, types.KVStore) { +func initTestStores(t *testing.T) (sdk.KVStore, sdk.KVStore) { db := dbm.NewMemDB() ms := rootmulti.NewStore(db, log.NewNopLogger()) - key1 := types.NewKVStoreKey("store1") - key2 := types.NewKVStoreKey("store2") - require.NotPanics(t, func() { ms.MountStoreWithDB(key1, types.StoreTypeIAVL, db) }) - require.NotPanics(t, func() { ms.MountStoreWithDB(key2, types.StoreTypeIAVL, db) }) + key1 := sdk.NewKVStoreKey("store1") + key2 := sdk.NewKVStoreKey("store2") + require.NotPanics(t, func() { ms.MountStoreWithDB(key1, sdk.StoreTypeIAVL, db) }) + require.NotPanics(t, func() { ms.MountStoreWithDB(key2, sdk.StoreTypeIAVL, db) }) require.NoError(t, ms.LoadLatestVersion()) return ms.GetKVStore(key1), ms.GetKVStore(key2) } @@ -32,27 +32,27 @@ func TestDiffKVStores(t *testing.T) { store1.Set(k1, v1) store2.Set(k1, v1) - kvAs, kvBs := types.DiffKVStores(store1, store2, nil) + kvAs, kvBs := sdk.DiffKVStores(store1, store2, nil) require.Equal(t, 0, len(kvAs)) require.Equal(t, len(kvAs), len(kvBs)) // delete k1 from store2, which is now empty store2.Delete(k1) - kvAs, kvBs = types.DiffKVStores(store1, store2, nil) + kvAs, kvBs = sdk.DiffKVStores(store1, store2, nil) require.Equal(t, 1, len(kvAs)) require.Equal(t, len(kvAs), len(kvBs)) // set k1 in store2, different value than what store1 holds for k1 v2 := []byte("v2") store2.Set(k1, v2) - kvAs, kvBs = types.DiffKVStores(store1, store2, nil) + kvAs, kvBs = sdk.DiffKVStores(store1, store2, nil) require.Equal(t, 1, len(kvAs)) require.Equal(t, len(kvAs), len(kvBs)) // add k2 to store2 k2 := []byte("k2") store2.Set(k2, v2) - kvAs, kvBs = types.DiffKVStores(store1, store2, nil) + kvAs, kvBs = sdk.DiffKVStores(store1, store2, nil) require.Equal(t, 2, len(kvAs)) require.Equal(t, len(kvAs), len(kvBs)) @@ -66,7 +66,7 @@ func TestDiffKVStores(t *testing.T) { k1Prefixed := append(prefix, k1...) store1.Set(k1Prefixed, v1) store2.Set(k1Prefixed, v2) - kvAs, kvBs = types.DiffKVStores(store1, store2, [][]byte{prefix}) + kvAs, kvBs = sdk.DiffKVStores(store1, store2, [][]byte{prefix}) require.Equal(t, 0, len(kvAs)) require.Equal(t, len(kvAs), len(kvBs)) } @@ -74,16 +74,16 @@ func TestDiffKVStores(t *testing.T) { func TestPrefixEndBytes(t *testing.T) { t.Parallel() bs1 := []byte{0x23, 0xA5, 0x06} - require.True(t, bytes.Equal([]byte{0x23, 0xA5, 0x07}, types.PrefixEndBytes(bs1))) + require.True(t, bytes.Equal([]byte{0x23, 0xA5, 0x07}, sdk.PrefixEndBytes(bs1))) bs2 := []byte{0x23, 0xA5, 0xFF} - require.True(t, bytes.Equal([]byte{0x23, 0xA6}, types.PrefixEndBytes(bs2))) - require.Nil(t, types.PrefixEndBytes([]byte{0xFF})) - require.Nil(t, types.PrefixEndBytes(nil)) + require.True(t, bytes.Equal([]byte{0x23, 0xA6}, sdk.PrefixEndBytes(bs2))) + require.Nil(t, sdk.PrefixEndBytes([]byte{0xFF})) + require.Nil(t, sdk.PrefixEndBytes(nil)) } func TestInclusiveEndBytes(t *testing.T) { t.Parallel() - require.True(t, bytes.Equal([]byte{0x00}, types.InclusiveEndBytes(nil))) + require.True(t, bytes.Equal([]byte{0x00}, sdk.InclusiveEndBytes(nil))) bs := []byte("test") - require.True(t, bytes.Equal(append(bs, byte(0x00)), types.InclusiveEndBytes(bs))) + require.True(t, bytes.Equal(append(bs, byte(0x00)), sdk.InclusiveEndBytes(bs))) } From c482cd3baf60c113b7a9491615042eb7055bcbb6 Mon Sep 17 00:00:00 2001 From: Roman <34196718+p0mvn@users.noreply.github.com> Date: Thu, 14 Apr 2022 06:23:49 -0700 Subject: [PATCH 42/58] Apply suggestions from code review in pruning/README.md Co-authored-by: Aleksandr Bezobchuk --- pruning/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pruning/README.md b/pruning/README.md index 3382b17d828c..f7afae8e6ac3 100644 --- a/pruning/README.md +++ b/pruning/README.md @@ -2,14 +2,14 @@ ## Overview -Pruning is the mechanism for deleting old heights from the disk. Depending on the use case, +Pruning is the mechanism for deleting old application heights from the disk. Depending on the use case, nodes may require different pruning strategies. For example, archive nodes must keep all the states and prune nothing. On the other hand, a regular validator node may want to only keep 100 latest heights for performance reasons. ## Strategies -The strategies are configured in `app.toml`: -pruning = "< strategy >" # where the options are: +The strategies are configured in `app.toml`, with the format `pruning = ""` where the options are: + - `default`: only the last 362,880 states(approximately 3.5 weeks worth of state) are kept; pruning at 10 block intervals - `nothing`: all historic states will be saved, nothing will be deleted (i.e. archiving node) - `everything`: 2 latest states will be kept; pruning at 10 block intervals. @@ -23,7 +23,7 @@ These are applied if and only if the pruning strategy is custom: - `pruning-keep-recent`: N means to keep all of the last N states - `pruning-interval`: N means to delete old states from disk every Nth block. -## Relationship to Snapshots +## Relationship to State Sync Snapshots Snapshot settings are optional. However, if set, they have an effect on how pruning is done by persisting the heights that are multiples of `state-sync.snapshot-interval` until after the snapshot is complete. See the "Relationship to Pruning" section in `snapshots/README.md` for more details. From 091061c98a8603fe4ee09e396b569a4e0b5231f1 Mon Sep 17 00:00:00 2001 From: Roman <34196718+p0mvn@users.noreply.github.com> Date: Thu, 14 Apr 2022 06:26:08 -0700 Subject: [PATCH 43/58] Apply more style suggestions from code review Co-authored-by: Aleksandr Bezobchuk --- pruning/export_test.go | 1 - pruning/manager.go | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pruning/export_test.go b/pruning/export_test.go index 7856e02139a3..8c38778bf93d 100644 --- a/pruning/export_test.go +++ b/pruning/export_test.go @@ -4,7 +4,6 @@ var ( PruneHeightsKey = pruneHeightsKey PruneSnapshotHeightsKey = pruneSnapshotHeightsKey - // functions Int64SliceToBytes = int64SliceToBytes ListToBytes = listToBytes LoadPruningHeights = loadPruningHeights diff --git a/pruning/manager.go b/pruning/manager.go index 8a69429af9ec..a12bc3985a1f 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -24,7 +24,7 @@ type Manager struct { // we sync access to them to avoid soundness issues in the future if concurrency pattern changes. pruneHeightsMx sync.Mutex pruneHeights []int64 - // Snapshots are taken in a separate goroutine fromt the regular execution + // Snapshots are taken in a separate goroutine from the regular execution // and can be delivered asynchrounously via HandleHeightSnapshot. // Therefore, we sync access to pruneSnapshotHeights with this mutex. pruneSnapshotHeightsMx sync.Mutex @@ -159,8 +159,10 @@ func (m *Manager) HandleHeightSnapshot(height int64) { if m.opts.GetPruningStrategy() == types.PruningNothing || height <= 0 { return } + m.pruneSnapshotHeightsMx.Lock() defer m.pruneSnapshotHeightsMx.Unlock() + m.logger.Debug("HandleHeightSnapshot", "height", height) m.pruneSnapshotHeights.PushBack(height) From f2ea6b009db6018235046132d6a547235d53f268 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 14 Apr 2022 09:27:14 -0400 Subject: [PATCH 44/58] remove junk test files --- x/genutil/config/priv_validator_key.json | 11 ----------- x/genutil/data/priv_validator_state.json | 5 ----- 2 files changed, 16 deletions(-) delete mode 100644 x/genutil/config/priv_validator_key.json delete mode 100644 x/genutil/data/priv_validator_state.json diff --git a/x/genutil/config/priv_validator_key.json b/x/genutil/config/priv_validator_key.json deleted file mode 100644 index 4f66d79b3376..000000000000 --- a/x/genutil/config/priv_validator_key.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "address": "275D129B1E2A5C4063E42C4E7910B11735510B0A", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "7c8cTnfgfhbsr5UZnSxT3IpP70tgHtKFCbKb7B2IKFo=" - }, - "priv_key": { - "type": "tendermint/PrivKeyEd25519", - "value": "3P9fwMdm03oSPwrWGHO240AgqVCPf3rAARgq1MhUSlHtzxxOd+B+FuyvlRmdLFPcik/vS2Ae0oUJspvsHYgoWg==" - } -} \ No newline at end of file diff --git a/x/genutil/data/priv_validator_state.json b/x/genutil/data/priv_validator_state.json deleted file mode 100644 index 48f3b67e3f85..000000000000 --- a/x/genutil/data/priv_validator_state.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "height": "0", - "round": 0, - "step": 0 -} \ No newline at end of file From 611560f2502948f6c125e2fb1497aa0454858a9d Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 14 Apr 2022 09:49:23 -0400 Subject: [PATCH 45/58] style fix in simapp/simd/cmd/root.go --- simapp/simd/cmd/root.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index bc84fd98c573..c21c43b947f0 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -272,7 +272,8 @@ func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, a snapshotOptions := sdk.NewSnapshotOptions( cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval)), - cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))) + cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent)), + ) return simapp.NewSimApp( logger, db, traceStore, true, skipUpgradeHeights, From 678ed17c06d2f726ea608bfd672af17a38ce6b7f Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 14 Apr 2022 09:53:26 -0400 Subject: [PATCH 46/58] remove unused import in baseapp --- baseapp/baseapp.go | 1 - 1 file changed, 1 deletion(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index fb90abd924dc..2dfa029b7c2f 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -2,7 +2,6 @@ package baseapp import ( "context" - "errors" "fmt" abci "github.com/tendermint/tendermint/abci/types" From dab1ba846d3143cf653ed61f9d74054453350663 Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 16 Apr 2022 13:44:16 -0400 Subject: [PATCH 47/58] resolve merge conflict --- store/rootmulti/store_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 19d460c3d5c4..d1d65770b09f 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -799,7 +799,7 @@ func TestTraceConcurrency(t *testing.T) { func TestCommitOrdered(t *testing.T) { var db dbm.DB = dbm.NewMemDB() - multi := newMultiStoreWithMounts(db, types.PruneNothing) + multi := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) err := multi.LoadLatestVersion() require.Nil(t, err) From d40790c3312429e1b90502a1487700f4ae0b4131 Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 16 Apr 2022 14:15:37 -0400 Subject: [PATCH 48/58] update snapshots/README.md --- snapshots/README.md | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/snapshots/README.md b/snapshots/README.md index 8d7b314d86d8..db0247a61673 100644 --- a/snapshots/README.md +++ b/snapshots/README.md @@ -63,12 +63,26 @@ the `pruning.Manager` to be pruned according to the pruning settings after the n To illustrate, assume that we are currently at height 960 with `pruning-keep-recent = 50`, `pruning-interval = 10`, and `state-sync.snapshot-interval = 100`. Let's assume that -the snapshot that was triggered at height `900` just finishes. Then, we can prune height -`900` right away (that is, when we call `Commit()` at height 960) because it (`900`) is less than `960 - 50 = 910`. +the snapshot that was triggered at height `900` **just finishes**. Then, we can prune height +`900` right away (that is, when we call `Commit()` at height 960 because 900 is less than `960 - 50 = 910`. + +Let's now assume that all conditions stay the same but the snapshot at height 900 is **not complete yet**. +Then, we cannot prune it to avoid deleting a height that is still being snapshotted. Therefore, we keep track +of this height until the snapshot is complete. The height 900 will be pruned at the first height h that satisfied the following conditions: +- the snapshot is complete +- h is a multiple of `pruning-interval` +- snapshot height is less than h - `pruning-keep-recent` + +Note that in both examples, if we let current height = C, and previous height P = C - 1, then for every height h that is: + +P - `pruning-keep-recent` - `pruning-interval` <= h <= P - `pruning-keep-recent` + +we can prune height h. In our first example, all heights 899 - 909 fall in this range and are pruned at height 960 as long as +h is not a snapshot height (E.g. 900). + +That is, we always use current height to determine at which height to prune (960) while we use previous +to determine which heights are to be pruned (959 - 50 - 10 = 899-909 = 959 - 50). -Let's now assume that all settings stay the same but `pruning-keep-recent = 100`. In that case, -we cannot prune height `900` which is greater than `960 - 100 = 850`. As a result, height 900 is persisted until -we can prune it according to the pruning settings. ## Configuration From 54068ced05d5e35d4edb9e4d191b2d2a303a47ba Mon Sep 17 00:00:00 2001 From: Roman <34196718+p0mvn@users.noreply.github.com> Date: Sat, 16 Apr 2022 11:49:06 -0700 Subject: [PATCH 49/58] Update SnapshotIntervalOff comment in snapshots/types/options.go Co-authored-by: Aleksandr Bezobchuk --- snapshots/types/options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapshots/types/options.go b/snapshots/types/options.go index 3a0e05a5a068..1ce39d486adb 100644 --- a/snapshots/types/options.go +++ b/snapshots/types/options.go @@ -10,7 +10,7 @@ type SnapshotOptions struct { KeepRecent uint32 } -// SnapshotIntervalOff represents the snapshot inerval, at which +// SnapshotIntervalOff represents the snapshot interval, at which // no snapshots are taken. const SnapshotIntervalOff uint64 = 0 From 70c2043a021456f435a64571ad9c1b9a14a40305 Mon Sep 17 00:00:00 2001 From: Roman <34196718+p0mvn@users.noreply.github.com> Date: Sat, 16 Apr 2022 11:53:10 -0700 Subject: [PATCH 50/58] Update pruneSnapshotHeightsKey pruning/manager.go Co-authored-by: Aleksandr Bezobchuk --- pruning/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pruning/manager.go b/pruning/manager.go index a12bc3985a1f..480a2192136d 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -46,7 +46,7 @@ func (e *NegativeHeightsError) Error() string { var ( pruneHeightsKey = []byte("s/pruneheights") - pruneSnapshotHeightsKey = []byte("s/pruneSnheights") + pruneSnapshotHeightsKey = []byte("s/prunesnapshotheights") ) // NewManager returns a new Manager with the given db and logger. From f3b548567148b1380cf007f672891310bba3305d Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 16 Apr 2022 14:55:38 -0400 Subject: [PATCH 51/58] update SetSnapshotInterval comment --- snapshots/types/snapshotter.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snapshots/types/snapshotter.go b/snapshots/types/snapshotter.go index cc0a18abd26b..76f800484a49 100644 --- a/snapshots/types/snapshotter.go +++ b/snapshots/types/snapshotter.go @@ -18,7 +18,8 @@ type Snapshotter interface { PruneSnapshotHeight(height int64) // SetSnapshotInterval sets the interval at which the snapshots are taken. - // It is used by the store to determine which heights to retain until after the snapshot is complete. + // It is used by the store that implements the Snapshotter interface + // to determine which heights to retain until after the snapshot is complete. SetSnapshotInterval(snapshotInterval uint64) // Restore restores a state snapshot, taking snapshot chunk readers as input. From 2023fa378a556bb85719f0f2ecc192a62432f2dd Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 16 Apr 2022 15:05:40 -0400 Subject: [PATCH 52/58] remove snapshot store type --- store/types/store.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/store/types/store.go b/store/types/store.go index e25ebe674957..bb4cf2031af3 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -299,7 +299,6 @@ const ( StoreTypeMemory StoreTypeSMT StoreTypePersistent - StoreTypeSnapshot ) func (st StoreType) String() string { @@ -324,9 +323,6 @@ func (st StoreType) String() string { case StoreTypePersistent: return "StoreTypePersistent" - - case StoreTypeSnapshot: - return "StoreTypeSnapshot" } return "unknown store type" From 823971f158d6bf83d3fead5c2033c54a587197df Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 16 Apr 2022 16:14:47 -0400 Subject: [PATCH 53/58] remove pruning and snapshot wrappers from store types --- baseapp/abci_test.go | 20 +++--- baseapp/baseapp_test.go | 142 ++++++++++++++++++++-------------------- simapp/simd/cmd/root.go | 3 +- types/store.go | 14 ---- 4 files changed, 83 insertions(+), 96 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 182c1248a591..ff48c44a7f72 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -10,9 +10,9 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/snapshots" "github.com/cosmos/cosmos-sdk/testutil" - sdk "github.com/cosmos/cosmos-sdk/types" ) func TestGetBlockRentionHeight(t *testing.T) { @@ -44,9 +44,9 @@ func TestGetBlockRentionHeight(t *testing.T) { "pruning iavl snapshot only": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)), + baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)), baseapp.SetMinRetainBlocks(1), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(10000, 1)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(10000, 1)), ), maxAgeBlocks: 0, commitHeight: 499000, @@ -55,7 +55,7 @@ func TestGetBlockRentionHeight(t *testing.T) { "pruning state sync snapshot only": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), baseapp.SetMinRetainBlocks(1), ), maxAgeBlocks: 0, @@ -74,9 +74,9 @@ func TestGetBlockRentionHeight(t *testing.T) { "pruning all conditions": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetPruning(sdk.NewCustomPruningOptions(0, 0)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(0, 0)), baseapp.SetMinRetainBlocks(400000), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), ), maxAgeBlocks: 362880, commitHeight: 499000, @@ -85,9 +85,9 @@ func TestGetBlockRentionHeight(t *testing.T) { "no pruning due to no persisted state": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetPruning(sdk.NewCustomPruningOptions(0, 0)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(0, 0)), baseapp.SetMinRetainBlocks(400000), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), ), maxAgeBlocks: 362880, commitHeight: 10000, @@ -96,9 +96,9 @@ func TestGetBlockRentionHeight(t *testing.T) { "disable pruning": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetPruning(sdk.NewCustomPruningOptions(0, 0)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(0, 0)), baseapp.SetMinRetainBlocks(0), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), ), maxAgeBlocks: 362880, commitHeight: 499000, diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 5616c2352b3d..2c17071aefe8 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -188,7 +188,7 @@ func setupBaseAppWithSnapshots(t *testing.T, config *setupConfig) (*baseapp.Base snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), testutil.GetTempDir(t)) require.NoError(t, err) - app, err := setupBaseApp(t, routerOpt, baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(config.snapshotInterval, uint32(config.snapshotKeepRecent))), baseapp.SetPruning(config.pruningOpts)) + app, err := setupBaseApp(t, routerOpt, baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(config.snapshotInterval, uint32(config.snapshotKeepRecent))), baseapp.SetPruning(config.pruningOpts)) if err != nil { return nil, err } @@ -299,7 +299,7 @@ func TestConsensusParamsNotNil(t *testing.T) { // Test that LoadLatestVersion actually does. func TestLoadVersion(t *testing.T) { logger := defaultLogger() - pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)) + pruningOpt := baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -352,7 +352,7 @@ func useDefaultLoader(app *baseapp.BaseApp) { func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { rs := rootmulti.NewStore(db, log.NewNopLogger()) - rs.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)) + rs.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) key := sdk.NewKVStoreKey(storeKey) rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() @@ -369,7 +369,7 @@ func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) { rs := rootmulti.NewStore(db, log.NewNopLogger()) - rs.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningDefault)) + rs.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningDefault)) key := sdk.NewKVStoreKey(storeKey) rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) err := rs.LoadLatestVersion() @@ -412,7 +412,7 @@ func TestSetLoader(t *testing.T) { initStore(t, db, tc.origStoreKey, k, v) // load the app with the existing db - opts := []func(*baseapp.BaseApp){baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing))} + opts := []func(*baseapp.BaseApp){baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing))} if tc.setLoader != nil { opts = append(opts, tc.setLoader) } @@ -435,7 +435,7 @@ func TestSetLoader(t *testing.T) { func TestVersionSetterGetter(t *testing.T) { logger := defaultLogger() - pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningDefault)) + pruningOpt := baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningDefault)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -455,7 +455,7 @@ func TestVersionSetterGetter(t *testing.T) { func TestLoadVersionInvalid(t *testing.T) { logger := log.NewNopLogger() - pruningOpt := baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)) + pruningOpt := baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) db := dbm.NewMemDB() name := t.Name() app := baseapp.NewBaseApp(name, logger, db, pruningOpt) @@ -487,14 +487,14 @@ func TestLoadVersionInvalid(t *testing.T) { func TestLoadVersionPruning(t *testing.T) { logger := log.NewNopLogger() - pruningOptions := sdk.NewCustomPruningOptions(10, 15) + pruningOptions := pruningtypes.NewCustomPruningOptions(10, 15) pruningOpt := baseapp.SetPruning(pruningOptions) db := dbm.NewMemDB() name := t.Name() snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), testutil.GetTempDir(t)) require.NoError(t, err) - snapshotOpt := baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(3, 1)) + snapshotOpt := baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(3, 1)) app := baseapp.NewBaseApp(name, logger, db, pruningOpt, snapshotOpt) @@ -1934,7 +1934,7 @@ func TestListSnapshots(t *testing.T) { blockTxs: 4, snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), } app, err := setupBaseAppWithSnapshots(t, setupConfig) @@ -1965,7 +1965,7 @@ func TestSnapshotWithPruning(t *testing.T) { blockTxs: 2, snapshotInterval: 5, snapshotKeepRecent: 1, - pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), }, expectedSnapshots: []*abci.Snapshot{ {Height: 20, Format: 2, Chunks: 5}, @@ -1977,7 +1977,7 @@ func TestSnapshotWithPruning(t *testing.T) { blockTxs: 2, snapshotInterval: 5, snapshotKeepRecent: 1, - pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningEverything), + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningEverything), }, expectedSnapshots: []*abci.Snapshot{ {Height: 20, Format: 2, Chunks: 5}, @@ -1989,7 +1989,7 @@ func TestSnapshotWithPruning(t *testing.T) { blockTxs: 2, snapshotInterval: 5, snapshotKeepRecent: 1, - pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningDefault), + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningDefault), }, expectedSnapshots: []*abci.Snapshot{ {Height: 20, Format: 2, Chunks: 5}, @@ -2001,7 +2001,7 @@ func TestSnapshotWithPruning(t *testing.T) { blockTxs: 2, snapshotInterval: 5, snapshotKeepRecent: 2, - pruningOpts: sdk.NewCustomPruningOptions(12, 12), + pruningOpts: pruningtypes.NewCustomPruningOptions(12, 12), }, expectedSnapshots: []*abci.Snapshot{ {Height: 25, Format: 2, Chunks: 6}, @@ -2013,7 +2013,7 @@ func TestSnapshotWithPruning(t *testing.T) { blocks: 10, blockTxs: 2, snapshotInterval: 0, // 0 implies disable snapshots - pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), }, expectedSnapshots: []*abci.Snapshot{}, }, @@ -2023,7 +2023,7 @@ func TestSnapshotWithPruning(t *testing.T) { blockTxs: 2, snapshotInterval: 3, snapshotKeepRecent: 0, // 0 implies keep all snapshots - pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), }, expectedSnapshots: []*abci.Snapshot{ {Height: 9, Format: 2, Chunks: 2}, @@ -2091,7 +2091,7 @@ func TestLoadSnapshotChunk(t *testing.T) { blockTxs: 5, snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), } app, err := setupBaseAppWithSnapshots(t, setupConfig) require.NoError(t, err) @@ -2134,7 +2134,7 @@ func TestOfferSnapshot_Errors(t *testing.T) { blockTxs: 0, snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), } app, err := setupBaseAppWithSnapshots(t, setupConfig) require.NoError(t, err) @@ -2196,7 +2196,7 @@ func TestApplySnapshotChunk(t *testing.T) { blockTxs: 10, snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), } source, err := setupBaseAppWithSnapshots(t, setupConfig1) require.NoError(t, err) @@ -2206,7 +2206,7 @@ func TestApplySnapshotChunk(t *testing.T) { blockTxs: 0, snapshotInterval: 2, snapshotKeepRecent: 2, - pruningOpts: sdk.NewPruningOptions(pruningtypes.PruningNothing), + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), } target, err := setupBaseAppWithSnapshots(t, setupConfig2) require.NoError(t, err) @@ -2364,124 +2364,124 @@ func TestBaseApp_Init(t *testing.T) { }{ "snapshot but no pruning": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(pruningtypes.PruningNothing), - sdk.NewSnapshotOptions(1500, 2), + pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + snapshottypes.NewSnapshotOptions(1500, 2), // if no pruning is set, the default is PruneNothing nil, }, "pruning everything only": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningEverything)), + baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningEverything)), ), - sdk.NewPruningOptions(pruningtypes.PruningEverything), - sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), + pruningtypes.NewPruningOptions(pruningtypes.PruningEverything), + snapshottypes.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), nil, }, "pruning nothing only": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)), + baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)), ), - sdk.NewPruningOptions(pruningtypes.PruningNothing), - sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), + pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + snapshottypes.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), nil, }, "pruning default only": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningDefault)), + baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningDefault)), ), - sdk.NewPruningOptions(pruningtypes.PruningDefault), - sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), + pruningtypes.NewPruningOptions(pruningtypes.PruningDefault), + snapshottypes.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), nil, }, "pruning custom only": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 10)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(10, 10)), ), - sdk.NewCustomPruningOptions(10, 10), - sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), + pruningtypes.NewCustomPruningOptions(10, 10), + snapshottypes.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), nil, }, "pruning everything and snapshots": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningEverything)), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningEverything)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(pruningtypes.PruningEverything), - sdk.NewSnapshotOptions(1500, 2), + pruningtypes.NewPruningOptions(pruningtypes.PruningEverything), + snapshottypes.NewSnapshotOptions(1500, 2), nil, }, "pruning nothing and snapshots": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningNothing)), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(pruningtypes.PruningNothing), - sdk.NewSnapshotOptions(1500, 2), + pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + snapshottypes.NewSnapshotOptions(1500, 2), nil, }, "pruning default and snapshots": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewPruningOptions(pruningtypes.PruningDefault)), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningDefault)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(1500, 2)), ), - sdk.NewPruningOptions(pruningtypes.PruningDefault), - sdk.NewSnapshotOptions(1500, 2), + pruningtypes.NewPruningOptions(pruningtypes.PruningDefault), + snapshottypes.NewSnapshotOptions(1500, 2), nil, }, "pruning custom and snapshots": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 10)), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(10, 10)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(1500, 2)), ), - sdk.NewCustomPruningOptions(10, 10), - sdk.NewSnapshotOptions(1500, 2), + pruningtypes.NewCustomPruningOptions(10, 10), + snapshottypes.NewSnapshotOptions(1500, 2), nil, }, "error custom pruning 0 interval": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 0)), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(10, 0)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(1500, 2)), ), - sdk.NewCustomPruningOptions(10, 0), - sdk.NewSnapshotOptions(1500, 2), + pruningtypes.NewCustomPruningOptions(10, 0), + snapshottypes.NewSnapshotOptions(1500, 2), pruningtypes.ErrPruningIntervalZero, }, "error custom pruning too small interval": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 9)), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(10, 9)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(1500, 2)), ), - sdk.NewCustomPruningOptions(10, 9), - sdk.NewSnapshotOptions(1500, 2), + pruningtypes.NewCustomPruningOptions(10, 9), + snapshottypes.NewSnapshotOptions(1500, 2), pruningtypes.ErrPruningIntervalTooSmall, }, "error custom pruning too small keep recent": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewCustomPruningOptions(1, 10)), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 2)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(1, 10)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(1500, 2)), ), - sdk.NewCustomPruningOptions(9, 10), - sdk.NewSnapshotOptions(1500, 2), + pruningtypes.NewCustomPruningOptions(9, 10), + snapshottypes.NewSnapshotOptions(1500, 2), pruningtypes.ErrPruningKeepRecentTooSmall, }, "snapshot zero interval - manager not set": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 10)), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 2)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(10, 10)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 2)), ), - sdk.NewCustomPruningOptions(10, 10), - sdk.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), + pruningtypes.NewCustomPruningOptions(10, 10), + snapshottypes.NewSnapshotOptions(snapshottypes.SnapshotIntervalOff, 0), nil, }, "snapshot zero keep recent - allowed": { baseapp.NewBaseApp(name, logger, db, - baseapp.SetPruning(sdk.NewCustomPruningOptions(10, 10)), - baseapp.SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(1500, 0)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(10, 10)), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(1500, 0)), ), - sdk.NewCustomPruningOptions(10, 10), - sdk.NewSnapshotOptions(1500, 0), // 0 snapshot-keep-recent means keep all + pruningtypes.NewCustomPruningOptions(10, 10), + snapshottypes.NewSnapshotOptions(1500, 0), // 0 snapshot-keep-recent means keep all nil, }, } diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index c21c43b947f0..354c00b8c5fa 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -26,6 +26,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/simapp/params" "github.com/cosmos/cosmos-sdk/snapshots" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" @@ -270,7 +271,7 @@ func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, a panic(err) } - snapshotOptions := sdk.NewSnapshotOptions( + snapshotOptions := snapshottypes.NewSnapshotOptions( cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval)), cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent)), ) diff --git a/types/store.go b/types/store.go index 2fafdae29531..274d4f9c2c2b 100644 --- a/types/store.go +++ b/types/store.go @@ -5,8 +5,6 @@ import ( "sort" "strings" - pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/types/kv" ) @@ -165,15 +163,3 @@ func NewGasMeter(limit Gas) GasMeter { func NewInfiniteGasMeter() GasMeter { return types.NewInfiniteGasMeter() } - -func NewSnapshotOptions(interval uint64, keepRecent uint32) snapshottypes.SnapshotOptions { - return snapshottypes.NewSnapshotOptions(interval, keepRecent) -} - -func NewPruningOptions(pruningStrategy pruningtypes.PruningStrategy) pruningtypes.PruningOptions { - return pruningtypes.NewPruningOptions(pruningStrategy) -} - -func NewCustomPruningOptions(keepRecent, interval uint64) pruningtypes.PruningOptions { - return pruningtypes.NewCustomPruningOptions(keepRecent, interval) -} From 73b75eefeae3723898c18c0f36304e402d8918e3 Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 16 Apr 2022 16:19:43 -0400 Subject: [PATCH 54/58] fix HandleHeight comment in pruning manager --- pruning/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pruning/manager.go b/pruning/manager.go index 480a2192136d..8b869799dea0 100644 --- a/pruning/manager.go +++ b/pruning/manager.go @@ -95,7 +95,7 @@ func (m *Manager) GetFlushAndResetPruningHeights() ([]int64, error) { return pruningHeights, nil } -// HandleHeight determines if pruneHeight height needs to be kept for pruning at the right interval prescribed by +// HandleHeight determines if previousHeight height needs to be kept for pruning at the right interval prescribed by // the pruning strategy. Returns previousHeight, if it was kept to be pruned at the next call to Prune(), 0 otherwise. // previousHeight must be greater than 0 for the handling to take effect since valid heights start at 1 and 0 represents // the latest height. The latest height cannot be pruned. As a result, if previousHeight is less than or equal to 0, 0 is returned. From bbe9d5e0cfb4f16cb8023d061861677025372d2b Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 20 Apr 2022 11:43:38 -0400 Subject: [PATCH 55/58] snapshot happens in a separate goroutine --- baseapp/abci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index 1732abdc3e73..9061170862d2 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -338,7 +338,7 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { app.halt() } - app.snapshotManager.SnapshotIfApplicable(header.Height) + go app.snapshotManager.SnapshotIfApplicable(header.Height) return abci.ResponseCommit{ Data: commitID.Hash, From 2dc26e5f22a41d7432ecf90e40e75aa9fd022771 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 21 Apr 2022 13:43:02 -0400 Subject: [PATCH 56/58] set snapshot interval on multistore in baseapp instead of snapshot manager --- baseapp/options.go | 1 + snapshots/manager.go | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/baseapp/options.go b/baseapp/options.go index ecaa6fc4f293..9ac0d0e33cc0 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -202,6 +202,7 @@ func (app *BaseApp) SetSnapshot(snapshotStore *snapshots.Store, opts snapshottyp app.snapshotManager = nil return } + app.cms.SetSnapshotInterval(opts.Interval) app.snapshotManager = snapshots.NewManager(snapshotStore, opts, app.cms, nil, app.logger) } diff --git a/snapshots/manager.go b/snapshots/manager.go index 72f1c15b4b76..58986aab2716 100644 --- a/snapshots/manager.go +++ b/snapshots/manager.go @@ -72,7 +72,6 @@ var ( // NewManager creates a new manager. func NewManager(store *Store, opts types.SnapshotOptions, multistore types.Snapshotter, extensions map[string]types.ExtensionSnapshotter, logger log.Logger) *Manager { - multistore.SetSnapshotInterval(opts.Interval) return &Manager{ store: store, opts: opts, From 8eee2f75e665a21c18454bbe19eaf2b2353f7019 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 21 Apr 2022 14:12:46 -0400 Subject: [PATCH 57/58] fix snapshot manager unit tests --- snapshots/helpers_test.go | 1 + snapshots/manager_test.go | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/snapshots/helpers_test.go b/snapshots/helpers_test.go index d10381bf3315..24051a17a927 100644 --- a/snapshots/helpers_test.go +++ b/snapshots/helpers_test.go @@ -164,6 +164,7 @@ func setupBusyManager(t *testing.T) *snapshots.Manager { store, err := snapshots.NewStore(db.NewMemDB(), testutil.GetTempDir(t)) require.NoError(t, err) hung := newHungSnapshotter() + hung.SetSnapshotInterval(opts.Interval) mgr := snapshots.NewManager(store, opts, hung, nil, log.NewNopLogger()) require.Equal(t, opts.Interval, hung.snapshotInterval) diff --git a/snapshots/manager_test.go b/snapshots/manager_test.go index 01e654c8bfed..7fbddd6c7d6d 100644 --- a/snapshots/manager_test.go +++ b/snapshots/manager_test.go @@ -17,6 +17,7 @@ var opts = types.NewSnapshotOptions(1500, 2) func TestManager_List(t *testing.T) { store := setupStore(t) snapshotter := &mockSnapshotter{} + snapshotter.SetSnapshotInterval(opts.Interval) manager := snapshots.NewManager(store, opts, snapshotter, nil, log.NewNopLogger()) require.Equal(t, opts.Interval, snapshotter.GetSnapshotInterval()) @@ -109,7 +110,9 @@ func TestManager_Take(t *testing.T) { func TestManager_Prune(t *testing.T) { store := setupStore(t) - manager := snapshots.NewManager(store, opts, &mockSnapshotter{}, nil, log.NewNopLogger()) + snapshotter := &mockSnapshotter{} + snapshotter.SetSnapshotInterval(opts.Interval) + manager := snapshots.NewManager(store, opts, snapshotter, nil, log.NewNopLogger()) pruned, err := manager.Prune(2) require.NoError(t, err) From e53691a1e8e5450a9a096e74856d00e679fabe9f Mon Sep 17 00:00:00 2001 From: Roman <34196718+p0mvn@users.noreply.github.com> Date: Thu, 21 Apr 2022 11:54:21 -0700 Subject: [PATCH 58/58] Update CHANGELOG.md Co-authored-by: Aleksandr Bezobchuk --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2efecf3e15af..87b384be1b27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,7 +85,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes -* [\#11496](https://github.com/cosmos/cosmos-sdk/pull/11496) refactor abstractions for snapshot and pruning; snapshot intervals eventually pruned; unit tests. +* [\#11496](https://github.com/cosmos/cosmos-sdk/pull/11496) Refactor abstractions for snapshot and pruning; snapshot intervals eventually pruned; unit tests. * (types) [\#11689](https://github.com/cosmos/cosmos-sdk/pull/11689) Make `Coins#Sub` and `Coins#SafeSub` consistent with `Coins#Add`. * (store)[\#11152](https://github.com/cosmos/cosmos-sdk/pull/11152) Remove `keep-every` from pruning options. * [\#10950](https://github.com/cosmos/cosmos-sdk/pull/10950) Add `envPrefix` parameter to `cmd.Execute`.