diff --git a/baseapp/abci.go b/baseapp/abci.go index 98a8b1402..148de4fc6 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -25,6 +25,7 @@ import ( 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" ) // InitChain implements the ABCI interface. It runs the initialization logic @@ -929,7 +930,7 @@ func splitPath(requestPath string) (path []string) { } // ABCI++ -func (app *BaseApp) PrepareProposal(ctx context.Context, req *abci.RequestPrepareProposal) (*abci.ResponsePrepareProposal, error) { +func (app *BaseApp) PrepareProposal(ctx context.Context, req *abci.RequestPrepareProposal) (resp *abci.ResponsePrepareProposal, err error) { defer telemetry.MeasureSince(time.Now(), "abci", "prepare_proposal") header := tmproto.Header{ @@ -963,21 +964,40 @@ func (app *BaseApp) PrepareProposal(ctx context.Context, req *abci.RequestPrepar app.preparePrepareProposalState() + defer func() { + if err := recover(); err != nil { + app.logger.Error( + "panic recovered in PrepareProposal", + "height", req.Height, + "time", req.Time, + "panic", err, + ) + + resp = &abci.ResponsePrepareProposal{ + TxRecords: utils.Map(req.Txs, func(tx []byte) *abci.TxRecord { + return &abci.TxRecord{Action: abci.TxRecord_UNMODIFIED, Tx: tx} + }), + } + } + }() + if app.prepareProposalHandler != nil { - res, err := app.prepareProposalHandler(app.prepareProposalState.ctx, req) + resp, err = app.prepareProposalHandler(app.prepareProposalState.ctx, req) if err != nil { return nil, err } + if cp := app.GetConsensusParams(app.prepareProposalState.ctx); cp != nil { - res.ConsensusParamUpdates = cp + resp.ConsensusParamUpdates = cp } - return res, nil - } else { - return nil, errors.New("no prepare proposal handler") + + return resp, nil } + + return nil, errors.New("no prepare proposal handler") } -func (app *BaseApp) ProcessProposal(ctx context.Context, req *abci.RequestProcessProposal) (*abci.ResponseProcessProposal, error) { +func (app *BaseApp) ProcessProposal(ctx context.Context, req *abci.RequestProcessProposal) (resp *abci.ResponseProcessProposal, err error) { defer telemetry.MeasureSince(time.Now(), "abci", "process_proposal") header := tmproto.Header{ @@ -1018,21 +1038,36 @@ func (app *BaseApp) ProcessProposal(ctx context.Context, req *abci.RequestProces } // NOTE: header hash is not set in NewContext, so we manually set it here - app.prepareProcessProposalState(gasMeter, req.Hash) + defer func() { + if err := recover(); err != nil { + app.logger.Error( + "panic recovered in ProcessProposal", + "height", req.Height, + "time", req.Time, + "hash", fmt.Sprintf("%X", req.Hash), + "panic", err, + ) + + resp = &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + }() + if app.processProposalHandler != nil { - res, err := app.processProposalHandler(app.processProposalState.ctx, req) + resp, err = app.processProposalHandler(app.processProposalState.ctx, req) if err != nil { return nil, err } + if cp := app.GetConsensusParams(app.processProposalState.ctx); cp != nil { - res.ConsensusParamUpdates = cp + resp.ConsensusParamUpdates = cp } - return res, nil - } else { - return nil, errors.New("no process proposal handler") + + return resp, nil } + + return nil, errors.New("no process proposal handler") } func (app *BaseApp) FinalizeBlock(ctx context.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) { diff --git a/storev2/rootmulti/store.go b/storev2/rootmulti/store.go index 89076e7d1..6b168e48f 100644 --- a/storev2/rootmulti/store.go +++ b/storev2/rootmulti/store.go @@ -91,7 +91,7 @@ func NewStore( // Commit implements interface Committer, called by ABCI Commit func (rs *Store) Commit(bumpVersion bool) types.CommitID { if !bumpVersion { - return rs.lastCommitInfo.CommitID() + panic("Commit should always bump version in root multistore") } if err := rs.flush(); err != nil { panic(err) @@ -206,8 +206,8 @@ func (rs *Store) GetStoreType() types.StoreType { } // Implements interface CacheWrapper -func (rs *Store) CacheWrap(storeKey types.StoreKey) types.CacheWrap { - return rs.CacheMultiStore().CacheWrap(storeKey) +func (rs *Store) CacheWrap(_ types.StoreKey) types.CacheWrap { + return rs.CacheMultiStore().(types.CacheWrap) } // Implements interface CacheWrapper @@ -237,6 +237,8 @@ func (rs *Store) CacheMultiStoreWithVersion(version int64) (types.CacheMultiStor if version <= 0 || (rs.lastCommitInfo != nil && version == rs.lastCommitInfo.Version) { return rs.CacheMultiStore(), nil } + rs.mtx.RLock() + defer rs.mtx.RUnlock() stores := make(map[types.StoreKey]types.CacheWrapper) // add the transient/mem stores registered in current app. for k, store := range rs.ckvStores { @@ -354,6 +356,12 @@ func (rs *Store) LoadVersionAndUpgrade(version int64, upgrades *types.StoreUpgra if err := rs.scStore.Initialize(initialStores); err != nil { return err } + if version > 0 { + _, err := rs.scStore.LoadVersion(version, false) + if err != nil { + return nil + } + } var treeUpgrades []*proto.TreeNameUpgrade for _, key := range storesKeys { @@ -486,6 +494,7 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { return sdkerrors.QueryResult(err) } var store types.Queryable + var commitInfo *types.CommitInfo if !req.Prove && version < rs.lastCommitInfo.Version && rs.ssStore != nil { // Serve abci query from ss store if no proofs needed @@ -498,9 +507,13 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { return sdkerrors.QueryResult(err) } store = types.Queryable(commitment.NewStore(scStore.GetTreeByName(storeName), rs.logger)) + commitInfo = convertCommitInfo(scStore.LastCommitInfo()) + commitInfo = amendCommitInfo(commitInfo, rs.storesParams) } else { // Serve directly from latest sc store store = types.Queryable(commitment.NewStore(rs.scStore.GetTreeByName(storeName), rs.logger)) + commitInfo = convertCommitInfo(rs.scStore.LastCommitInfo()) + commitInfo = amendCommitInfo(commitInfo, rs.storesParams) } // trim the path and execute the query @@ -509,14 +522,13 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { if !req.Prove || !rootmulti.RequireProof(subPath) { return res + } else if commitInfo != nil { + // Restore origin path and append proof op. + res.ProofOps.Ops = append(res.ProofOps.Ops, commitInfo.ProofOp(storeName)) } if res.ProofOps == nil || len(res.ProofOps.Ops) == 0 { return sdkerrors.QueryResult(errors.Wrap(sdkerrors.ErrInvalidRequest, "proof is unexpectedly empty; ensure height has not been pruned")) } - commitInfo := convertCommitInfo(rs.scStore.LastCommitInfo()) - commitInfo = amendCommitInfo(commitInfo, rs.storesParams) - // Restore origin path and append proof op. - res.ProofOps.Ops = append(res.ProofOps.Ops, commitInfo.ProofOp(storeName)) return res } diff --git a/storev2/state/store.go b/storev2/state/store.go index d59a310cb..b9c9c7599 100644 --- a/storev2/state/store.go +++ b/storev2/state/store.go @@ -98,6 +98,7 @@ func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { if req.Height > 0 && req.Height > st.version { return sdkerrors.QueryResult(errors.Wrap(sdkerrors.ErrInvalidHeight, "invalid height")) } + res.Height = st.version switch req.Path { case "/key": // get by key res.Key = req.Data // data holds the key bytes @@ -106,7 +107,6 @@ func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { pairs := kv.Pairs{ Pairs: make([]kv.Pair, 0), } - subspace := req.Data res.Key = subspace iterator := types.KVStorePrefixIterator(st, subspace) diff --git a/x/accesscontrol/keeper/keeper.go b/x/accesscontrol/keeper/keeper.go index 950014f5d..8bab2b9d3 100644 --- a/x/accesscontrol/keeper/keeper.go +++ b/x/accesscontrol/keeper/keeper.go @@ -579,11 +579,6 @@ func (k Keeper) GetMessageDependencies(ctx sdk.Context, msg sdk.Msg) []acltypes. ctx.Logger().Error(errorMessage) } } - if dependencyMapping.DynamicEnabled { - // there was an issue with dynamic generation, so lets disable it - // this will not error, the validation check was done in previous calls already - _ = k.SetDependencyMappingDynamicFlag(ctx, messageKey, false) - } return dependencyMapping.AccessOps } diff --git a/x/accesscontrol/keeper/keeper_test.go b/x/accesscontrol/keeper/keeper_test.go index ae30a7930..d0a4695fe 100644 --- a/x/accesscontrol/keeper/keeper_test.go +++ b/x/accesscontrol/keeper/keeper_test.go @@ -112,7 +112,8 @@ func TestInvalidGetMessageDependencies(t *testing.T) { delete(app.AccessControlKeeper.MessageDependencyGeneratorMapper, undelegateKey) accessOps := app.AccessControlKeeper.GetMessageDependencies(ctx, &stakingUndelegate) require.Equal(t, types.SynchronousMessageDependencyMapping("").AccessOps, accessOps) - require.False(t, app.AccessControlKeeper.GetResourceDependencyMapping(ctx, undelegateKey).DynamicEnabled) + // no longer gets disabled such that there arent writes in the dependency generation path + require.True(t, app.AccessControlKeeper.GetResourceDependencyMapping(ctx, undelegateKey).DynamicEnabled) } func TestWasmDependencyMapping(t *testing.T) { @@ -2433,14 +2434,14 @@ func (suite *KeeperTestSuite) TestMessageDependencies() { req.Equal(delegateStaticMapping.AccessOps, accessOps) // verify dynamic got disabled dependencyMapping = app.AccessControlKeeper.GetResourceDependencyMapping(ctx, delegateKey) - req.Equal(false, dependencyMapping.DynamicEnabled) + req.Equal(true, dependencyMapping.DynamicEnabled) // lets also try with undelegate, but this time there is no dynamic generator, so we disable it as well accessOps = app.AccessControlKeeper.GetMessageDependencies(ctx, &stakingUndelegate) req.Equal(undelegateStaticMapping.AccessOps, accessOps) // verify dynamic got disabled dependencyMapping = app.AccessControlKeeper.GetResourceDependencyMapping(ctx, undelegateKey) - req.Equal(false, dependencyMapping.DynamicEnabled) + req.Equal(true, dependencyMapping.DynamicEnabled) } func (suite *KeeperTestSuite) TestImportContractReferences() {