Skip to content

Commit

Permalink
Add QMS for IAVL migration query multistore (#542)
Browse files Browse the repository at this point in the history
## Describe your changes and provide context
This PR add an extra QMS used for serving online migration query
fallback. When the request height is lower than the migration height, we
will fall back to read from IAVL store, otherwise, it will use the
default CMS

## Testing performed to validate your change
  • Loading branch information
yzang2019 authored and Kbhat1 committed Oct 22, 2024
1 parent e2001f3 commit a48731c
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 15 deletions.
44 changes: 32 additions & 12 deletions baseapp/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ import (
"time"

"github.com/armon/go-metrics"
"github.com/gogo/protobuf/proto"
abci "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"google.golang.org/grpc/codes"
grpcstatus "google.golang.org/grpc/status"

"github.com/cosmos/cosmos-sdk/codec"
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
"github.com/cosmos/cosmos-sdk/store/types"
"github.com/cosmos/cosmos-sdk/tasks"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/legacytm"
"github.com/cosmos/cosmos-sdk/utils"
"github.com/gogo/protobuf/proto"
abci "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"google.golang.org/grpc/codes"
grpcstatus "google.golang.org/grpc/status"
)

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

Expand All @@ -734,7 +735,13 @@ func (app *BaseApp) CreateQueryContext(height int64, prove bool) (sdk.Context, e
)
}

cacheMS, err := app.cms.CacheMultiStoreWithVersion(height)
var cacheMS types.CacheMultiStore
if height < app.migrationHeight && app.qms != nil {
cacheMS, err = app.qms.CacheMultiStoreWithVersion(height)
} else {
cacheMS, err = app.cms.CacheMultiStoreWithVersion(height)
}

if err != nil {
return sdk.Context{},
sdkerrors.Wrapf(
Expand Down Expand Up @@ -905,12 +912,25 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res
}

func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery {
// "/store" prefix for store queries
queryable, ok := app.cms.(sdk.Queryable)
if !ok {
return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries"), app.trace)

var (
queryable sdk.Queryable
ok bool
)
// Check if online migration is enabled for fallback read
if req.Height < app.migrationHeight && app.qms != nil {
queryable, ok = app.qms.(sdk.Queryable)
if !ok {
return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries"), app.trace)
}
} else {
queryable, ok = app.cms.(sdk.Queryable)
if !ok {
return sdkerrors.QueryResultWithDebug(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries"), app.trace)
}
}

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

if req.Height <= 1 && req.Prove {
Expand Down
8 changes: 5 additions & 3 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,11 @@ type BaseApp struct { //nolint: maligned
}

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

// an inter-block write-through cache provided to the context during deliverState
interBlockCache sdk.MultiStorePersistentCache
Expand Down
10 changes: 10 additions & 0 deletions baseapp/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,3 +361,13 @@ func (app *BaseApp) SetStreamingService(s StreamingService) {
// BaseApp will pass BeginBlock, DeliverTx, and EndBlock requests and responses to the streaming services to update their ABCI context
app.abciListeners = append(app.abciListeners, s)
}

// SetQueryMultiStore set a alternative MultiStore implementation to support online migration fallback read.
func (app *BaseApp) SetQueryMultiStore(ms sdk.MultiStore) {
app.qms = ms
}

// SetMigrationHeight set the migration height for online migration so that query below this height will still be served from IAVL.
func (app *BaseApp) SetMigrationHeight(height int64) {
app.migrationHeight = height
}

0 comments on commit a48731c

Please sign in to comment.