diff --git a/.github/workflows/auto-assign-prs.yml b/.github/workflows/auto-assign-prs.yml new file mode 100644 index 000000000000..c7bbd8c5dbe7 --- /dev/null +++ b/.github/workflows/auto-assign-prs.yml @@ -0,0 +1,60 @@ +name: Auto Assign Reviewers + +on: + pull_request: + types: [opened, edited, review_requested] + +jobs: + assign-reviewers: + runs-on: ubuntu-latest + + steps: + - name: Check out the repository + uses: actions/checkout@v4 + + - name: Assign reviewers as assignees + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.PRBOT_PAT }} + script: | + const { owner, repo } = context.repo; + + async function getCurrentPR() { + if (context.payload.pull_request) { + return context.payload.pull_request; + } + + const allPRs = await github.rest.pulls.list({ + owner, + repo, + state: 'open', + }); + + return allPRs.data.find(pr => pr.head.sha === context.sha); + } + + const pr = await getCurrentPR(); + if (!pr) { + console.log('No matching PR found.'); + return; + } + + console.log(`Processing PR #${pr.number}`); + + const reviewers = pr.requested_reviewers.map(reviewer => reviewer.login); + + if (reviewers.length === 0) { + console.log('No reviewers found for this PR.'); + return; + } + + console.log(`Current reviewers: ${reviewers.join(', ')}`); + + await github.rest.issues.addAssignees({ + owner, + repo, + issue_number: pr.number, + assignees: reviewers, + }); + + console.log(`Assigned ${reviewers.join(', ')} as assignees to PR #${pr.number}`); diff --git a/CHANGELOG.md b/CHANGELOG.md index 43d1126394b7..a100df6fadfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,8 +54,8 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i * (sims) [#21613](https://github.com/cosmos/cosmos-sdk/pull/21613) Add sims2 framework and factory methods for simpler message factories in modules ### Bug Fixes - -* (sims) [21906](https://github.com/cosmos/cosmos-sdk/pull/21906) Skip sims test when running dry on validators +* (sims) [#21952](https://github.com/cosmos/cosmos-sdk/pull/21952) Use liveness matrix for validator sign status in sims +* (sims) [#21906](https://github.com/cosmos/cosmos-sdk/pull/21906) Skip sims test when running dry on validators * (cli) [#21919](https://github.com/cosmos/cosmos-sdk/pull/21919) Query address-by-acc-num by account_id instead of id. ### API Breaking Changes @@ -139,6 +139,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i * (internal) [#21412](https://github.com/cosmos/cosmos-sdk/pull/21412) Using unsafe.String and unsafe.SliceData. * (client) [#21436](https://github.com/cosmos/cosmos-sdk/pull/21436) Use `address.Codec` from client.Context in `tx.Sign`. * (x/genutil) [#21249](https://github.com/cosmos/cosmos-sdk/pull/21249) Incremental JSON parsing for AppGenesis where possible. +* (testnet) [#21941](https://github.com/cosmos/cosmos-sdk/pull/21941) Regenerate addrbook.json for in place testnet. ### Bug Fixes diff --git a/buf.work.yaml b/buf.work.yaml index 5a070acabfd2..afd7c4ea0d8e 100644 --- a/buf.work.yaml +++ b/buf.work.yaml @@ -2,7 +2,6 @@ version: v1 directories: - proto - x/accounts/proto - - x/auth/proto - x/authz/proto - x/bank/proto - x/circuit/proto diff --git a/server/start.go b/server/start.go index cff5807fbdb4..f9ae56676305 100644 --- a/server/start.go +++ b/server/start.go @@ -9,6 +9,7 @@ import ( "io" "net" "os" + "path/filepath" "runtime/pprof" "strings" "time" @@ -780,6 +781,17 @@ func testnetify[T types.Application](ctx *Context, testnetAppCreator types.AppCr return nil, err } + // Regenerate addrbook.json to prevent peers on old network from causing error logs. + addrBookPath := filepath.Join(config.RootDir, "config", "addrbook.json") + if err := os.Remove(addrBookPath); err != nil && !os.IsNotExist(err) { + return nil, fmt.Errorf("failed to remove existing addrbook.json: %w", err) + } + + emptyAddrBook := []byte("{}") + if err := os.WriteFile(addrBookPath, emptyAddrBook, 0o600); err != nil { + return nil, fmt.Errorf("failed to create empty addrbook.json: %w", err) + } + // Load the comet genesis doc provider. genDocProvider := node.DefaultGenesisDocProviderFunc(config) diff --git a/server/v2/api/grpc/config.go b/server/v2/api/grpc/config.go index 86fb514e70d8..4e9cabc7a418 100644 --- a/server/v2/api/grpc/config.go +++ b/server/v2/api/grpc/config.go @@ -4,14 +4,9 @@ import "math" func DefaultConfig() *Config { return &Config{ - Enable: true, - // DefaultGRPCAddress defines the default address to bind the gRPC server to. - Address: "localhost:9090", - // DefaultGRPCMaxRecvMsgSize defines the default gRPC max message size in - // bytes the server can receive. + Enable: true, + Address: "localhost:9090", MaxRecvMsgSize: 1024 * 1024 * 10, - // DefaultGRPCMaxSendMsgSize defines the default gRPC max message size in - // bytes the server can send. MaxSendMsgSize: math.MaxInt32, } } diff --git a/server/v2/api/grpc/server.go b/server/v2/api/grpc/server.go index 0003f2343222..170343fd512c 100644 --- a/server/v2/api/grpc/server.go +++ b/server/v2/api/grpc/server.go @@ -148,7 +148,7 @@ func (s *Server[T]) Name() string { } func (s *Server[T]) Config() any { - if s.config == nil || s.config == (&Config{}) { + if s.config == nil || s.config.Address == "" { cfg := DefaultConfig() // overwrite the default config with the provided options for _, opt := range s.cfgOptions { @@ -163,6 +163,7 @@ func (s *Server[T]) Config() any { func (s *Server[T]) Start(ctx context.Context) error { if !s.config.Enable { + s.logger.Info(fmt.Sprintf("%s server is disabled via config", s.Name())) return nil } @@ -171,24 +172,12 @@ func (s *Server[T]) Start(ctx context.Context) error { return fmt.Errorf("failed to listen on address %s: %w", s.config.Address, err) } - errCh := make(chan error) - - // Start the gRPC in an external goroutine as Serve is blocking and will return - // an error upon failure, which we'll send on the error channel that will be - // consumed by the for block below. - go func() { - s.logger.Info("starting gRPC server...", "address", s.config.Address) - errCh <- s.grpcSrv.Serve(listener) - }() - - // Start a blocking select to wait for an indication to stop the server or that - // the server failed to start properly. - err = <-errCh - if err != nil { - s.logger.Error("failed to start gRPC server", "err", err) + s.logger.Info("starting gRPC server...", "address", s.config.Address) + if err := s.grpcSrv.Serve(listener); err != nil { + return fmt.Errorf("failed to start gRPC server: %w", err) } - return err + return nil } func (s *Server[T]) Stop(ctx context.Context) error { @@ -198,6 +187,10 @@ func (s *Server[T]) Stop(ctx context.Context) error { s.logger.Info("stopping gRPC server...", "address", s.config.Address) s.grpcSrv.GracefulStop() - return nil } + +// GetGRPCServer returns the underlying gRPC server. +func (s *Server[T]) GetGRPCServer() *grpc.Server { + return s.grpcSrv +} diff --git a/server/v2/api/grpcgateway/config.go b/server/v2/api/grpcgateway/config.go index c5ccb3bfe2d1..773eeb4d58ad 100644 --- a/server/v2/api/grpcgateway/config.go +++ b/server/v2/api/grpcgateway/config.go @@ -2,13 +2,17 @@ package grpcgateway func DefaultConfig() *Config { return &Config{ - Enable: true, + Enable: true, + Address: "localhost:1317", } } type Config struct { // Enable defines if the gRPC-gateway should be enabled. Enable bool `mapstructure:"enable" toml:"enable" comment:"Enable defines if the gRPC-gateway should be enabled."` + + // Address defines the address the gRPC-gateway server binds to. + Address string `mapstructure:"address" toml:"address" comment:"Address defines the address the gRPC-gateway server binds to."` } type CfgOption func(*Config) diff --git a/server/v2/api/grpcgateway/server.go b/server/v2/api/grpcgateway/server.go index 05a6bf1aa829..412c4e4ad81d 100644 --- a/server/v2/api/grpcgateway/server.go +++ b/server/v2/api/grpcgateway/server.go @@ -8,7 +8,6 @@ import ( gateway "github.com/cosmos/gogogateway" "github.com/cosmos/gogoproto/jsonpb" - "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" "google.golang.org/grpc" @@ -17,26 +16,25 @@ import ( serverv2 "cosmossdk.io/server/v2" ) -var _ serverv2.ServerComponent[transaction.Tx] = (*GRPCGatewayServer[transaction.Tx])(nil) - -const ( - ServerName = "grpc-gateway" - - // GRPCBlockHeightHeader is the gRPC header for block height. - GRPCBlockHeightHeader = "x-cosmos-block-height" +var ( + _ serverv2.ServerComponent[transaction.Tx] = (*Server[transaction.Tx])(nil) + _ serverv2.HasConfig = (*Server[transaction.Tx])(nil) ) -type GRPCGatewayServer[T transaction.Tx] struct { +const ServerName = "grpc-gateway" + +type Server[T transaction.Tx] struct { logger log.Logger config *Config cfgOptions []CfgOption - GRPCSrv *grpc.Server - GRPCGatewayRouter *runtime.ServeMux + server *http.Server + gRPCSrv *grpc.Server + gRPCGatewayRouter *runtime.ServeMux } // New creates a new gRPC-gateway server. -func New[T transaction.Tx](grpcSrv *grpc.Server, ir jsonpb.AnyResolver, cfgOptions ...CfgOption) *GRPCGatewayServer[T] { +func New[T transaction.Tx](grpcSrv *grpc.Server, ir jsonpb.AnyResolver, cfgOptions ...CfgOption) *Server[T] { // The default JSON marshaller used by the gRPC-Gateway is unable to marshal non-nullable non-scalar fields. // Using the gogo/gateway package with the gRPC-Gateway WithMarshaler option fixes the scalar field marshaling issue. marshalerOption := &gateway.JSONPb{ @@ -46,9 +44,9 @@ func New[T transaction.Tx](grpcSrv *grpc.Server, ir jsonpb.AnyResolver, cfgOptio AnyResolver: ir, } - return &GRPCGatewayServer[T]{ - GRPCSrv: grpcSrv, - GRPCGatewayRouter: runtime.NewServeMux( + return &Server[T]{ + gRPCSrv: grpcSrv, + gRPCGatewayRouter: runtime.NewServeMux( // Custom marshaler option is required for gogo proto runtime.WithMarshalerOption(runtime.MIMEWildcard, marshalerOption), @@ -64,12 +62,12 @@ func New[T transaction.Tx](grpcSrv *grpc.Server, ir jsonpb.AnyResolver, cfgOptio } } -func (g *GRPCGatewayServer[T]) Name() string { +func (s *Server[T]) Name() string { return ServerName } -func (s *GRPCGatewayServer[T]) Config() any { - if s.config == nil || s.config == (&Config{}) { +func (s *Server[T]) Config() any { + if s.config == nil || s.config.Address == "" { cfg := DefaultConfig() // overwrite the default config with the provided options for _, opt := range s.cfgOptions { @@ -82,7 +80,7 @@ func (s *GRPCGatewayServer[T]) Config() any { return s.config } -func (s *GRPCGatewayServer[T]) Init(appI serverv2.AppI[transaction.Tx], cfg map[string]any, logger log.Logger) error { +func (s *Server[T]) Init(appI serverv2.AppI[transaction.Tx], cfg map[string]any, logger log.Logger) error { serverCfg := s.Config().(*Config) if len(cfg) > 0 { if err := serverv2.UnmarshalSubConfig(cfg, s.Name(), &serverCfg); err != nil { @@ -90,42 +88,43 @@ func (s *GRPCGatewayServer[T]) Init(appI serverv2.AppI[transaction.Tx], cfg map[ } } - // Register the gRPC-Gateway server. - // appI.RegisterGRPCGatewayRoutes(s.GRPCGatewayRouter, s.GRPCSrv) + // TODO: register the gRPC-Gateway routes - s.logger = logger + s.logger = logger.With(log.ModuleKey, s.Name()) s.config = serverCfg return nil } -func (s *GRPCGatewayServer[T]) Start(ctx context.Context) error { +func (s *Server[T]) Start(ctx context.Context) error { if !s.config.Enable { + s.logger.Info(fmt.Sprintf("%s server is disabled via config", s.Name())) return nil } - // TODO start a normal Go http server (and do not leverage comet's like https://github.com/cosmos/cosmos-sdk/blob/9df6019de6ee7999fe9864bac836deb2f36dd44a/server/api/server.go#L98) + mux := http.NewServeMux() + mux.Handle("/", s.gRPCGatewayRouter) - return nil -} + s.server = &http.Server{ + Addr: s.config.Address, + Handler: mux, + } -func (s *GRPCGatewayServer[T]) Stop(ctx context.Context) error { - if !s.config.Enable { - return nil + s.logger.Info("starting gRPC-Gateway server...", "address", s.config.Address) + if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + return fmt.Errorf("failed to start gRPC-Gateway server: %w", err) } return nil } -// Register implements registers a grpc-gateway server -func (s *GRPCGatewayServer[T]) Register(r mux.Router) error { - // configure grpc-gatway server - r.PathPrefix("/").Handler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - // Fall back to grpc gateway server. - s.GRPCGatewayRouter.ServeHTTP(w, req) - })) +func (s *Server[T]) Stop(ctx context.Context) error { + if !s.config.Enable { + return nil + } - return nil + s.logger.Info("stopping gRPC-Gateway server...", "address", s.config.Address) + return s.server.Shutdown(ctx) } // CustomGRPCHeaderMatcher for mapping request headers to @@ -134,6 +133,9 @@ func (s *GRPCGatewayServer[T]) Register(r mux.Router) error { // gRPC metadata after removing prefix 'Grpc-Metadata-'. We can use this // CustomGRPCHeaderMatcher if headers don't start with `Grpc-Metadata-` func CustomGRPCHeaderMatcher(key string) (string, bool) { + // GRPCBlockHeightHeader is the gRPC header for block height. + const GRPCBlockHeightHeader = "x-cosmos-block-height" + switch strings.ToLower(key) { case GRPCBlockHeightHeader: return GRPCBlockHeightHeader, true diff --git a/server/v2/api/telemetry/config.go b/server/v2/api/telemetry/config.go index 63a37ed1f39d..2619665d1844 100644 --- a/server/v2/api/telemetry/config.go +++ b/server/v2/api/telemetry/config.go @@ -1,13 +1,32 @@ package telemetry -type Config struct { - // Prefixed with keys to separate services - ServiceName string `mapstructure:"service-name" toml:"service-name" comment:"Prefixed with keys to separate services."` +func DefaultConfig() *Config { + return &Config{ + Enable: true, + Address: "localhost:1318", + ServiceName: "", + EnableHostname: false, + EnableHostnameLabel: false, + EnableServiceLabel: false, + PrometheusRetentionTime: 0, + GlobalLabels: nil, + MetricsSink: "", + StatsdAddr: "", + DatadogHostname: "", + } +} - // Enabled enables the application telemetry functionality. When enabled, +type Config struct { + // Enable enables the application telemetry functionality. When enabled, // an in-memory sink is also enabled by default. Operators may also enabled // other sinks such as Prometheus. - Enabled bool `mapstructure:"enabled" toml:"enabled" comment:"Enabled enables the application telemetry functionality. When enabled, an in-memory sink is also enabled by default. Operators may also enabled other sinks such as Prometheus."` + Enable bool `mapstructure:"enable" toml:"enable" comment:"Enable enables the application telemetry functionality. When enabled, an in-memory sink is also enabled by default. Operators may also enabled other sinks such as Prometheus."` + + // Address defines the API server to listen on + Address string `mapstructure:"address" toml:"address" comment:"Address defines the metrics server address to bind to."` + + // Prefixed with keys to separate services + ServiceName string `mapstructure:"service-name" toml:"service-name" comment:"Prefixed with keys to separate services."` // Enable prefixing gauge values with hostname EnableHostname bool `mapstructure:"enable-hostname" toml:"enable-hostname" comment:"Enable prefixing gauge values with hostname."` diff --git a/server/v2/api/telemetry/metrics.go b/server/v2/api/telemetry/metrics.go index 75e857bb8ec4..3dd9e3d55b94 100644 --- a/server/v2/api/telemetry/metrics.go +++ b/server/v2/api/telemetry/metrics.go @@ -57,12 +57,8 @@ type GatherResponse struct { ContentType string } -// New creates a new instance of Metrics -func New(cfg Config) (_ *Metrics, rerr error) { - if !cfg.Enabled { - return nil, nil - } - +// NewMetrics creates a new instance of Metrics +func NewMetrics(cfg *Config) (*Metrics, error) { if numGlobalLabels := len(cfg.GlobalLabels); numGlobalLabels > 0 { parsedGlobalLabels := make([]metrics.Label, numGlobalLabels) for i, gl := range cfg.GlobalLabels { @@ -89,12 +85,11 @@ func New(cfg Config) (_ *Metrics, rerr error) { sink = memSink inMemSig := metrics.DefaultInmemSignal(memSink) defer func() { - if rerr != nil { + if err != nil { inMemSig.Stop() } }() } - if err != nil { return nil, err } diff --git a/server/v2/api/telemetry/server.go b/server/v2/api/telemetry/server.go index a944fc7f4f03..411b1bda797d 100644 --- a/server/v2/api/telemetry/server.go +++ b/server/v2/api/telemetry/server.go @@ -1,47 +1,126 @@ package telemetry import ( + "context" "encoding/json" "fmt" "net/http" "strings" - "github.com/gorilla/mux" + "cosmossdk.io/core/transaction" + "cosmossdk.io/log" + serverv2 "cosmossdk.io/server/v2" ) -func RegisterMetrics(r mux.Router, cfg Config) (*Metrics, error) { - m, err := New(cfg) +var ( + _ serverv2.ServerComponent[transaction.Tx] = (*Server[transaction.Tx])(nil) + _ serverv2.HasConfig = (*Server[transaction.Tx])(nil) +) + +const ServerName = "telemetry" + +type Server[T transaction.Tx] struct { + config *Config + logger log.Logger + server *http.Server + metrics *Metrics +} + +// New creates a new telemetry server. +func New[T transaction.Tx]() *Server[T] { + return &Server[T]{} +} + +// Name returns the server name. +func (s *Server[T]) Name() string { + return ServerName +} + +func (s *Server[T]) Config() any { + if s.config == nil || s.config.Address == "" { + return DefaultConfig() + } + + return s.config +} + +// Init implements serverv2.ServerComponent. +func (s *Server[T]) Init(appI serverv2.AppI[T], cfg map[string]any, logger log.Logger) error { + serverCfg := s.Config().(*Config) + if len(cfg) > 0 { + if err := serverv2.UnmarshalSubConfig(cfg, s.Name(), &serverCfg); err != nil { + return fmt.Errorf("failed to unmarshal config: %w", err) + } + } + s.config = serverCfg + s.logger = logger.With(log.ModuleKey, s.Name()) + + metrics, err := NewMetrics(s.config) if err != nil { - return nil, err + return fmt.Errorf("failed to initialize metrics: %w", err) } + s.metrics = metrics - metricsHandler := func(w http.ResponseWriter, r *http.Request) { - format := strings.TrimSpace(r.FormValue("format")) + return nil +} - gr, err := m.Gather(format) - if err != nil { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - bz, err := json.Marshal(errorResponse{Code: 400, Error: fmt.Sprintf("failed to gather metrics: %s", err)}) - if err != nil { - return - } - _, _ = w.Write(bz) +func (s *Server[T]) Start(ctx context.Context) error { + if !s.config.Enable { + s.logger.Info(fmt.Sprintf("%s server is disabled via config", s.Name())) + return nil + } - return - } + mux := http.NewServeMux() + mux.HandleFunc("/", s.metricsHandler) + // keeping /metrics for backwards compatibility + mux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, "/", http.StatusMovedPermanently) + }) - w.Header().Set("Content-Type", gr.ContentType) - _, _ = w.Write(gr.Metrics) + s.server = &http.Server{ + Addr: s.config.Address, + Handler: mux, } - r.HandleFunc("/metrics", metricsHandler).Methods("GET") + s.logger.Info("starting telemetry server...", "address", s.config.Address) + if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + return fmt.Errorf("failed to start telemetry server: %w", err) + } - return m, nil + return nil } -// errorResponse defines the attributes of a JSON error response. -type errorResponse struct { - Code int `json:"code,omitempty"` - Error string `json:"error"` +func (s *Server[T]) Stop(ctx context.Context) error { + if !s.config.Enable || s.server == nil { + return nil + } + + s.logger.Info("stopping telemetry server...", "address", s.config.Address) + return s.server.Shutdown(ctx) +} + +func (s *Server[T]) metricsHandler(w http.ResponseWriter, r *http.Request) { + format := strings.TrimSpace(r.FormValue("format")) + + // errorResponse defines the attributes of a JSON error response. + type errorResponse struct { + Code int `json:"code,omitempty"` + Error string `json:"error"` + } + + gr, err := s.metrics.Gather(format) + if err != nil { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusBadRequest) + bz, err := json.Marshal(errorResponse{Code: 400, Error: fmt.Sprintf("failed to gather metrics: %s", err)}) + if err != nil { + return + } + _, _ = w.Write(bz) + + return + } + + w.Header().Set("Content-Type", gr.ContentType) + _, _ = w.Write(gr.Metrics) } diff --git a/server/v2/cometbft/server.go b/server/v2/cometbft/server.go index 2f402522c099..21b6d59ddc72 100644 --- a/server/v2/cometbft/server.go +++ b/server/v2/cometbft/server.go @@ -271,7 +271,7 @@ func (s *CometBFTServer[T]) CLICommands() serverv2.CLIConfig { // Config returns the (app.toml) server configuration. func (s *CometBFTServer[T]) Config() any { - if s.config.AppTomlConfig == nil || s.config.AppTomlConfig == (&AppTomlConfig{}) { + if s.config.AppTomlConfig == nil || s.config.AppTomlConfig.Address == "" { cfg := &Config{AppTomlConfig: DefaultAppTomlConfig()} // overwrite the default config with the provided options for _, opt := range s.cfgOptions { diff --git a/server/v2/go.mod b/server/v2/go.mod index 7ccfca6f628c..d996ab3d3681 100644 --- a/server/v2/go.mod +++ b/server/v2/go.mod @@ -22,7 +22,6 @@ require ( github.com/cosmos/gogogateway v1.2.0 github.com/cosmos/gogoproto v1.7.0 github.com/golang/protobuf v1.5.4 - github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-metrics v0.5.3 diff --git a/server/v2/go.sum b/server/v2/go.sum index 748913b517f3..1a64fd341f6c 100644 --- a/server/v2/go.sum +++ b/server/v2/go.sum @@ -150,8 +150,6 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= diff --git a/server/v2/store/commands.go b/server/v2/store/commands.go index 7c50995f923e..3b9f175c7b0f 100644 --- a/server/v2/store/commands.go +++ b/server/v2/store/commands.go @@ -16,8 +16,8 @@ import ( "cosmossdk.io/store/v2/root" ) -// QueryBlockResultsCmd implements the default command for a BlockResults query. -func (s *StoreComponent[T]) PrunesCmd() *cobra.Command { +// PrunesCmd implements the default command for pruning app history states. +func (s *Server[T]) PrunesCmd() *cobra.Command { cmd := &cobra.Command{ Use: "prune [pruning-method]", Short: "Prune app history states by keeping the recent heights and deleting old heights", diff --git a/server/v2/store/server.go b/server/v2/store/server.go index a5f464c964a5..c50a53dc6e24 100644 --- a/server/v2/store/server.go +++ b/server/v2/store/server.go @@ -12,49 +12,49 @@ import ( ) var ( - _ serverv2.ServerComponent[transaction.Tx] = (*StoreComponent[transaction.Tx])(nil) - _ serverv2.HasConfig = (*StoreComponent[transaction.Tx])(nil) - _ serverv2.HasCLICommands = (*StoreComponent[transaction.Tx])(nil) + _ serverv2.ServerComponent[transaction.Tx] = (*Server[transaction.Tx])(nil) + _ serverv2.HasConfig = (*Server[transaction.Tx])(nil) + _ serverv2.HasCLICommands = (*Server[transaction.Tx])(nil) ) const ServerName = "store" -// StoreComponent manages store config -// and contains prune & snapshot commands -type StoreComponent[T transaction.Tx] struct { +// Server manages store config and contains prune & snapshot commands +type Server[T transaction.Tx] struct { config *Config // saving appCreator for only RestoreSnapshotCmd appCreator serverv2.AppCreator[T] } -func New[T transaction.Tx](appCreator serverv2.AppCreator[T]) *StoreComponent[T] { - return &StoreComponent[T]{appCreator: appCreator} +func New[T transaction.Tx](appCreator serverv2.AppCreator[T]) *Server[T] { + return &Server[T]{appCreator: appCreator} } -func (s *StoreComponent[T]) Init(appI serverv2.AppI[T], cfg map[string]any, logger log.Logger) error { - serverCfg := DefaultConfig() +func (s *Server[T]) Init(appI serverv2.AppI[T], cfg map[string]any, logger log.Logger) error { + serverCfg := s.Config().(*Config) if len(cfg) > 0 { if err := serverv2.UnmarshalSubConfig(cfg, s.Name(), &serverCfg); err != nil { return fmt.Errorf("failed to unmarshal config: %w", err) } } + s.config = serverCfg return nil } -func (s *StoreComponent[T]) Name() string { +func (s *Server[T]) Name() string { return ServerName } -func (s *StoreComponent[T]) Start(ctx context.Context) error { +func (s *Server[T]) Start(ctx context.Context) error { return nil } -func (s *StoreComponent[T]) Stop(ctx context.Context) error { +func (s *Server[T]) Stop(ctx context.Context) error { return nil } -func (s *StoreComponent[T]) CLICommands() serverv2.CLIConfig { +func (s *Server[T]) CLICommands() serverv2.CLIConfig { return serverv2.CLIConfig{ Commands: []*cobra.Command{ s.PrunesCmd(), @@ -68,10 +68,10 @@ func (s *StoreComponent[T]) CLICommands() serverv2.CLIConfig { } } -func (g *StoreComponent[T]) Config() any { - if g.config == nil || g.config == (&Config{}) { +func (s *Server[T]) Config() any { + if s.config == nil || s.config.AppDBBackend == "" { return DefaultConfig() } - return g.config + return s.config } diff --git a/server/v2/store/snapshot.go b/server/v2/store/snapshot.go index 2c106f85fe69..b804e34b71c8 100644 --- a/server/v2/store/snapshot.go +++ b/server/v2/store/snapshot.go @@ -24,8 +24,8 @@ import ( const SnapshotFileName = "_snapshot" -// QueryBlockResultsCmd implements the default command for a BlockResults query. -func (s *StoreComponent[T]) ExportSnapshotCmd() *cobra.Command { +// ExportSnapshotCmd exports app state to snapshot store. +func (s *Server[T]) ExportSnapshotCmd() *cobra.Command { cmd := &cobra.Command{ Use: "export", Short: "Export app state to snapshot store", @@ -76,7 +76,7 @@ func (s *StoreComponent[T]) ExportSnapshotCmd() *cobra.Command { } // RestoreSnapshotCmd returns a command to restore a snapshot -func (s *StoreComponent[T]) RestoreSnapshotCmd(newApp serverv2.AppCreator[T]) *cobra.Command { +func (s *Server[T]) RestoreSnapshotCmd(newApp serverv2.AppCreator[T]) *cobra.Command { cmd := &cobra.Command{ Use: "restore ", Short: "Restore app state from local snapshot", @@ -113,7 +113,7 @@ func (s *StoreComponent[T]) RestoreSnapshotCmd(newApp serverv2.AppCreator[T]) *c } // ListSnapshotsCmd returns the command to list local snapshots -func (s *StoreComponent[T]) ListSnapshotsCmd() *cobra.Command { +func (s *Server[T]) ListSnapshotsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "list", Short: "List local snapshots", @@ -139,7 +139,7 @@ func (s *StoreComponent[T]) ListSnapshotsCmd() *cobra.Command { } // DeleteSnapshotCmd returns the command to delete a local snapshot -func (s *StoreComponent[T]) DeleteSnapshotCmd() *cobra.Command { +func (s *Server[T]) DeleteSnapshotCmd() *cobra.Command { return &cobra.Command{ Use: "delete ", Short: "Delete a local snapshot", @@ -167,7 +167,7 @@ func (s *StoreComponent[T]) DeleteSnapshotCmd() *cobra.Command { } // DumpArchiveCmd returns a command to dump the snapshot as portable archive format -func (s *StoreComponent[T]) DumpArchiveCmd() *cobra.Command { +func (s *Server[T]) DumpArchiveCmd() *cobra.Command { cmd := &cobra.Command{ Use: "dump ", Short: "Dump the snapshot as portable archive format", @@ -260,7 +260,7 @@ func (s *StoreComponent[T]) DumpArchiveCmd() *cobra.Command { } // LoadArchiveCmd load a portable archive format snapshot into snapshot store -func (s *StoreComponent[T]) LoadArchiveCmd() *cobra.Command { +func (s *Server[T]) LoadArchiveCmd() *cobra.Command { return &cobra.Command{ Use: "load ", Short: "Load a snapshot archive file (.tar.gz) into snapshot store", diff --git a/simapp/v2/simdv2/cmd/commands.go b/simapp/v2/simdv2/cmd/commands.go index 916f4b2be9da..addc7eeb768b 100644 --- a/simapp/v2/simdv2/cmd/commands.go +++ b/simapp/v2/simdv2/cmd/commands.go @@ -15,6 +15,7 @@ import ( runtimev2 "cosmossdk.io/runtime/v2" serverv2 "cosmossdk.io/server/v2" "cosmossdk.io/server/v2/api/grpc" + "cosmossdk.io/server/v2/api/telemetry" "cosmossdk.io/server/v2/cometbft" "cosmossdk.io/server/v2/store" "cosmossdk.io/simapp/v2" @@ -81,6 +82,7 @@ func initRootCmd[T transaction.Tx]( ), grpc.New[T](), store.New[T](newApp), + telemetry.New[T](), ); err != nil { panic(err) } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 0c8a1ef3a3b0..d23bcc57b090 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -1147,7 +1147,9 @@ func (rs *Store) flushMetadata(db corestore.KVStoreWithBatch, version int64, cIn rs.logger.Debug("flushing metadata", "height", version) batch := db.NewBatch() defer func() { - _ = batch.Close() + if err := batch.Close(); err != nil { + rs.logger.Error("call flushMetadata error on batch close", "err", err) + } }() if cInfo != nil { diff --git a/store/v2/commitment/metadata.go b/store/v2/commitment/metadata.go index d7aea487c706..8c1e7f1f8a9d 100644 --- a/store/v2/commitment/metadata.go +++ b/store/v2/commitment/metadata.go @@ -2,6 +2,7 @@ package commitment import ( "bytes" + "errors" "fmt" corestore "cosmossdk.io/core/store" @@ -158,9 +159,7 @@ func (m *MetadataStore) deleteRemovedStoreKeys(version uint64, removeStore func( batch := m.kv.NewBatch() defer func() { - if berr := batch.Close(); berr != nil { - err = berr - } + err = errors.Join(err, batch.Close()) }() for _, storeKey := range removedStoreKeys { if err := removeStore(storeKey, version); err != nil { diff --git a/tests/systemtests/fraud_test.go b/tests/systemtests/fraud_test.go index a383669eeff6..043db59a545e 100644 --- a/tests/systemtests/fraud_test.go +++ b/tests/systemtests/fraud_test.go @@ -11,8 +11,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) func TestValidatorDoubleSign(t *testing.T) { @@ -27,43 +25,38 @@ func TestValidatorDoubleSign(t *testing.T) { // Check the validator is in the active set rsp := cli.CustomQuery("q", "staking", "validators") t.Log(rsp) - nodePowerBefore := QueryCometValidatorPowerForNode(t, sut, 0) + validatorPubKey := LoadValidatorPubKeyForNode(t, sut, 0) + rpc, pkBz := sut.RPCClient(t), validatorPubKey.Bytes() + + nodePowerBefore := QueryCometValidatorPower(rpc, pkBz) require.NotEmpty(t, nodePowerBefore) t.Logf("nodePowerBefore: %v", nodePowerBefore) - var validatorPubKey cryptotypes.PubKey newNode := sut.AddFullnode(t, func(nodeNumber int, nodePath string) { valKeyFile := filepath.Join(WorkDir, nodePath, "config", "priv_validator_key.json") _ = os.Remove(valKeyFile) _, err := copyFile(filepath.Join(WorkDir, sut.nodePath(0), "config", "priv_validator_key.json"), valKeyFile) require.NoError(t, err) - validatorPubKey = LoadValidatorPubKeyForNode(t, sut, nodeNumber) }) sut.AwaitNodeUp(t, fmt.Sprintf("http://%s:%d", newNode.IP, newNode.RPCPort)) // let's wait some blocks to have evidence and update persisted - rpc := sut.RPCClient(t) - pkBz := validatorPubKey.Bytes() - for i := 0; i < 20; i++ { + var nodePowerAfter int64 = -1 + for i := 0; i < 30; i++ { sut.AwaitNextBlock(t) - if QueryCometValidatorPower(rpc, pkBz) == 0 { + if nodePowerAfter = QueryCometValidatorPower(rpc, pkBz); nodePowerAfter == 0 { break } + t.Logf("wait %d", sut.CurrentHeight()) } - sut.AwaitNextBlock(t) - // then comet status updated - nodePowerAfter := QueryCometValidatorPowerForNode(t, sut, 0) require.Empty(t, nodePowerAfter) - t.Logf("nodePowerAfter: %v", nodePowerAfter) // and sdk status updated byzantineOperatorAddr := cli.GetKeyAddrPrefix("node0", "val") rsp = cli.CustomQuery("q", "staking", "validator", byzantineOperatorAddr) assert.True(t, gjson.Get(rsp, "validator.jailed").Bool(), rsp) - t.Log("let's run for some blocks to confirm all good") - for i := 0; i < 10; i++ { - sut.AwaitNextBlock(t) - } + // let's run for some blocks to confirm all good + sut.AwaitNBlocks(t, 5) } diff --git a/tools/confix/data/v0.52-app.toml b/tools/confix/data/v0.52-app.toml index d6e3cf95ab01..f97f48044502 100644 --- a/tools/confix/data/v0.52-app.toml +++ b/tools/confix/data/v0.52-app.toml @@ -66,7 +66,7 @@ index-events = [] # IavlCacheSize set the size of the iavl tree cache (in number of nodes). iavl-cache-size = 781250 -# IAVLDisableFastNode enables or disables the fast node feature of IAVL. +# IAVLDisableFastNode enables or disables the fast node feature of IAVL. # Default is false. iavl-disable-fastnode = false @@ -223,9 +223,3 @@ stop-node-on-err = true # Note, this configuration only applies to SDK built-in app-side mempool # implementations. max-txs = -1 - -[custom] - -# That field will be parsed by server.InterceptConfigsPreRunHandler and held by viper. -# Do not forget to add quotes around the value if it is a string. -custom-field = "anything" diff --git a/tools/confix/data/v2-app.toml b/tools/confix/data/v2-app.toml index 8f7f7f9940d2..c4f19348ce52 100644 --- a/tools/confix/data/v2-app.toml +++ b/tools/confix/data/v2-app.toml @@ -16,6 +16,11 @@ trace = false # standalone starts the application without the CometBFT node. The node should be started separately. standalone = false +# mempool defines the configuration for the SDK built-in app-side mempool implementations. +[comet.mempool] +# max-txs defines the maximum number of transactions that can be in the mempool. A value of 0 indicates an unbounded mempool, a negative value disables the app-side mempool. +max-txs = -1 + [grpc] # Enable defines if the gRPC server should be enabled. enable = true @@ -37,27 +42,53 @@ minimum-gas-prices = '0stake' app-db-backend = 'goleveldb' [store.options] -# State storage database type. Currently we support: 0 for SQLite, 1 for Pebble -ss-type = 0 -# State commitment database type. Currently we support:0 for iavl, 1 for iavl v2 -sc-type = 0 +# SState storage database type. Currently we support: "sqlite", "pebble" and "rocksdb" +ss-type = 'sqlite' +# State commitment database type. Currently we support: "iavl" and "iavl-v2" +sc-type = 'iavl' # Pruning options for state storage [store.options.ss-pruning-option] # Number of recent heights to keep on disk. keep-recent = 2 # Height interval at which pruned heights are removed from disk. -interval = 1 +interval = 100 # Pruning options for state commitment [store.options.sc-pruning-option] # Number of recent heights to keep on disk. keep-recent = 2 # Height interval at which pruned heights are removed from disk. -interval = 1 +interval = 100 [store.options.iavl-config] # CacheSize set the size of the iavl tree cache. cache-size = 100000 # If true, the tree will work like no fast storage and always not upgrade fast storage. skip-fast-storage-upgrade = true + +[telemetry] +# Enable enables the application telemetry functionality. When enabled, an in-memory sink is also enabled by default. Operators may also enabled other sinks such as Prometheus. +enable = true +# Address defines the metrics server address to bind to. +address = 'localhost:1338' +# Prefixed with keys to separate services. +service-name = '' +# Enable prefixing gauge values with hostname. +enable-hostname = false +# Enable adding hostname to labels. +enable-hostname-label = false +# Enable adding service to labels. +enable-service-label = false +# PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. It defines the retention duration in seconds. +prometheus-retention-time = 0 +# GlobalLabels defines a global set of name/value label tuples applied to all metrics emitted using the wrapper functions defined in telemetry package. +# Example: +# [["chain_id", "cosmoshub-1"]] +global-labels = [] +# MetricsSink defines the type of metrics backend to use. Default is in memory +metrics-sink = '' +# StatsdAddr defines the address of a statsd server to send metrics to. Only utilized if MetricsSink is set to "statsd" or "dogstatsd". +stats-addr = '' +# DatadogHostname defines the hostname to use when emitting metrics to Datadog. Only utilized if MetricsSink is set to "dogstatsd". +data-dog-hostname = '' diff --git a/tools/confix/migrations.go b/tools/confix/migrations.go index 86bf1affee24..77fc4a671cb4 100644 --- a/tools/confix/migrations.go +++ b/tools/confix/migrations.go @@ -55,6 +55,8 @@ var v2KeyChanges = v2KeyChangesMap{ }, "iavl-cache-size": []string{"store.options.iavl-config.cache-size"}, "iavl-disable-fastnode": []string{"store.options.iavl-config.skip-fast-storage-upgrade"}, + "telemetry.enabled": []string{"telemetry.enable"}, + "mempool.max-txs": []string{"comet.mempool.max-txs"}, // Add other key mappings as needed } diff --git a/tools/cosmovisor/testdata/download/cosmovisor/genesis/bin/autod b/tools/cosmovisor/testdata/download/cosmovisor/genesis/bin/autod index 67dcba9c63b1..c1b2348787ae 100755 --- a/tools/cosmovisor/testdata/download/cosmovisor/genesis/bin/autod +++ b/tools/cosmovisor/testdata/download/cosmovisor/genesis/bin/autod @@ -10,7 +10,7 @@ cat > "$3" < "$3" < 0 { + n += 2 + l + runtime.Sov(uint64(l)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -2431,6 +2456,15 @@ func (x *fastReflection_ABitOfEverything) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if len(x.PrettyBytes) > 0 { + i -= len(x.PrettyBytes) + copy(dAtA[i:], x.PrettyBytes) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.PrettyBytes))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa2 + } if x.Sf64 != 0 { i -= 8 binary.LittleEndian.PutUint64(dAtA[i:], uint64(x.Sf64)) @@ -2981,6 +3015,40 @@ func (x *fastReflection_ABitOfEverything) ProtoMethods() *protoiface.Methods { } x.Sf64 = int64(binary.LittleEndian.Uint64(dAtA[iNdEx:])) iNdEx += 8 + case 20: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field PrettyBytes", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.PrettyBytes = append(x.PrettyBytes[:0], dAtA[iNdEx:postIndex]...) + if x.PrettyBytes == nil { + x.PrettyBytes = []byte{} + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -4178,22 +4246,23 @@ type ABitOfEverything struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Message *NestedMessage `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` - Enum AnEnum `protobuf:"varint,2,opt,name=enum,proto3,enum=testpb.AnEnum" json:"enum,omitempty"` - Repeated []int32 `protobuf:"varint,6,rep,packed,name=repeated,proto3" json:"repeated,omitempty"` - Str string `protobuf:"bytes,7,opt,name=str,proto3" json:"str,omitempty"` - Bool bool `protobuf:"varint,8,opt,name=bool,proto3" json:"bool,omitempty"` - Bytes []byte `protobuf:"bytes,9,opt,name=bytes,proto3" json:"bytes,omitempty"` - I32 int32 `protobuf:"varint,10,opt,name=i32,proto3" json:"i32,omitempty"` - F32 uint32 `protobuf:"fixed32,11,opt,name=f32,proto3" json:"f32,omitempty"` - U32 uint32 `protobuf:"varint,12,opt,name=u32,proto3" json:"u32,omitempty"` - Si32 int32 `protobuf:"zigzag32,13,opt,name=si32,proto3" json:"si32,omitempty"` - Sf32 int32 `protobuf:"fixed32,14,opt,name=sf32,proto3" json:"sf32,omitempty"` - I64 int64 `protobuf:"varint,15,opt,name=i64,proto3" json:"i64,omitempty"` - F64 uint64 `protobuf:"fixed64,16,opt,name=f64,proto3" json:"f64,omitempty"` - U64 uint64 `protobuf:"varint,17,opt,name=u64,proto3" json:"u64,omitempty"` - Si64 int64 `protobuf:"zigzag64,18,opt,name=si64,proto3" json:"si64,omitempty"` - Sf64 int64 `protobuf:"fixed64,19,opt,name=sf64,proto3" json:"sf64,omitempty"` + Message *NestedMessage `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + Enum AnEnum `protobuf:"varint,2,opt,name=enum,proto3,enum=testpb.AnEnum" json:"enum,omitempty"` + Repeated []int32 `protobuf:"varint,6,rep,packed,name=repeated,proto3" json:"repeated,omitempty"` + Str string `protobuf:"bytes,7,opt,name=str,proto3" json:"str,omitempty"` + Bool bool `protobuf:"varint,8,opt,name=bool,proto3" json:"bool,omitempty"` + Bytes []byte `protobuf:"bytes,9,opt,name=bytes,proto3" json:"bytes,omitempty"` + I32 int32 `protobuf:"varint,10,opt,name=i32,proto3" json:"i32,omitempty"` + F32 uint32 `protobuf:"fixed32,11,opt,name=f32,proto3" json:"f32,omitempty"` + U32 uint32 `protobuf:"varint,12,opt,name=u32,proto3" json:"u32,omitempty"` + Si32 int32 `protobuf:"zigzag32,13,opt,name=si32,proto3" json:"si32,omitempty"` + Sf32 int32 `protobuf:"fixed32,14,opt,name=sf32,proto3" json:"sf32,omitempty"` + I64 int64 `protobuf:"varint,15,opt,name=i64,proto3" json:"i64,omitempty"` + F64 uint64 `protobuf:"fixed64,16,opt,name=f64,proto3" json:"f64,omitempty"` + U64 uint64 `protobuf:"varint,17,opt,name=u64,proto3" json:"u64,omitempty"` + Si64 int64 `protobuf:"zigzag64,18,opt,name=si64,proto3" json:"si64,omitempty"` + Sf64 int64 `protobuf:"fixed64,19,opt,name=sf64,proto3" json:"sf64,omitempty"` + PrettyBytes []byte `protobuf:"bytes,20,opt,name=pretty_bytes,json=prettyBytes,proto3" json:"pretty_bytes,omitempty"` } func (x *ABitOfEverything) Reset() { @@ -4328,6 +4397,13 @@ func (x *ABitOfEverything) GetSf64() int64 { return 0 } +func (x *ABitOfEverything) GetPrettyBytes() []byte { + if x != nil { + return x.PrettyBytes + } + return nil +} + type Duration struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -4450,7 +4526,7 @@ var file_testpb_test_proto_rawDesc = []byte{ 0x09, 0x57, 0x69, 0x74, 0x68, 0x41, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x10, 0x9a, 0xe7, 0xb0, 0x2a, 0x0b, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x52, 0x06, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x31, 0x22, 0x92, 0x03, 0x0a, 0x10, 0x41, 0x42, 0x69, 0x74, 0x4f, 0x66, 0x45, + 0x65, 0x6c, 0x64, 0x31, 0x22, 0xbf, 0x03, 0x0a, 0x10, 0x41, 0x42, 0x69, 0x74, 0x4f, 0x66, 0x45, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x12, 0x2f, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, @@ -4474,32 +4550,35 @@ var file_testpb_test_proto_rawDesc = []byte{ 0x11, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x75, 0x36, 0x34, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x36, 0x34, 0x18, 0x12, 0x20, 0x01, 0x28, 0x12, 0x52, 0x04, 0x73, 0x69, 0x36, 0x34, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x66, 0x36, 0x34, 0x18, 0x13, 0x20, 0x01, 0x28, 0x10, 0x52, 0x04, 0x73, 0x66, - 0x36, 0x34, 0x3a, 0x15, 0x8a, 0xe7, 0xb0, 0x2a, 0x10, 0x41, 0x42, 0x69, 0x74, 0x4f, 0x66, 0x45, - 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x22, 0x7b, 0x0a, 0x08, 0x44, 0x75, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x47, 0x0a, 0x0d, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x62, 0x61, 0x72, 0x3a, 0x12, 0x8a, 0xe7, 0xb0, - 0x2a, 0x0d, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, - 0x29, 0x0a, 0x06, 0x41, 0x6e, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, - 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x4e, 0x45, 0x10, - 0x01, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x57, 0x4f, 0x10, 0x02, 0x42, 0x83, 0x01, 0x0a, 0x0a, 0x63, - 0x6f, 0x6d, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x42, 0x09, 0x54, 0x65, 0x73, 0x74, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x32, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, - 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x78, 0x2f, 0x74, 0x78, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x6a, - 0x73, 0x6f, 0x6e, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, - 0x74, 0x70, 0x62, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, - 0xaa, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xca, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, - 0x70, 0x62, 0xe2, 0x02, 0x12, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x36, 0x34, 0x12, 0x2b, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x5f, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x08, 0x9a, 0xe7, 0xb0, 0x2a, 0x03, 0x68, + 0x65, 0x78, 0x52, 0x0b, 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x3a, + 0x15, 0x8a, 0xe7, 0xb0, 0x2a, 0x10, 0x41, 0x42, 0x69, 0x74, 0x4f, 0x66, 0x45, 0x76, 0x65, 0x72, + 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x22, 0x7b, 0x0a, 0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x22, 0x47, 0x0a, 0x0d, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x03, 0x62, 0x61, 0x72, 0x3a, 0x12, 0x8a, 0xe7, 0xb0, 0x2a, 0x0d, 0x4e, + 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x29, 0x0a, 0x06, + 0x41, 0x6e, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, + 0x4e, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x07, + 0x0a, 0x03, 0x54, 0x57, 0x4f, 0x10, 0x02, 0x42, 0x83, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, + 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x42, 0x09, 0x54, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x32, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, + 0x6f, 0x2f, 0x78, 0x2f, 0x74, 0x78, 0x2f, 0x61, 0x6d, 0x69, 0x6e, 0x6f, 0x6a, 0x73, 0x6f, 0x6e, + 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, + 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x06, + 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xca, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xe2, + 0x02, 0x12, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/x/tx/signing/aminojson/json_marshal_test.go b/x/tx/signing/aminojson/json_marshal_test.go index 29d2f8cf8f59..b2a4ddd77e42 100644 --- a/x/tx/signing/aminojson/json_marshal_test.go +++ b/x/tx/signing/aminojson/json_marshal_test.go @@ -1,6 +1,7 @@ package aminojson_test import ( + "crypto/sha256" "encoding/json" "errors" "fmt" @@ -414,3 +415,33 @@ func TestAminoNameAsTypeURL(t *testing.T) { } }`, string(bz)) } + +func TestCustomBytesEncoder(t *testing.T) { + cdc := amino.NewCodec() + cdc.RegisterConcrete(&testpb.ABitOfEverything{}, "ABitOfEverything", nil) + encoder := aminojson.NewEncoder(aminojson.EncoderOptions{}) + + bz := sha256.Sum256([]byte("test")) + + msg := &testpb.ABitOfEverything{ + Bytes: bz[:], + PrettyBytes: bz[:], + } + + legacyJSON, err := cdc.MarshalJSON(msg) + require.NoError(t, err) + aminoJSON, err := encoder.Marshal(msg) + require.NoError(t, err) + require.Equal(t, string(legacyJSON), string(aminoJSON)) + + encoder.DefineFieldEncoding( + "hex", + func(enc *aminojson.Encoder, v protoreflect.Value, w io.Writer) error { + _, err := fmt.Fprintf(w, "\"%x\"", v.Bytes()) + return err + }) + aminoJSON, err = encoder.Marshal(msg) + require.NoError(t, err) + require.NotEqual(t, string(legacyJSON), string(aminoJSON)) + t.Logf("hex encoded bytes: %s", string(aminoJSON)) +}