Skip to content

Commit 851b25b

Browse files
Kbhat1yzang2019
andauthored
Archive Node Migration: Expose Get State Store + Query Iavl Before Migration Height (#541)
## Describe your changes and provide context - Exposes `GetStateStore` from rootmulti - For historical queries, if before migration height, points to iavl ## Testing performed to validate your change - Verified and tested on node --------- Co-authored-by: Yiming Zang <[email protected]> Co-authored-by: yzang2019 <[email protected]>
1 parent c7e50a2 commit 851b25b

File tree

6 files changed

+94
-18
lines changed

6 files changed

+94
-18
lines changed

baseapp/abci.go

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@ import (
1313
"time"
1414

1515
"github.com/armon/go-metrics"
16-
"github.com/gogo/protobuf/proto"
17-
abci "github.com/tendermint/tendermint/abci/types"
18-
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
19-
"google.golang.org/grpc/codes"
20-
grpcstatus "google.golang.org/grpc/status"
21-
2216
"github.com/cosmos/cosmos-sdk/codec"
2317
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
18+
"github.com/cosmos/cosmos-sdk/store/types"
2419
"github.com/cosmos/cosmos-sdk/tasks"
2520
"github.com/cosmos/cosmos-sdk/telemetry"
2621
sdk "github.com/cosmos/cosmos-sdk/types"
2722
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
2823
"github.com/cosmos/cosmos-sdk/types/legacytm"
2924
"github.com/cosmos/cosmos-sdk/utils"
25+
"github.com/gogo/protobuf/proto"
26+
abci "github.com/tendermint/tendermint/abci/types"
27+
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
28+
"google.golang.org/grpc/codes"
29+
grpcstatus "google.golang.org/grpc/status"
3030
)
3131

3232
// InitChain implements the ABCI interface. It runs the initialization logic
@@ -705,7 +705,8 @@ func checkNegativeHeight(height int64) error {
705705
// CreateQueryContext creates a new sdk.Context for a query, taking as args
706706
// the block height and whether the query needs a proof or not.
707707
func (app *BaseApp) CreateQueryContext(height int64, prove bool) (sdk.Context, error) {
708-
if err := checkNegativeHeight(height); err != nil {
708+
err := checkNegativeHeight(height)
709+
if err != nil {
709710
return sdk.Context{}, err
710711
}
711712

@@ -731,7 +732,15 @@ func (app *BaseApp) CreateQueryContext(height int64, prove bool) (sdk.Context, e
731732
)
732733
}
733734

734-
cacheMS, err := app.cms.CacheMultiStoreWithVersion(height)
735+
var cacheMS types.CacheMultiStore
736+
if height < app.migrationHeight && app.qms != nil {
737+
cacheMS, err = app.qms.CacheMultiStoreWithVersion(height)
738+
app.logger.Info("SeiDB Archive Migration: Serving Query From Iavl", "height", height)
739+
} else {
740+
cacheMS, err = app.cms.CacheMultiStoreWithVersion(height)
741+
app.logger.Info("SeiDB Archive Migration: Serving Query From State Store", "height", height)
742+
}
743+
735744
if err != nil {
736745
return sdk.Context{},
737746
sdkerrors.Wrapf(
@@ -902,12 +911,26 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res
902911
}
903912

904913
func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery {
905-
// "/store" prefix for store queries
906-
queryable, ok := app.cms.(sdk.Queryable)
907-
if !ok {
908-
return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries"), app.trace)
914+
var (
915+
queryable sdk.Queryable
916+
ok bool
917+
)
918+
// Check if online migration is enabled for fallback read
919+
if req.Height < app.migrationHeight && app.qms != nil {
920+
queryable, ok = app.qms.(sdk.Queryable)
921+
if !ok {
922+
return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries"), app.trace)
923+
}
924+
app.logger.Info("SeiDB Archive Migration: Serving Query From Iavl", "height", req.Height)
925+
} else {
926+
queryable, ok = app.cms.(sdk.Queryable)
927+
if !ok {
928+
return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries"), app.trace)
929+
}
930+
app.logger.Info("SeiDB Archive Migration: Serving Query From State Store", "height", req.Height)
909931
}
910932

933+
// "/store" prefix for store queries
911934
req.Path = "/" + strings.Join(path[1:], "/")
912935

913936
if req.Height <= 1 && req.Prove {

baseapp/abci_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
dbm "github.com/tendermint/tm-db"
1212

1313
"github.com/cosmos/cosmos-sdk/testutil"
14+
"github.com/cosmos/cosmos-sdk/types"
1415
sdk "github.com/cosmos/cosmos-sdk/types"
1516
)
1617

@@ -200,3 +201,27 @@ func (ps *paramStore) Get(_ sdk.Context, key []byte, ptr interface{}) {
200201
panic(err)
201202
}
202203
}
204+
func TestHandleQueryStore_NonQueryableMultistore(t *testing.T) {
205+
logger := defaultLogger()
206+
db := dbm.NewMemDB()
207+
name := t.Name()
208+
app := NewBaseApp(name, logger, db, nil, nil, &testutil.TestAppOpts{})
209+
210+
// Mock a non-queryable cms
211+
mockCMS := &mockNonQueryableMultiStore{}
212+
app.cms = mockCMS
213+
214+
path := []string{"store", "test"}
215+
req := abci.RequestQuery{
216+
Path: "store/test",
217+
Height: 1,
218+
}
219+
220+
resp := handleQueryStore(app, path, req)
221+
require.True(t, resp.IsErr())
222+
require.Contains(t, resp.Log, "multistore doesn't support queries")
223+
}
224+
225+
type mockNonQueryableMultiStore struct {
226+
types.CommitMultiStore
227+
}

baseapp/baseapp.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,11 @@ type BaseApp struct { //nolint: maligned
179179
}
180180

181181
type appStore struct {
182-
db dbm.DB // common DB backend
183-
cms sdk.CommitMultiStore // Main (uncached) state
184-
storeLoader StoreLoader // function to handle store loading, may be overridden with SetStoreLoader()
182+
db dbm.DB // common DB backend
183+
cms sdk.CommitMultiStore // Main (uncached) state
184+
qms sdk.CommitMultiStore // Query multistore used for migration only
185+
migrationHeight int64
186+
storeLoader StoreLoader // function to handle store loading, may be overridden with SetStoreLoader()
185187

186188
// an inter-block write-through cache provided to the context during deliverState
187189
interBlockCache sdk.MultiStorePersistentCache
@@ -411,6 +413,9 @@ func (app *BaseApp) MountMemoryStores(keys map[string]*sdk.MemoryStoreKey) {
411413
// using the default DB.
412414
func (app *BaseApp) MountStore(key sdk.StoreKey, typ sdk.StoreType) {
413415
app.cms.MountStoreWithDB(key, typ, nil)
416+
if app.qms != nil {
417+
app.qms.MountStoreWithDB(key, typ, nil)
418+
}
414419
}
415420

416421
// LoadLatestVersion loads the latest application version. It will panic if
@@ -421,6 +426,13 @@ func (app *BaseApp) LoadLatestVersion() error {
421426
return fmt.Errorf("failed to load latest version: %w", err)
422427
}
423428

429+
if app.qms != nil {
430+
err = app.storeLoader(app.qms)
431+
if err != nil {
432+
return fmt.Errorf("failed to load latest version: %w", err)
433+
}
434+
}
435+
424436
return app.init()
425437
}
426438

baseapp/options.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,13 @@ func (app *BaseApp) SetStreamingService(s StreamingService) {
361361
// BaseApp will pass BeginBlock, DeliverTx, and EndBlock requests and responses to the streaming services to update their ABCI context
362362
app.abciListeners = append(app.abciListeners, s)
363363
}
364+
365+
// SetQueryMultiStore set a alternative MultiStore implementation to support online migration fallback read.
366+
func (app *BaseApp) SetQueryMultiStore(ms sdk.CommitMultiStore) {
367+
app.qms = ms
368+
}
369+
370+
// SetMigrationHeight set the migration height for online migration so that query below this height will still be served from IAVL.
371+
func (app *BaseApp) SetMigrationHeight(height int64) {
372+
app.migrationHeight = height
373+
}

storev2/rootmulti/store.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ func NewStore(
6363
logger log.Logger,
6464
scConfig config.StateCommitConfig,
6565
ssConfig config.StateStoreConfig,
66+
migrateIavl bool,
6667
) *Store {
6768
scStore := sc.NewCommitStore(homeDir, logger, scConfig)
6869
store := &Store{
@@ -81,7 +82,7 @@ func NewStore(
8182
// Check whether SC was enabled before but SS was not
8283
ssVersion, _ := ssStore.GetLatestVersion()
8384
scVersion, _ := scStore.GetLatestVersion()
84-
if ssVersion <= 0 && scVersion > 0 {
85+
if ssVersion <= 0 && scVersion > 0 && !migrateIavl {
8586
panic("Enabling SS store without state sync could cause data corruption")
8687
}
8788
if err = ss.RecoverStateStore(logger, homeDir, ssStore); err != nil {
@@ -214,6 +215,11 @@ func (rs *Store) GetStoreType() types.StoreType {
214215
return types.StoreTypeMulti
215216
}
216217

218+
// GetStateStore returns the ssStore instance
219+
func (rs *Store) GetStateStore() sstypes.StateStore {
220+
return rs.ssStore
221+
}
222+
217223
// Implements interface CacheWrapper
218224
func (rs *Store) CacheWrap(_ types.StoreKey) types.CacheWrap {
219225
return rs.CacheMultiStore().(types.CacheWrap)
@@ -757,7 +763,7 @@ loop:
757763
scImporter.AddNode(node)
758764

759765
// Check if we should also import to SS store
760-
if rs.ssStore != nil && node.Height == 0 && ssImporter != nil {
766+
if rs.ssStore != nil && ssImporter != nil {
761767
ssImporter <- sstypes.SnapshotNode{
762768
StoreKey: storeKey,
763769
Key: node.Key,

storev2/rootmulti/store_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ import (
1010
)
1111

1212
func TestLastCommitID(t *testing.T) {
13-
store := NewStore(t.TempDir(), log.NewNopLogger(), config.StateCommitConfig{}, config.StateStoreConfig{})
13+
store := NewStore(t.TempDir(), log.NewNopLogger(), config.StateCommitConfig{}, config.StateStoreConfig{}, false)
1414
require.Equal(t, types.CommitID{}, store.LastCommitID())
1515
}

0 commit comments

Comments
 (0)