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 c9b1a6fad98..e5d008eab5f 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 eddee8b954b..2d4f3181558 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 45c65b8030e..62d607c9d45 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 5cfb616bd13..5d16ced3a02 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 4b24c108da0..8b5e54a9f31 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 7244aff8307..c4e5ae5b719 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 00000000000..35d0c2351ce --- /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 00000000000..c2354f8b0fe --- /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 00000000000..bd45bf8b47d --- /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 00000000000..84ed73b41e8 --- /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 00000000000..c2d4e93e5cc --- /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 8d4c003eae4..7e37e015177 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 4b574b5e784..a9664db554c 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 37852de711e..6aa33921821 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 fb2ba34e8f8..d6d48de0b8e 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 8b4af74cad8..f7f5a97efe1 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 1413967d54b..6f4561b8474 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 6cbaf0a5a34..f0f3d1a0af1 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 9ae7f10a7b4..bc84fd98c57 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 8f6e526f083..8d7b314d86d 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 63775d3dda2..6a849fc9f06 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 2d94d1561c4..02e2458df42 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 0989bb4bd21..ecaff9578b3 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 0a3e4388e8b..b7cbfaa0455 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 00000000000..16b078157b6 --- /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 f747920d13a..cc0a18abd26 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 a5706553668..28906f4819f 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 c8aa6dca599..1f6ebacdc2d 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 4d6e5afeb87..157681461ee 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 10f8397e728..d593732d4c6 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 92e1311fdd8..bad1603da7c 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 f38bd41824b..6101df0679b 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 80cbcf68cbd..bbf2f9524d7 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 2c068c413f4..492bd4fee1d 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 572ab55f769..90370b5939c 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 16a165b3ba2..c13d91448f5 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 3dd05b02bd1..00000000000 --- 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 d524aea70ed..00000000000 --- 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 bbf1b875803..c4a08f71158 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 32064d7e182..7af25af15f9 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 b984aac81dc..4f9ec299f44 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 09f1f74b5a1..bf7b0f921cd 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 0495e95e1e1..6242928c0c0 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 191239bc83f..e50022e8b98 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 d157f009908..f03f5b9f5d2 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 29c391287a9..d4b97325dd1 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 2a9609afb12..d62956368e4 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 5aacfc2d413..91f75088d64 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 71fe7283b05..684c7026465 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 00000000000..6c4bf2d992b --- /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 b50f95d02a7..a9604da8baa 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 d2039f8cb89..7d4dfecb644 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 341a2ffe30d..4031642d56d 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 e5d008eab5f..1732abdc3e7 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 b7cbfaa0455..0a3e4388e8b 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 2d4f3181558..0d822db988f 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 5d16ced3a02..f773d32b276 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 6a849fc9f06..b579eaaf111 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 47ac556d2b4..1cb27f57721 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 6ff54d24ecb..2d65a96a01d 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 6c4bf2d992b..00000000000 --- 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 2d65a96a01d..ef33eaa4411 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 487c256e03b..fb6ba4b1294 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 0d822db988f..4520fc04e7a 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 f773d32b276..3fc8ce757e5 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 8b5e54a9f31..3bbb43b2777 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 7e37e015177..2329018f8c0 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 6aa33921821..4ca10c40683 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 d6d48de0b8e..ee9c36dcaa3 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 f7f5a97efe1..2321476b548 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 f0f3d1a0af1..bc0485c11b2 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 28906f4819f..fdcf3b96eda 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 1f6ebacdc2d..b48a566c853 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 157681461ee..b862375ae01 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 6101df0679b..2cd4516181a 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 bbf2f9524d7..4fe61b4b44e 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 90370b5939c..5c40c3b134f 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 c13d91448f5..900e6cb7a91 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 c4a08f71158..6ba93ee13f9 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 684c7026465..995eb56889d 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 4031642d56d..ba3d772039b 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 3bbb43b2777..dddff27feaf 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 4ca10c40683..2108d8eee07 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 b579eaaf111..d10381bf331 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 6ba93ee13f9..f7e86c62d80 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 35d0c2351ce..91b9435bec2 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 84ed73b41e8..bfb1dc81418 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 bc0485c11b2..1afee407b56 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 bd45bf8b47d..f7cb55becbf 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 62d607c9d45..062b003c57a 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 00000000000..c4bc2d432ef --- /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 c2354f8b0fe..e2fdf4319cc 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 f7cb55becbf..783a0052c87 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 02e2458df42..70530ec032d 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 16b078157b6..c419c019e4e 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 2cd4516181a..ef58d3b9169 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 3fc8ce757e5..30c5b9aa445 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 2108d8eee07..9e5dcfc2bca 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 dddff27feaf..5a4c6a73ee1 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 9e5dcfc2bca..5de875a83ee 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 f7e86c62d80..7cf2960e905 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 4520fc04e7a..182c1248a59 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 30c5b9aa445..38ad9681a6a 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 5a4c6a73ee1..6498281b4b9 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 e2fdf4319cc..8cc66f33c70 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 783a0052c87..49268c0f2c4 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 2329018f8c0..834cae14bec 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 ee9c36dcaa3..8cc02b8e496 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 1afee407b56..387a29b7bef 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 d10381bf331..54866e37865 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 70530ec032d..58e47bc4543 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 fdcf3b96eda..55ccda428ee 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 b48a566c853..6642da5c889 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 b862375ae01..102c196e1cf 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 d593732d4c6..3490351efc4 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 ef58d3b9169..5b335d04d78 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 4fe61b4b44e..46f9c48fdd5 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 5c40c3b134f..703419672ed 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 900e6cb7a91..f6c41d75d92 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 38ad9681a6a..40e69667de5 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 6498281b4b9..5a4c6a73ee1 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 c4e5ae5b719..3a26e5e5a09 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 c4bc2d432ef..6a270b46eb8 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 49268c0f2c4..23ddbce7e36 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 c2d4e93e5cc..75edb2f6f85 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 834cae14bec..2329018f8c0 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 8cc02b8e496..ee9c36dcaa3 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 387a29b7bef..f5cb5cb18bd 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 54866e37865..d10381bf331 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 58e47bc4543..b0ddf04bd46 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 ecaff9578b3..01e654c8bfe 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 55ccda428ee..fdcf3b96eda 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 6642da5c889..b48a566c853 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 3490351efc4..d593732d4c6 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 5b335d04d78..47409a3fd52 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 46f9c48fdd5..4fe61b4b44e 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 703419672ed..5c40c3b134f 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 f6c41d75d92..900e6cb7a91 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 4f9ec299f44..4ff6396aa92 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 91f75088d64..3e55f726192 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 75edb2f6f85..949b01489ae 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 23ddbce7e36..914a717313b 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 8cc66f33c70..37c8788b73d 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 f5cb5cb18bd..63ed31fe82e 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 47409a3fd52..dc6a8232fda 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 b0ddf04bd46..0defd623bd5 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 00000000000..4f66d79b337 --- /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 00000000000..48f3b67e3f8 --- /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 062b003c57a..429321f9dcf 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 37c8788b73d..935bb73d277 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 914a717313b..49ca9a35ece 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 5de875a83ee..abe3e0f45e8 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 dc6a8232fda..25b8933c4a1 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 7cf2960e905..6a1d47def98 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 40e69667de5..e393b34e9f0 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 8a365ab758f..5b101b4ac30 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 4fe61b4b44e..bba5776cd9a 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 6a1d47def98..2f26a102980 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 4ff6396aa92..32e31e7b42a 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 6242928c0c0..48b8b416087 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 e50022e8b98..736c2c32f3f 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 f03f5b9f5d2..094dd876254 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 d62956368e4..596af3f16a2 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 3e55f726192..176e314c5a8 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 a9604da8baa..ff2b6b4b280 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 e393b34e9f0..74b33cb50ba 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 5a4c6a73ee1..90b59ed1382 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 935bb73d277..2b4b6309b85 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 49ca9a35ece..e6a696b7f02 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 bfb1dc81418..a8479e97ffc 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 949b01489ae..6fb0dbf8da5 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 abe3e0f45e8..745ea44e49d 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 ee9c36dcaa3..2e21579032c 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 2321476b548..2d7bc976d92 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 fdcf3b96eda..3b961e0ab1c 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 b48a566c853..06d7b63f550 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 102c196e1cf..00ca3755382 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 25b8933c4a1..fe720240c46 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 bba5776cd9a..930361600dc 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 5c40c3b134f..b9723b56efd 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 2f26a102980..5554e1e1389 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 32e31e7b42a..1b7fca28e04 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 736c2c32f3f..983f132fcc1 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 094dd876254..0598b1f035b 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 596af3f16a2..7a3286989ee 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 ff2b6b4b280..9968d4118cf 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 74b33cb50ba..f70f8ad81db 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 90b59ed1382..ecaa6fc4f29 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 0defd623bd5..e614be07697 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 c419c019e4e..3a0e05a5a06 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 9968d4118cf..d654ef3e5d2 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 6a270b46eb8..51b1c10462a 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 2b4b6309b85..cd13365f196 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 e6a696b7f02..f00171c673f 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 fe720240c46..48ab06a0f55 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 930361600dc..f2b1bc82ed0 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 f70f8ad81db..5616c2352b3 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 cd13365f196..019c11f38be 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 f00171c673f..fc73e65b480 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 00000000000..c8d2e2c343a --- /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 a8479e97ffc..229dbed984d 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 6fb0dbf8da5..3e82320c870 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 51b1c10462a..7856e02139a 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 019c11f38be..a8f9e9e628a 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 fc73e65b480..1bb712a8a36 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 c8d2e2c343a..fb6ee740b97 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 3e82320c870..abc6bf39e2a 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 1b7fca28e04..3c8fa82bbab 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 48b8b416087..77637910e76 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 983f132fcc1..3bf6c73096a 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 0598b1f035b..cdcbbd2fb98 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 7a3286989ee..586cc4e9d36 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 176e314c5a8..44c97ff4f52 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 d654ef3e5d2..2fafdae2953 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 91b9435bec2..3382b17d828 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 a8f9e9e628a..d894cdf462f 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 1732abdc3e7..9061170862d 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 e614be07697..72f1c15b4b7 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 9061170862d..1732abdc3e7 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 d894cdf462f..af0fd60be8c 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 af0fd60be8c..8a69429af9e 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 429321f9dcf..fb90abd924d 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 7af25af15f9..a13a2d9a5a5 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 3382b17d828..f7afae8e6ac 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 7856e02139a..8c38778bf93 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 8a69429af9e..a12bc3985a1 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 4f66d79b337..00000000000 --- 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 48f3b67e3f8..00000000000 --- 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 bc84fd98c57..c21c43b947f 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 fb90abd924d..2dfa029b7c2 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 19d460c3d5c..d1d65770b09 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 8d7b314d86d..db0247a6167 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 3a0e05a5a06..1ce39d486ad 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 a12bc3985a1..480a2192136 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 cc0a18abd26..76f800484a4 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 e25ebe67495..bb4cf2031af 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 182c1248a59..ff48c44a7f7 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 5616c2352b3..2c17071aefe 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 c21c43b947f..354c00b8c5f 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 2fafdae2953..274d4f9c2c2 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 480a2192136..8b869799dea 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 1732abdc3e7..9061170862d 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 ecaa6fc4f29..9ac0d0e33cc 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 72f1c15b4b7..58986aab271 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 d10381bf331..24051a17a92 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 01e654c8bfe..7fbddd6c7d6 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 2efecf3e15a..87b384be1b2 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`.