From 2be528f04f608375ece33d0c115c825606abe866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=90=C3=B4ng=20Li=E1=BB=81u?= <93205232+DongLieu@users.noreply.github.com> Date: Tue, 25 Mar 2025 23:54:43 +0700 Subject: [PATCH] fix(server): allow align block header with skip check heaader in grpc server (#24068) Co-authored-by: Alex | Interchain Labs Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com> --- CHANGELOG.md | 1 + baseapp/grpcserver.go | 15 ++++++++++++++- server/config/config.go | 12 ++++++++---- server/grpc/server.go | 2 +- server/start.go | 9 +++++---- server/types/app.go | 6 +++--- 6 files changed, 32 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2340c13cea..c7ebdc67fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes +* (server) [#24068](https://github.com/cosmos/cosmos-sdk/pull/24068) Allow align block header with skip check header in grpc server. * (x/gov) [#24044](https://github.com/cosmos/cosmos-sdk/pull/24044) Fix some places in which we call Remove inside a Walk (x/gov). * (baseapp) [#24042](https://github.com/cosmos/cosmos-sdk/pull/24042) Fixed a data race inside BaseApp.getContext, found by end-to-end (e2e) tests. * (client/server) [#24059](https://github.com/cosmos/cosmos-sdk/pull/24059) Consistently set viper prefix in client and server. It defaults for the binary name for both client and server. diff --git a/baseapp/grpcserver.go b/baseapp/grpcserver.go index eed6d50aba..126b7c2ba9 100644 --- a/baseapp/grpcserver.go +++ b/baseapp/grpcserver.go @@ -22,6 +22,19 @@ import ( // RegisterGRPCServer registers gRPC services directly with the gRPC server. func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) { + app.RegisterGRPCServerWithSkipCheckHeader(server, false) +} + +// RegisterGRPCServerWithSkipCheckHeader registers gRPC services with the specified gRPC server +// and bypass check header flag. During the commit phase, gRPC queries may be processed before the block header +// is fully updated, causing header checks to fail erroneously. Skipping the header check in these cases prevents +// false negatives and ensures more robust query handling. While bypassing the header check is generally preferred to avoid false +// negatives during the commit phase, there are niche scenarios where someone might want to enable it. +// For instance, if an application requires strict validation to ensure that the query context exactly +// reflects the expected block header (for consistency or security reasons), then enabling header checks +// could be beneficial. However, this strictness comes at the cost of potentially more frequent errors +// when queries occur during the commit phase. +func (app *BaseApp) RegisterGRPCServerWithSkipCheckHeader(server gogogrpc.Server, skipCheckHeader bool) { // Define an interceptor for all gRPC queries: this interceptor will create // a new sdk.Context, and pass it into the query handler. interceptor := func(grpcCtx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { @@ -47,7 +60,7 @@ func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) { // Create the sdk.Context. Passing false as 2nd arg, as we can't // actually support proofs with gRPC right now. - sdkCtx, err := app.CreateQueryContext(height, false) + sdkCtx, err := app.CreateQueryContextWithCheckHeader(height, false, !skipCheckHeader) if err != nil { return nil, err } diff --git a/server/config/config.go b/server/config/config.go index e70615b853..631644c57d 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -139,6 +139,9 @@ type GRPCConfig struct { // MaxSendMsgSize defines the max message size in bytes the server can send. // The default value is math.MaxInt32. MaxSendMsgSize int `mapstructure:"max-send-msg-size"` + + // SkipCheckHeader defines if the gRPC server should bypass check header. + SkipCheckHeader bool `mapstructure:"skip-check-header"` } // GRPCWebConfig defines configuration for the gRPC-web server. @@ -244,10 +247,11 @@ func DefaultConfig() *Config { RPCMaxBodyBytes: 1000000, }, GRPC: GRPCConfig{ - Enable: true, - Address: DefaultGRPCAddress, - MaxRecvMsgSize: DefaultGRPCMaxRecvMsgSize, - MaxSendMsgSize: DefaultGRPCMaxSendMsgSize, + Enable: true, + Address: DefaultGRPCAddress, + MaxRecvMsgSize: DefaultGRPCMaxRecvMsgSize, + MaxSendMsgSize: DefaultGRPCMaxSendMsgSize, + SkipCheckHeader: false, }, GRPCWeb: GRPCWebConfig{ Enable: true, diff --git a/server/grpc/server.go b/server/grpc/server.go index 51bcf3f445..2e63131472 100644 --- a/server/grpc/server.go +++ b/server/grpc/server.go @@ -38,7 +38,7 @@ func NewGRPCServer(clientCtx client.Context, app types.Application, cfg config.G grpc.MaxRecvMsgSize(maxRecvMsgSize), ) - app.RegisterGRPCServer(grpcSrv) + app.RegisterGRPCServerWithSkipCheckHeader(grpcSrv, cfg.SkipCheckHeader) // Reflection allows consumers to build dynamic clients that can write to any // Cosmos SDK application without relying on application packages at compile diff --git a/server/start.go b/server/start.go index 602262d985..faea11cb97 100644 --- a/server/start.go +++ b/server/start.go @@ -91,10 +91,11 @@ const ( FlagAPIEnableUnsafeCORS = "api.enabled-unsafe-cors" // gRPC-related flags - flagGRPCOnly = "grpc-only" - flagGRPCEnable = "grpc.enable" - flagGRPCAddress = "grpc.address" - flagGRPCWebEnable = "grpc-web.enable" + flagGRPCOnly = "grpc-only" + flagGRPCEnable = "grpc.enable" + flagGRPCAddress = "grpc.address" + flagGRPCWebEnable = "grpc-web.enable" + flagGRPCSkipCheckHeader = "grpc.skip-check-header" // mempool flags FlagMempoolMaxTxs = "mempool.max-txs" diff --git a/server/types/app.go b/server/types/app.go index 3b5feab3c0..9eac5ed27c 100644 --- a/server/types/app.go +++ b/server/types/app.go @@ -39,9 +39,9 @@ type ( RegisterAPIRoutes(*api.Server, config.APIConfig) - // RegisterGRPCServer registers gRPC services directly with the gRPC - // server. - RegisterGRPCServer(grpc.Server) + // RegisterGRPCServerWithSkipCheckHeader registers gRPC services directly with the gRPC + // server and bypass check header flag. + RegisterGRPCServerWithSkipCheckHeader(grpc.Server, bool) // RegisterTxService registers the gRPC Query service for tx (such as tx // simulation, fetching txs by hash...).