diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 5d13ac151f..79f666aa28 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -637,6 +637,23 @@ func validateBasicTxMsgs(msgs []sdk.Msg) error { return nil } +// validateRuntimeTxMsgs executes basic runtime validator calls for messages. +func validateRuntimeTxMsgs(ctx sdk.Context, msgs []sdk.Msg) error { + if len(msgs) == 0 { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "must contain at least one message") + } + + for _, msg := range msgs { + if runtimeMsg, ok := msg.(sdk.MsgWithRuntimeValidation); ok { + if err := runtimeMsg.ValidateRuntime(ctx); err != nil { + return err + } + } + } + + return nil +} + // Returns the application's deliverState if app is in runTxModeDeliver, // prepareProposalState if app is in runTxPrepareProposal, processProposalState // if app is in runTxProcessProposal, and checkState otherwise. @@ -790,6 +807,9 @@ func (app *BaseApp) runTxOnContext(ctx sdk.Context, mode runTxMode, txBytes []by if err := validateBasicTxMsgs(msgs); err != nil { return sdk.GasInfo{}, nil, nil, 0, err } + if err := validateRuntimeTxMsgs(ctx, msgs); err != nil { + return sdk.GasInfo{}, nil, nil, 0, err + } if app.anteHandler != nil { var ( diff --git a/baseapp/msg_service_router.go b/baseapp/msg_service_router.go index ec68ffd4c4..a1837349fc 100644 --- a/baseapp/msg_service_router.go +++ b/baseapp/msg_service_router.go @@ -122,6 +122,12 @@ func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler inter return nil, err } + if runtimeReq, ok := req.(sdk.MsgWithRuntimeValidation); ok { + if err := runtimeReq.ValidateRuntime(ctx); err != nil { + return nil, err + } + } + if msr.circuitBreaker != nil { msgURL := sdk.MsgTypeURL(req) diff --git a/types/tx_msg.go b/types/tx_msg.go index 41c647e57d..2f6255cb41 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -25,6 +25,17 @@ type ( GetSigners() []AccAddress } + // MsgWithRuntimeValidation defines the interface a transaction message which wants to enable runtime validation. + // Contract: enable runtime validation after Xxxx upgrade. + MsgWithRuntimeValidation interface { + Msg + + // ValidateRuntime does a simple validation, different from ValidateBasic the context information + // will be used to facilitate validation for hardfork. + // Contract: only used for simple validation which needs hardfork logic. + ValidateRuntime(ctx Context) error + } + // Fee defines an interface for an application application-defined concrete // transaction type to be able to set and return the transaction fee. Fee interface { diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index 175cfff7a0..db8d4506c8 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -43,6 +43,12 @@ func (k Keeper) SubmitProposal(ctx sdk.Context, messages []sdk.Msg, metadata, ti return v1.Proposal{}, sdkerrors.Wrap(types.ErrInvalidProposalMsg, err.Error()) } + if runtimeMsg, ok := msg.(sdk.MsgWithRuntimeValidation); ok { + if err := runtimeMsg.ValidateRuntime(ctx); err != nil { + return v1.Proposal{}, sdkerrors.Wrap(types.ErrInvalidProposalMsg, err.Error()) + } + } + signers := msg.GetSigners() if len(signers) != 1 { return v1.Proposal{}, types.ErrInvalidSigner