diff --git a/evmrpc/state.go b/evmrpc/state.go index d90544cde1..96f7591210 100644 --- a/evmrpc/state.go +++ b/evmrpc/state.go @@ -136,7 +136,7 @@ func (a *StateAPI) GetProof(ctx context.Context, address common.Address, storage for _, key := range storageKeys { paddedKey := common.BytesToHash([]byte(key)) formattedKey := append(types.StateKey(address), paddedKey[:]...) - qres := queryStore.Query(abci.RequestQuery{ + qres := queryStore.Query(ctx, abci.RequestQuery{ Path: "/key", Data: formattedKey, Height: block.Block.Height, diff --git a/sei-cosmos/baseapp/abci.go b/sei-cosmos/baseapp/abci.go index e26c065bc7..de093612e1 100644 --- a/sei-cosmos/baseapp/abci.go +++ b/sei-cosmos/baseapp/abci.go @@ -23,6 +23,8 @@ import ( "github.com/sei-protocol/sei-chain/sei-cosmos/types/legacytm" abci "github.com/sei-protocol/sei-chain/sei-tendermint/abci/types" tmproto "github.com/sei-protocol/sei-chain/sei-tendermint/proto/tendermint/types" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" "google.golang.org/grpc/codes" grpcstatus "google.golang.org/grpc/status" ) @@ -102,7 +104,12 @@ func (app *BaseApp) Info(ctx context.Context, req *abci.RequestInfo) (*abci.Resp } func (app *BaseApp) MidBlock(ctx sdk.Context, height int64) (events []abci.Event) { - defer telemetry.MeasureSince(time.Now(), "abci", "mid_block") + start := time.Now() + defer func() { + baseappMetrics.midBlockDuration.Record(ctx.Context(), time.Since(start).Seconds()) + // TODO(PLT-353): remove once baseapp_mid_block_duration verified + telemetry.MeasureSince(start, "abci", "mid_block") + }() if app.midBlocker != nil { midBlockEvents := app.midBlocker(ctx, height) @@ -114,7 +121,12 @@ func (app *BaseApp) MidBlock(ctx sdk.Context, height int64) (events []abci.Event // EndBlock implements the ABCI interface. func (app *BaseApp) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) (res abci.ResponseEndBlock) { - defer telemetry.MeasureSince(time.Now(), "abci", "end_block") + start := time.Now() + defer func() { + baseappMetrics.endBlockDuration.Record(ctx.Context(), time.Since(start).Seconds()) + // TODO(PLT-353): remove once baseapp_end_block_duration verified + telemetry.MeasureSince(start, "abci", "end_block") + }() if app.endBlocker != nil { res = app.endBlocker(ctx, req) @@ -166,15 +178,25 @@ func (app *BaseApp) DeliverTxBatch(ctx sdk.Context, req sdk.DeliverTxBatchReques // Regardless of tx execution outcome, the ResponseDeliverTx will contain relevant // gas execution context. func (app *BaseApp) DeliverTx(ctx sdk.Context, req abci.RequestDeliverTxV2, tx sdk.Tx, checksum [32]byte) (res abci.ResponseDeliverTx) { - defer telemetry.MeasureSince(time.Now(), "abci", "deliver_tx") - + deliverTxStart := time.Now() gInfo := sdk.GasInfo{} resultStr := "successful" defer func() { + baseappMetrics.deliverTxDuration.Record(ctx.Context(), time.Since(deliverTxStart).Seconds()) + // TODO(PLT-353): remove once baseapp_deliver_tx_duration verified + telemetry.MeasureSince(deliverTxStart, "abci", "deliver_tx") + baseappMetrics.txCount.Add(ctx.Context(), 1) + // TODO(PLT-353): remove once baseapp_tx_count verified telemetry.IncrCounter(1, "tx", "count") + baseappMetrics.txResult.Add(ctx.Context(), 1, otelmetric.WithAttributes(attribute.String("result", resultStr))) + // TODO(PLT-353): remove once baseapp_tx_result verified telemetry.IncrCounter(1, "tx", resultStr) + baseappMetrics.txGasUsed.Record(ctx.Context(), int64(gInfo.GasUsed)) //nolint:gosec + // TODO(PLT-353): remove once baseapp_tx_gas_used verified telemetry.SetGauge(float32(gInfo.GasUsed), "tx", "gas", "used") + baseappMetrics.txGasWanted.Record(ctx.Context(), int64(gInfo.GasWanted)) //nolint:gosec + // TODO(PLT-353): remove once baseapp_tx_gas_wanted verified telemetry.SetGauge(float32(gInfo.GasWanted), "tx", "gas", "wanted") }() @@ -245,8 +267,12 @@ func (app *BaseApp) SetDeliverStateToCommit() { // against that height and gracefully halt if it matches the latest committed // height. func (app *BaseApp) Commit(ctx context.Context) (res *abci.ResponseCommit, err error) { - defer telemetry.MeasureSince(time.Now(), "abci", "commit") commitStart := time.Now() + defer func() { + baseappMetrics.commitDuration.Record(ctx, time.Since(commitStart).Seconds()) + // TODO(PLT-353): remove once baseapp_commit_duration verified + telemetry.MeasureSince(commitStart, "abci", "commit") + }() app.commitLock.Lock() defer app.commitLock.Unlock() @@ -388,7 +414,13 @@ func (app *BaseApp) Snapshot(height int64) { // Query implements the ABCI interface. It delegates to CommitMultiStore if it // implements Queryable. func (app *BaseApp) Query(ctx context.Context, req *abci.RequestQuery) (res *abci.ResponseQuery, err error) { - defer telemetry.MeasureSinceWithLabels([]string{"abci", "query"}, time.Now(), []metrics.Label{{Name: "path", Value: req.Path}}) + queryStart := time.Now() + defer func() { + route := app.abciQueryMetricRoute(req.Path) + baseappMetrics.abciQueryDuration.Record(ctx, time.Since(queryStart).Seconds(), otelmetric.WithAttributes(attribute.String(abciQueryMetricRouteLabel, route))) + // TODO(PLT-353): remove once baseapp_abci_query_duration verified + telemetry.MeasureSinceWithLabels([]string{"abci", "query"}, queryStart, []metrics.Label{{Name: "path", Value: req.Path}}) + }() // Add panic recovery for all queries. // ref: https://github.com/cosmos/cosmos-sdk/pull/8039 @@ -425,7 +457,7 @@ func (app *BaseApp) Query(ctx context.Context, req *abci.RequestQuery) (res *abc resp = handleQueryApp(app, path, *req) case "store": - resp = handleQueryStore(app, path, *req) + resp = handleQueryStore(ctx, app, path, *req) case "custom": resp = handleQueryCustom(app, path, *req) @@ -846,7 +878,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res ), app.trace) } -func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { +func handleQueryStore(ctx context.Context, app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { var ( queryable sdk.Queryable ok bool @@ -875,7 +907,7 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.R ), app.trace) } - resp := queryable.Query(req) + resp := queryable.Query(ctx, req) resp.Height = req.Height return resp @@ -934,7 +966,12 @@ func splitPath(requestPath string) (path []string) { // ABCI++ func (app *BaseApp) ProcessProposal(ctx context.Context, req *abci.RequestProcessProposal) (resp *abci.ResponseProcessProposal, err error) { - defer telemetry.MeasureSince(time.Now(), "abci", "process_proposal") + processProposalStart := time.Now() + defer func() { + baseappMetrics.processProposalDuration.Record(ctx, time.Since(processProposalStart).Seconds()) + // TODO(PLT-353): remove once baseapp_process_proposal_duration verified + telemetry.MeasureSince(processProposalStart, "abci", "process_proposal") + }() ppStart := time.Now() defer func() { app.execProcessProposalMs = time.Since(ppStart).Milliseconds() }() if app.ChainID != req.Header.ChainID { @@ -997,7 +1034,12 @@ func (app *BaseApp) ProcessProposal(ctx context.Context, req *abci.RequestProces } func (app *BaseApp) FinalizeBlock(ctx context.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) { - defer telemetry.MeasureSince(time.Now(), "abci", "finalize_block") + finalizeBlockStart := time.Now() + defer func() { + baseappMetrics.finalizeBlockDuration.Record(ctx, time.Since(finalizeBlockStart).Seconds()) + // TODO(PLT-353): remove once baseapp_finalize_block_duration verified + telemetry.MeasureSince(finalizeBlockStart, "abci", "finalize_block") + }() fbStart := time.Now() app.execBlockTxCount = len(req.Txs) defer func() { app.execFinalizeBlockMs = time.Since(fbStart).Milliseconds() }() @@ -1040,7 +1082,7 @@ func (app *BaseApp) FinalizeBlock(ctx context.Context, req *abci.RequestFinalize } } -func (app *BaseApp) GetTxPriorityHint(_ context.Context, req *abci.RequestGetTxPriorityHintV2) (_resp *abci.ResponseGetTxPriorityHint, _err error) { +func (app *BaseApp) GetTxPriorityHint(ctx context.Context, req *abci.RequestGetTxPriorityHintV2) (_resp *abci.ResponseGetTxPriorityHint, _err error) { defer func() { if r := recover(); r != nil { // Fall back to no-op priority if we panic for any reason. This is to avoid DoS @@ -1056,7 +1098,12 @@ func (app *BaseApp) GetTxPriorityHint(_ context.Context, req *abci.RequestGetTxP } }() - defer telemetry.MeasureSince(time.Now(), "abci", "get_tx_priority_hint") + priorityHintStart := time.Now() + defer func() { + baseappMetrics.getTxPriorityHintDuration.Record(ctx, time.Since(priorityHintStart).Seconds()) + // TODO(PLT-353): remove once baseapp_get_tx_priority_hint_duration verified + telemetry.MeasureSince(priorityHintStart, "abci", "get_tx_priority_hint") + }() tx, err := app.txDecoder(req.Tx) if err != nil { diff --git a/sei-cosmos/baseapp/abci_query_metrics.go b/sei-cosmos/baseapp/abci_query_metrics.go new file mode 100644 index 0000000000..a17f403f82 --- /dev/null +++ b/sei-cosmos/baseapp/abci_query_metrics.go @@ -0,0 +1,85 @@ +package baseapp + +import storetypes "github.com/sei-protocol/sei-chain/sei-cosmos/store/types" + +// storeByNameLookup is implemented by CommitMultiStore backends (rootmulti, storev2). +type storeByNameLookup interface { + GetStoreByName(name string) storetypes.Store +} + +// abciStoreQuerySubpaths are the only subpath segments used by mounted store +// Query implementations (/key, /subspace). See store/rootmulti and storev2/commitment. +var abciStoreQuerySubpaths = map[string]struct{}{ + "key": {}, + "subspace": {}, +} + +// abciQueryMetricRoute returns a bounded label for ABCI query metrics. +// Raw client paths are not used directly to avoid unbounded metric cardinality. +// +// Rules: +// - Registered gRPC query paths are returned as-is (finite set at startup). +// - Legacy paths use a fixed prefix + registered segment shape. +// - Everything else is "other". +func (app *BaseApp) abciQueryMetricRoute(reqPath string) string { + if app.grpcQueryRouter != nil && app.grpcQueryRouter.Route(reqPath) != nil { + return reqPath + } + + parts := splitPath(reqPath) + if len(parts) == 0 { + return "other" + } + + switch parts[0] { + case "app": + if len(parts) >= 2 { + switch parts[1] { + case "simulate", "version", "snapshots": + return "app/" + parts[1] + } + } + return "app/unknown" + + case "store": + return app.abciStoreQueryMetricRoute(parts) + + case "custom": + if len(parts) >= 2 && parts[1] != "" && app.queryRouter != nil && app.queryRouter.Route(parts[1]) != nil { + return "custom/" + parts[1] + } + return "custom/unknown" + + default: + return "other" + } +} + +func (app *BaseApp) abciStoreQueryMetricRoute(parts []string) string { + if len(parts) < 3 { + return "store/unknown" + } + storeName, subpath := parts[1], parts[2] + if _, ok := abciStoreQuerySubpaths[subpath]; !ok { + return "store/unknown" + } + if !app.storeRegisteredForQuery(storeName) { + return "store/unknown" + } + return "store/" + storeName + "/" + subpath +} + +func (app *BaseApp) storeRegisteredForQuery(name string) bool { + if lookup, ok := app.cms.(storeByNameLookup); ok && lookup.GetStoreByName(name) != nil { + return true + } + if app.qms != nil { + if lookup, ok := app.qms.(storeByNameLookup); ok && lookup.GetStoreByName(name) != nil { + return true + } + } + return false +} + +// abciQueryMetricRouteLabel is kept as "path" for compatibility with existing dashboards. +const abciQueryMetricRouteLabel = "path" diff --git a/sei-cosmos/baseapp/abci_query_metrics_test.go b/sei-cosmos/baseapp/abci_query_metrics_test.go new file mode 100644 index 0000000000..c402bb6fcb --- /dev/null +++ b/sei-cosmos/baseapp/abci_query_metrics_test.go @@ -0,0 +1,74 @@ +package baseapp + +import ( + "testing" + + abci "github.com/sei-protocol/sei-chain/sei-tendermint/abci/types" + "github.com/sei-protocol/sei-chain/sei-cosmos/testutil" + "github.com/sei-protocol/sei-chain/sei-cosmos/testutil/testdata" + sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" + "github.com/stretchr/testify/require" + dbm "github.com/tendermint/tm-db" +) + +func TestAbciQueryMetricRoute(t *testing.T) { + db := dbm.NewMemDB() + app := NewBaseApp(t.Name(), db, nil, nil, &testutil.TestAppOpts{}) + + grpcQR := app.GRPCQueryRouter() + grpcQR.SetInterfaceRegistry(testdata.NewTestInterfaceRegistry()) + testdata.RegisterQueryServer(grpcQR, testdata.QueryImpl{}) + + app.QueryRouter().AddRoute("bank", func(_ sdk.Context, _ []string, _ abci.RequestQuery) ([]byte, error) { + return nil, nil + }) + + grpcEcho := "/testdata.Query/Echo" + + tests := map[string]struct { + reqPath string + expected string + }{ + // Production gRPC paths (3-month sample); registered via testdata.Query. + "grpc registered": { + reqPath: grpcEcho, + expected: grpcEcho, + }, + "grpc unregistered": { + reqPath: "/cosmos.bank.v1beta1.Query/TotalSupply", + expected: "other", + }, + + // Legacy app paths. + "app snapshots": {reqPath: "app/snapshots", expected: "app/snapshots"}, + "app version": {reqPath: "app/version", expected: "app/version"}, + "app unknown": {reqPath: "app/unknown-action", expected: "app/unknown"}, + + // Legacy store paths (unknown store name or subpath → single bucket). + "store ibc key unregistered": {reqPath: "store/ibc/key", expected: "store/unknown"}, + "store random attack": {reqPath: "store/random1/random2", expected: "store/unknown"}, + "store bad subpath": {reqPath: "store/key1/evil", expected: "store/unknown"}, + "store short": {reqPath: "store/bank", expected: "store/unknown"}, + + // Legacy custom paths; subpath segments are not part of the metric label. + "custom bank": {reqPath: "custom/bank/all_balances", expected: "custom/bank"}, + "custom unregistered": {reqPath: "custom/unknown/foo", expected: "custom/unknown"}, + + // Garbage / attack paths. + "empty": {reqPath: "", expected: "other"}, + "random": {reqPath: "/totally/made/up", expected: "other"}, + "leading slash app": {reqPath: "/app/snapshots", expected: "app/snapshots"}, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + require.Equal(t, tc.expected, app.abciQueryMetricRoute(tc.reqPath)) + }) + } +} + +func TestAbciQueryMetricRoute_RegisteredStore(t *testing.T) { + app := setupBaseApp(t) + require.Equal(t, "store/key1/key", app.abciQueryMetricRoute("store/key1/key")) + require.Equal(t, "store/unknown", app.abciQueryMetricRoute("store/random1/key")) +} diff --git a/sei-cosmos/baseapp/abci_test.go b/sei-cosmos/baseapp/abci_test.go index e76eaa2cb2..99b2622962 100644 --- a/sei-cosmos/baseapp/abci_test.go +++ b/sei-cosmos/baseapp/abci_test.go @@ -216,7 +216,7 @@ func TestHandleQueryStore_NonQueryableMultistore(t *testing.T) { Height: 1, } - resp := handleQueryStore(app, path, req) + resp := handleQueryStore(context.Background(), app, path, req) require.True(t, resp.IsErr()) require.Contains(t, resp.Log, "multistore doesn't support queries") } diff --git a/sei-cosmos/baseapp/baseapp.go b/sei-cosmos/baseapp/baseapp.go index 4c53d7ed7b..8b73b4553a 100644 --- a/sei-cosmos/baseapp/baseapp.go +++ b/sei-cosmos/baseapp/baseapp.go @@ -32,6 +32,7 @@ import ( dbm "github.com/tendermint/tm-db" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/noop" ) @@ -843,13 +844,18 @@ type runTxResult struct { // returned if the tx does not run out of gas and if all the messages are valid // and execute successfully. An error is returned otherwise. func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, tx sdk.Tx, checksum [32]byte) (runTxRes runTxResult, err error) { - defer telemetry.MeasureThroughputSinceWithLabels( - telemetry.TxCount, - []metrics.Label{ - telemetry.NewLabel("mode", modeKeyToString[mode]), - }, - time.Now(), - ) + runTxStart := time.Now() + defer func() { + baseappMetrics.runTxDuration.Record(ctx.Context(), time.Since(runTxStart).Seconds(), otelmetric.WithAttributes(attribute.String("mode", modeKeyToString[mode]))) + // TODO(PLT-353): remove once baseapp_run_tx_duration verified + telemetry.MeasureThroughputSinceWithLabels( + telemetry.TxCount, + []metrics.Label{ + telemetry.NewLabel("mode", modeKeyToString[mode]), + }, + runTxStart, + ) + }() // check for existing parent tracer, and if applicable, use it spanCtx, span := app.TracingInfo.StartWithContext("RunTx", ctx.TraceSpanContext()) @@ -996,14 +1002,18 @@ func (app *BaseApp) runTx(ctx sdk.Context, mode runTxMode, tx sdk.Tx, checksum [ // Handler does not exist for a given message route. Otherwise, a reference to a // Result is returned. The caller must not commit state if an error is returned. func (app *BaseApp) RunMsgs(ctx sdk.Context, msgs []sdk.Msg) (*sdk.Result, error) { - - defer telemetry.MeasureThroughputSinceWithLabels( - telemetry.MessageCount, - []metrics.Label{ - telemetry.NewLabel("mode", "deliver"), - }, - time.Now(), - ) + runMsgsStart := time.Now() + defer func() { + baseappMetrics.runMsgsDuration.Record(ctx.Context(), time.Since(runMsgsStart).Seconds()) + // TODO(PLT-353): remove once baseapp_run_msgs_duration verified + telemetry.MeasureThroughputSinceWithLabels( + telemetry.MessageCount, + []metrics.Label{ + telemetry.NewLabel("mode", "deliver"), + }, + runMsgsStart, + ) + }() defer func() { if err := recover(); err != nil { @@ -1037,6 +1047,8 @@ func (app *BaseApp) RunMsgs(ctx sdk.Context, msgs []sdk.Msg) (*sdk.Result, error // ADR 031 request type routing msgResult, err = handler(msgCtx, msg) eventMsgName = sdk.MsgTypeURL(msg) + baseappMetrics.runMsgLatency.Record(ctx.Context(), time.Since(startTime).Seconds(), otelmetric.WithAttributes(attribute.String("type", eventMsgName))) + // TODO(PLT-353): remove once baseapp_run_msg_latency verified metrics.MeasureSinceWithLabels( []string{"sei", "cosmos", "run", "msg", "latency"}, startTime, @@ -1055,6 +1067,8 @@ func (app *BaseApp) RunMsgs(ctx sdk.Context, msgs []sdk.Msg) (*sdk.Result, error return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s; message index: %d", msgRoute, i) } msgResult, err = handler(msgCtx, msg) + baseappMetrics.runMsgLatency.Record(ctx.Context(), time.Since(startTime).Seconds(), otelmetric.WithAttributes(attribute.String("type", eventMsgName))) + // TODO(PLT-353): remove once baseapp_run_msg_latency verified metrics.MeasureSinceWithLabels( []string{"cosmos", "run", "msg", "latency"}, startTime, diff --git a/sei-cosmos/baseapp/metrics.go b/sei-cosmos/baseapp/metrics.go new file mode 100644 index 0000000000..ac133871be --- /dev/null +++ b/sei-cosmos/baseapp/metrics.go @@ -0,0 +1,127 @@ +package baseapp + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_baseapp") + + // finerGrainedBuckets units are in seconds + finerGrainedBuckets = metric.WithExplicitBucketBoundaries( + 0.000025, 0.000050, 0.0001, 0.0005, 0.001, 0.0025, 0.005, 0.010, 0.020, 0.050, 0.075, 0.1, 0.25, 0.5, 1, 10, + ) + + baseappMetrics = struct { + midBlockDuration metric.Float64Histogram + endBlockDuration metric.Float64Histogram + deliverTxDuration metric.Float64Histogram + txCount metric.Int64Counter + txResult metric.Int64Counter + txGasUsed metric.Int64Gauge + txGasWanted metric.Int64Gauge + commitDuration metric.Float64Histogram + abciQueryDuration metric.Float64Histogram + processProposalDuration metric.Float64Histogram + finalizeBlockDuration metric.Float64Histogram + getTxPriorityHintDuration metric.Float64Histogram + runTxDuration metric.Float64Histogram + runMsgsDuration metric.Float64Histogram + runMsgLatency metric.Float64Histogram + }{ + midBlockDuration: must(meter.Float64Histogram( + "mid_block_duration", + metric.WithDescription("Duration of mid-block execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + endBlockDuration: must(meter.Float64Histogram( + "end_block_duration", + metric.WithDescription("Duration of end-block execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + deliverTxDuration: must(meter.Float64Histogram( + "deliver_tx_duration", + metric.WithDescription("Duration of DeliverTx execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + txCount: must(meter.Int64Counter( + "tx", + metric.WithDescription("Total number of transactions delivered"), + metric.WithUnit("{count}"), + )), + txResult: must(meter.Int64Counter( + "tx_result", + metric.WithDescription("Number of delivered transactions by result"), + metric.WithUnit("{count}"), + )), + txGasUsed: must(meter.Int64Gauge( + "tx_gas_used", + metric.WithDescription("Gas used by the last delivered transaction"), + metric.WithUnit("{gas}"), + )), + txGasWanted: must(meter.Int64Gauge( + "tx_gas_wanted", + metric.WithDescription("Gas wanted by the last delivered transaction"), + metric.WithUnit("{gas}"), + )), + commitDuration: must(meter.Float64Histogram( + "commit_duration", + metric.WithDescription("Duration of ABCI Commit in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + abciQueryDuration: must(meter.Float64Histogram( + "abci_query_duration", + metric.WithDescription("Duration of ABCI Query by bounded route label in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + processProposalDuration: must(meter.Float64Histogram( + "process_proposal_duration", + metric.WithDescription("Duration of ProcessProposal execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + finalizeBlockDuration: must(meter.Float64Histogram( + "finalize_block_duration", + metric.WithDescription("Duration of FinalizeBlock execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + getTxPriorityHintDuration: must(meter.Float64Histogram( + "get_tx_priority_hint_duration", + metric.WithDescription("Duration of GetTxPriorityHint execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + runTxDuration: must(meter.Float64Histogram( + "run_tx_duration", + metric.WithDescription("Duration of runTx by mode in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + runMsgsDuration: must(meter.Float64Histogram( + "run_msgs_duration", + metric.WithDescription("Duration of RunMsgs execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + runMsgLatency: must(meter.Float64Histogram( + "run_msg_latency", + metric.WithDescription("Latency of individual message handler execution by message type in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-cosmos/store/rootmulti/dbadapter.go b/sei-cosmos/store/rootmulti/dbadapter.go index f599e2c5d6..6e97635e79 100644 --- a/sei-cosmos/store/rootmulti/dbadapter.go +++ b/sei-cosmos/store/rootmulti/dbadapter.go @@ -1,6 +1,7 @@ package rootmulti import ( + "context" "fmt" abci "github.com/sei-protocol/sei-chain/sei-tendermint/abci/types" @@ -40,7 +41,7 @@ func (cdsa commitDBStoreAdapter) SetPruning(_ types.PruningOptions) {} // They must be set on the root commit multi-store. func (cdsa commitDBStoreAdapter) GetPruning() types.PruningOptions { return types.PruningOptions{} } -func (cdsa commitDBStoreAdapter) Query(req abci.RequestQuery) abci.ResponseQuery { +func (cdsa commitDBStoreAdapter) Query(_ context.Context, req abci.RequestQuery) abci.ResponseQuery { if len(req.Data) == 0 { return abci.ResponseQuery{ Code: 1, diff --git a/sei-cosmos/store/rootmulti/store.go b/sei-cosmos/store/rootmulti/store.go index d9c0a60e7b..3969c49ee9 100644 --- a/sei-cosmos/store/rootmulti/store.go +++ b/sei-cosmos/store/rootmulti/store.go @@ -1,6 +1,7 @@ package rootmulti import ( + "context" "encoding/binary" "fmt" "io" @@ -570,7 +571,7 @@ func (rs *Store) GetStoreByName(name string) types.Store { // Special case: if `req.Path` is `/proofs`, the commit hash is included // as response value. In addition, proofs of every store are appended to the response for // the requested height -func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { +func (rs *Store) Query(ctx context.Context, req abci.RequestQuery) abci.ResponseQuery { path := req.Path firstPath, subpath, err := parsePath(path) if err != nil { @@ -593,7 +594,7 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { // trim the path and make the query req.Path = subpath - res := queryable.Query(req) + res := queryable.Query(ctx, req) if !req.Prove || !RequireProof(subpath) { return res diff --git a/sei-cosmos/store/types/cache.go b/sei-cosmos/store/types/cache.go index aaba4c877e..7c753f84c1 100644 --- a/sei-cosmos/store/types/cache.go +++ b/sei-cosmos/store/types/cache.go @@ -1,10 +1,13 @@ package types import ( + "context" "sync" "github.com/armon/go-metrics" "github.com/sei-protocol/sei-chain/sei-cosmos/telemetry" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" ) const DefaultCacheSizeLimit = 4000000 // TODO: revert back to 1000000 after paritioning r/w caches @@ -65,6 +68,8 @@ func NewBoundedCache(backend CacheBackend, limit int) *BoundedCache { } func (c *BoundedCache) emitKeysEvictedMetrics(keysToEvict int) { + storeMetrics.boundedCache.Record(context.Background(), int64(keysToEvict), otelmetric.WithAttributes(attribute.String("type", "keys_evicted"))) + // TODO(PLT-353): remove once store_bounded_cache verified telemetry.SetGaugeWithLabels( c.metricName, float32(keysToEvict), diff --git a/sei-cosmos/store/types/gas.go b/sei-cosmos/store/types/gas.go index 27f82d53a1..83c094922d 100644 --- a/sei-cosmos/store/types/gas.go +++ b/sei-cosmos/store/types/gas.go @@ -1,12 +1,15 @@ package types import ( + "context" "fmt" "math" "sync" "github.com/armon/go-metrics" "github.com/sei-protocol/sei-chain/sei-cosmos/telemetry" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" ) // Gas consumption descriptors. @@ -113,6 +116,11 @@ func (g *basicGasMeter) ConsumeGas(amount Gas, descriptor string) { // cosmos_tx_gas_exceeded func (g *basicGasMeter) incrGasExceededCounter(errorType string, descriptor string) { + storeMetrics.gasExceeded.Add(context.Background(), 1, otelmetric.WithAttributes( + attribute.String("error", errorType), + attribute.String("descriptor", descriptor), + )) + // TODO(PLT-353): remove once store_gas_exceeded verified telemetry.IncrCounterWithLabels( []string{"gas", "exceeded"}, 1, diff --git a/sei-cosmos/store/types/metrics.go b/sei-cosmos/store/types/metrics.go new file mode 100644 index 0000000000..94ffe6e2d0 --- /dev/null +++ b/sei-cosmos/store/types/metrics.go @@ -0,0 +1,33 @@ +package types + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_store_types") + + storeMetrics = struct { + gasExceeded metric.Int64Counter + boundedCache metric.Int64Gauge + }{ + gasExceeded: must(meter.Int64Counter( + "gas_exceeded", + metric.WithDescription("Number of gas exceeded errors by error type and descriptor"), + metric.WithUnit("{count}"), + )), + boundedCache: must(meter.Int64Gauge( + "bounded_cache", + metric.WithDescription("Number of keys evicted in the last bounded cache eviction by type"), + metric.WithUnit("{count}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-cosmos/store/types/store.go b/sei-cosmos/store/types/store.go index 1933e1681b..974be43bb3 100644 --- a/sei-cosmos/store/types/store.go +++ b/sei-cosmos/store/types/store.go @@ -1,6 +1,7 @@ package types import ( + "context" "fmt" "io" @@ -37,7 +38,7 @@ type CommitStore interface { // // This is an optional, but useful extension to any CommitStore type Queryable interface { - Query(abci.RequestQuery) abci.ResponseQuery + Query(context.Context, abci.RequestQuery) abci.ResponseQuery } //---------------------------------------- diff --git a/sei-cosmos/storev2/commitment/store.go b/sei-cosmos/storev2/commitment/store.go index a6c9822626..c60f68e9df 100644 --- a/sei-cosmos/storev2/commitment/store.go +++ b/sei-cosmos/storev2/commitment/store.go @@ -2,6 +2,7 @@ package commitment import ( "bytes" + "context" "fmt" "io" @@ -126,7 +127,7 @@ func (st *Store) PopChangeSet() seidbproto.ChangeSet { return cs } -func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { +func (st *Store) Query(_ context.Context, req abci.RequestQuery) (res abci.ResponseQuery) { if req.Height > 0 && req.Height != st.tree.Version() { return sdkerrors.QueryResult(errors.Wrap(sdkerrors.ErrInvalidHeight, "invalid height")) } diff --git a/sei-cosmos/storev2/rootmulti/flatkv_modes_test.go b/sei-cosmos/storev2/rootmulti/flatkv_modes_test.go index 8a4699649b..36b57887f1 100644 --- a/sei-cosmos/storev2/rootmulti/flatkv_modes_test.go +++ b/sei-cosmos/storev2/rootmulti/flatkv_modes_test.go @@ -3,6 +3,7 @@ package rootmulti // WriteMode / Query path coverage: Shadow, SS, proof, missing-key, async restart. import ( + "context" "fmt" "testing" @@ -114,7 +115,7 @@ func TestFlatKVQueryWithSSAndReadMode(t *testing.T) { waitUntilSSVersion(t, store, c2.version) - resp := store.Query(abci.RequestQuery{ + resp := store.Query(context.Background(), abci.RequestQuery{ Path: "/acc/key", Data: []byte("acct1"), Height: c1.version, @@ -123,7 +124,7 @@ func TestFlatKVQueryWithSSAndReadMode(t *testing.T) { require.EqualValues(t, 0, resp.Code, "cosmos query failed: %s", resp.Log) require.Equal(t, []byte{1}, resp.Value) - resp = store.Query(abci.RequestQuery{ + resp = store.Query(context.Background(), abci.RequestQuery{ Path: "/evm/key", Data: evmData.storKey, Height: c1.version, @@ -132,7 +133,7 @@ func TestFlatKVQueryWithSSAndReadMode(t *testing.T) { require.EqualValues(t, 0, resp.Code, "evm query failed: %s", resp.Log) require.Equal(t, makeSlot(0x01, 0xAA), resp.Value) - resp = store.Query(abci.RequestQuery{ + resp = store.Query(context.Background(), abci.RequestQuery{ Path: "/evm/key", Data: evmData.storKey, Height: c2.version, @@ -142,7 +143,7 @@ func TestFlatKVQueryWithSSAndReadMode(t *testing.T) { require.Equal(t, makeSlot(0x02, 0xBB), resp.Value) // Proof path (SC). - resp = store.Query(abci.RequestQuery{ + resp = store.Query(context.Background(), abci.RequestQuery{ Path: "/evm/key", Data: evmData.storKey, Height: c1.version, @@ -206,7 +207,7 @@ func TestFlatKVQueryNonExistentKey(t *testing.T) { waitUntilSSVersion(t, store, c1.version) // Missing acc key — cosmos module path, no proof. - resp := store.Query(abci.RequestQuery{ + resp := store.Query(context.Background(), abci.RequestQuery{ Path: "/acc/key", Data: []byte("missing-acct"), Height: c1.version, @@ -218,7 +219,7 @@ func TestFlatKVQueryNonExistentKey(t *testing.T) { // Missing evm key — SS path, no proof. Uses an evm storage-kind key that // was never written. missingEVM := newEVMTestData(0xAA) - resp = store.Query(abci.RequestQuery{ + resp = store.Query(context.Background(), abci.RequestQuery{ Path: "/evm/key", Data: missingEVM.storKey, Height: c1.version, @@ -229,7 +230,7 @@ func TestFlatKVQueryNonExistentKey(t *testing.T) { // Missing evm key — SC path, proof requested. ics23 should produce an // absence proof; Code=0 with nil Value is the expected shape. - resp = store.Query(abci.RequestQuery{ + resp = store.Query(context.Background(), abci.RequestQuery{ Path: "/evm/key", Data: missingEVM.storKey, Height: c1.version, @@ -356,7 +357,7 @@ func TestFlatKVSSAsyncRestartConsistency(t *testing.T) { for v := int64(1); v <= latestVersion; v++ { rec := history[v] if rec.hasCosmo { - resp := store2.Query(abci.RequestQuery{ + resp := store2.Query(context.Background(), abci.RequestQuery{ Path: "/acc/key", Data: []byte("acct1"), Height: v, @@ -367,7 +368,7 @@ func TestFlatKVSSAsyncRestartConsistency(t *testing.T) { "SS cosmos value at v%d should match committed value", v) } if rec.hasEVM { - resp := store2.Query(abci.RequestQuery{ + resp := store2.Query(context.Background(), abci.RequestQuery{ Path: "/evm/key", Data: evmData.storKey, Height: v, diff --git a/sei-cosmos/storev2/rootmulti/metrics.go b/sei-cosmos/storev2/rootmulti/metrics.go new file mode 100644 index 0000000000..68d429351c --- /dev/null +++ b/sei-cosmos/storev2/rootmulti/metrics.go @@ -0,0 +1,69 @@ +package rootmulti + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_storev2_rootmulti") + + // finerGrainedBuckets units are in seconds + finerGrainedBuckets = metric.WithExplicitBucketBoundaries( + 0.000025, 0.000050, 0.0001, 0.0005, 0.001, 0.0025, 0.005, 0.010, 0.020, 0.050, 0.075, 0.1, 0.25, 0.5, 1, 10, + ) + + storev2Metrics = struct { + scCommitLatency metric.Float64Histogram + ssVersion metric.Int64Gauge + historicalAbciQuery metric.Int64Counter + iavlTotalKeyBytes metric.Int64Gauge + iavlTotalValueBytes metric.Int64Gauge + iavlTotalNumKeys metric.Int64Gauge + stateSyncKeysExported metric.Int64Counter + }{ + scCommitLatency: must(meter.Float64Histogram( + "sc_commit_latency", + metric.WithDescription("Duration of SC store commit in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + ssVersion: must(meter.Int64Gauge( + "ss_version", + metric.WithDescription("Current SS store version"), + metric.WithUnit("{version}"), + )), + historicalAbciQuery: must(meter.Int64Counter( + "historical_abci_query", + metric.WithDescription("Number of historical ABCI queries by success and proof status"), + metric.WithUnit("{count}"), + )), + iavlTotalKeyBytes: must(meter.Int64Gauge( + "iavl_total_key_bytes", + metric.WithDescription("Total key bytes per store in IAVL snapshot"), + metric.WithUnit("By"), + )), + iavlTotalValueBytes: must(meter.Int64Gauge( + "iavl_total_value_bytes", + metric.WithDescription("Total value bytes per store in IAVL snapshot"), + metric.WithUnit("By"), + )), + iavlTotalNumKeys: must(meter.Int64Gauge( + "iavl_total_num_keys", + metric.WithDescription("Total number of keys per store in IAVL snapshot"), + metric.WithUnit("{count}"), + )), + stateSyncKeysExported: must(meter.Int64Counter( + "state_sync_keys_exported", + metric.WithDescription("Number of keys exported during state sync"), + metric.WithUnit("{count}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-cosmos/storev2/rootmulti/store.go b/sei-cosmos/storev2/rootmulti/store.go index d3442c2549..86dc62c529 100644 --- a/sei-cosmos/storev2/rootmulti/store.go +++ b/sei-cosmos/storev2/rootmulti/store.go @@ -14,6 +14,8 @@ import ( "cosmossdk.io/errors" "github.com/armon/go-metrics" "github.com/sei-protocol/seilog" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" "golang.org/x/time/rate" protoio "github.com/gogo/protobuf/io" @@ -132,7 +134,11 @@ func (rs *Store) Commit(bumpVersion bool) types.CommitID { panic("Commit should always bump version in root multistore") } commitStartTime := time.Now() - defer telemetry.MeasureSince(commitStartTime, "storeV2", "sc", "commit", "latency") + defer func() { + storev2Metrics.scCommitLatency.Record(context.Background(), time.Since(commitStartTime).Seconds()) + // TODO(PLT-353): remove once storev2_sc_commit_latency verified + telemetry.MeasureSince(commitStartTime, "storeV2", "sc", "commit", "latency") + }() if err := rs.flush(); err != nil { panic(err) } @@ -191,6 +197,8 @@ func (rs *Store) flush() error { if err := rs.ssStore.ApplyChangesetAsync(currentVersion, changeSets); err != nil { return err } + storev2Metrics.ssVersion.Record(context.Background(), currentVersion) + // TODO(PLT-353): remove once storev2_ss_version verified telemetry.SetGauge(float32(currentVersion), "storeV2", "ss", "version") } } else { @@ -199,6 +207,8 @@ func (rs *Store) flush() error { if err := rs.ssStore.SetLatestVersion(currentVersion); err != nil { panic(err) } + storev2Metrics.ssVersion.Record(context.Background(), currentVersion) + // TODO(PLT-353): remove once storev2_ss_version verified telemetry.SetGauge(float32(currentVersion), "storeV2", "ss", "version") } } @@ -613,7 +623,7 @@ func (rs *Store) GetStoreByName(name string) types.Store { } // Implements interface Queryable -func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { +func (rs *Store) Query(ctx context.Context, req abci.RequestQuery) abci.ResponseQuery { version := req.Height if version <= 0 || version > rs.lastCommitInfo.Version { version = rs.scStore.Version() @@ -632,7 +642,7 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { // Fast path: no proof + SS enabled if !needProof && rs.ssStore != nil { store := types.Queryable(state.NewStore(rs.ssStore, types.NewKVStoreKey(storeName), version)) - return store.Query(req) + return store.Query(ctx, req) } var ( @@ -648,6 +658,11 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { // historical path (this is where RPC pressure happens) if err := rs.tryAcquireHistProofPermit(); err != nil { logger.Debug("Failed to acquire historical proof permit", "err", err) + storev2Metrics.historicalAbciQuery.Add(ctx, 1, otelmetric.WithAttributes( + attribute.String("success", "false"), + attribute.String("proof", strconv.FormatBool(needProof)), + )) + // TODO(PLT-353): remove once storev2_historical_abci_query verified telemetry.IncrCounterWithLabels([]string{"historical", "abci", "query"}, 1, []metrics.Label{ @@ -656,6 +671,11 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { }) return sdkerrors.QueryResult(err) } else { + storev2Metrics.historicalAbciQuery.Add(ctx, 1, otelmetric.WithAttributes( + attribute.String("success", "true"), + attribute.String("proof", strconv.FormatBool(needProof)), + )) + // TODO(PLT-353): remove once storev2_historical_abci_query verified telemetry.IncrCounterWithLabels([]string{"historical", "abci", "query"}, 1, []metrics.Label{ @@ -676,7 +696,7 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { commitInfo = amendCommitInfo(commitInfo, rs.storesParams) } - res := store.Query(req) + res := store.Query(ctx, req) // If underlying query failed (e.g. invalid height/path) or doesn' need proof, return as-is. if res.Code != 0 || !needProof { @@ -949,6 +969,8 @@ func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error { if err != nil { if err == commonerrors.ErrorExportDone { for k, v := range keySizePerStore { + storev2Metrics.iavlTotalKeyBytes.Record(context.Background(), v, otelmetric.WithAttributes(attribute.String("store_name", k))) + // TODO(PLT-353): remove once storev2_iavl_total_key_bytes verified telemetry.SetGaugeWithLabels( []string{"iavl", "store", "total_key_bytes"}, float32(v), @@ -956,6 +978,8 @@ func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error { ) } for k, v := range valueSizePerStore { + storev2Metrics.iavlTotalValueBytes.Record(context.Background(), v, otelmetric.WithAttributes(attribute.String("store_name", k))) + // TODO(PLT-353): remove once storev2_iavl_total_value_bytes verified telemetry.SetGaugeWithLabels( []string{"iavl", "store", "total_value_bytes"}, float32(v), @@ -963,6 +987,8 @@ func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error { ) } for k, v := range numKeysPerStore { + storev2Metrics.iavlTotalNumKeys.Record(context.Background(), v, otelmetric.WithAttributes(attribute.String("store_name", k))) + // TODO(PLT-353): remove once storev2_iavl_total_num_keys verified telemetry.SetGaugeWithLabels( []string{"iavl", "store", "total_num_keys"}, float32(v), @@ -990,6 +1016,8 @@ func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error { keySizePerStore[currentStoreName] += int64(len(item.Key)) valueSizePerStore[currentStoreName] += int64(len(item.Value)) numKeysPerStore[currentStoreName] += 1 + storev2Metrics.stateSyncKeysExported.Add(context.Background(), 1) + // TODO(PLT-353): remove once storev2_state_sync_keys_exported verified telemetry.IncrCounter(1, "state_sync", "num_keys_exported") case string: if err := protoWriter.WriteMsg(&snapshottypes.SnapshotItem{ diff --git a/sei-cosmos/storev2/rootmulti/store_test.go b/sei-cosmos/storev2/rootmulti/store_test.go index d8b80b7e27..5558bec852 100644 --- a/sei-cosmos/storev2/rootmulti/store_test.go +++ b/sei-cosmos/storev2/rootmulti/store_test.go @@ -1,6 +1,7 @@ package rootmulti import ( + "context" "fmt" "sync" "testing" @@ -82,7 +83,7 @@ func TestSCSS_WriteAndHistoricalRead(t *testing.T) { store.histProofSem <- struct{}{} // Query API without proof at v1 should be served by SS and return v1 - resp := store.Query(abci.RequestQuery{ + resp := store.Query(context.Background(), abci.RequestQuery{ Path: "/store1/key", Data: keyBytes, Height: c1.Version, @@ -94,7 +95,7 @@ func TestSCSS_WriteAndHistoricalRead(t *testing.T) { <-store.histProofSem // Query API with proof at v1 should still return v1 (served by SC historical) - resp = store.Query(abci.RequestQuery{ + resp = store.Query(context.Background(), abci.RequestQuery{ Path: "/store1/key", Data: keyBytes, Height: c1.Version, @@ -260,7 +261,7 @@ func TestQuery_HistoricalNoProofWithoutSS_UsesPermit(t *testing.T) { store.histProofSem <- struct{}{} defer func() { <-store.histProofSem }() - resp := store.Query(abci.RequestQuery{ + resp := store.Query(context.Background(), abci.RequestQuery{ Path: "/store1/key", Data: keyBytes, Height: c1.Version, @@ -391,7 +392,7 @@ func TestQuery_LatestProofBypassesHistoricalPermit(t *testing.T) { store.histProofSem <- struct{}{} defer func() { <-store.histProofSem }() - resp := store.Query(abci.RequestQuery{ + resp := store.Query(context.Background(), abci.RequestQuery{ Path: "/store1/key", Data: keyBytes, Height: c1.Version, diff --git a/sei-cosmos/storev2/state/store.go b/sei-cosmos/storev2/state/store.go index a25e4b2690..4750e4d7bf 100644 --- a/sei-cosmos/storev2/state/store.go +++ b/sei-cosmos/storev2/state/store.go @@ -1,6 +1,7 @@ package state import ( + "context" "fmt" "io" @@ -89,7 +90,7 @@ func (st *Store) GetWorkingHash() ([]byte, error) { panic("get working hash operation is not supported") } -func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { +func (st *Store) Query(_ context.Context, req abci.RequestQuery) (res abci.ResponseQuery) { if req.Height > 0 && req.Height > st.version { return sdkerrors.QueryResult(errors.Wrap(sdkerrors.ErrInvalidHeight, "invalid height")) } diff --git a/sei-cosmos/tasks/metrics.go b/sei-cosmos/tasks/metrics.go new file mode 100644 index 0000000000..79c0b2f697 --- /dev/null +++ b/sei-cosmos/tasks/metrics.go @@ -0,0 +1,33 @@ +package tasks + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_tasks") + + taskMetrics = struct { + retries metric.Int64Counter + incarnations metric.Int64Counter + }{ + retries: must(meter.Int64Counter( + "scheduler_retries", + metric.WithDescription("Number of OCC scheduler transaction retries"), + metric.WithUnit("{count}"), + )), + incarnations: must(meter.Int64Counter( + "scheduler_incarnations", + metric.WithDescription("Maximum incarnation seen in OCC scheduler round"), + metric.WithUnit("{count}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-cosmos/tasks/scheduler.go b/sei-cosmos/tasks/scheduler.go index 473739737b..edcfa901f8 100644 --- a/sei-cosmos/tasks/scheduler.go +++ b/sei-cosmos/tasks/scheduler.go @@ -266,7 +266,11 @@ type schedulerMetrics struct { } func (s *scheduler) emitMetrics() { + taskMetrics.retries.Add(context.Background(), int64(s.metrics.retries)) + // TODO(PLT-353): remove once scheduler_retries verified telemetry.IncrCounter(float32(s.metrics.retries), "scheduler", "retries") + taskMetrics.incarnations.Add(context.Background(), int64(s.metrics.maxIncarnation)) + // TODO(PLT-353): remove once scheduler_incarnations verified telemetry.IncrCounter(float32(s.metrics.maxIncarnation), "scheduler", "incarnations") } diff --git a/sei-cosmos/telemetry/wrapper.go b/sei-cosmos/telemetry/wrapper.go index 535eccd2db..93348018dc 100644 --- a/sei-cosmos/telemetry/wrapper.go +++ b/sei-cosmos/telemetry/wrapper.go @@ -1,6 +1,7 @@ package telemetry import ( + "strings" "time" metrics "github.com/armon/go-metrics" @@ -16,6 +17,21 @@ const ( TxCount = "transaction" ) +// DenomClass buckets a denom into a cardinality-bounded class. +// Returns "usei", "ibc", "factory", or "other". +func DenomClass(denom string) string { + switch { + case denom == "usei": + return "usei" + case strings.HasPrefix(denom, "ibc/"): + return "ibc" + case strings.HasPrefix(denom, "factory/"): + return "factory" + default: + return "other" + } +} + // NewLabel creates a new instance of Label with name and value func NewLabel(name, value string) metrics.Label { return metrics.Label{Name: name, Value: value} diff --git a/sei-cosmos/x/auth/vesting/metrics.go b/sei-cosmos/x/auth/vesting/metrics.go new file mode 100644 index 0000000000..0a52cdbc7d --- /dev/null +++ b/sei-cosmos/x/auth/vesting/metrics.go @@ -0,0 +1,33 @@ +package vesting + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_x_auth_vesting") + + vestingMetrics = struct { + newAccount metric.Int64Counter + accountAmount metric.Int64Gauge + }{ + newAccount: must(meter.Int64Counter( + "new_account", + metric.WithDescription("Number of new vesting accounts created"), + metric.WithUnit("{count}"), + )), + accountAmount: must(meter.Int64Gauge( + "account_amount", + metric.WithDescription("Amount funded into the last new vesting account by denomination"), + metric.WithUnit("{usei}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-cosmos/x/auth/vesting/msg_server.go b/sei-cosmos/x/auth/vesting/msg_server.go index b4c5022f8f..1bd1994d27 100644 --- a/sei-cosmos/x/auth/vesting/msg_server.go +++ b/sei-cosmos/x/auth/vesting/msg_server.go @@ -12,6 +12,8 @@ import ( sdkerrors "github.com/sei-protocol/sei-chain/sei-cosmos/types/errors" "github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/keeper" "github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/vesting/types" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" ) type msgServer struct { @@ -82,10 +84,14 @@ func (s msgServer) CreateVestingAccount(goCtx context.Context, msg *types.MsgCre ak.SetAccount(ctx, acc) defer func() { + vestingMetrics.newAccount.Add(goCtx, 1) + // TODO(PLT-353): remove once vesting_new_account verified telemetry.IncrCounter(1, "new", "account") for _, a := range msg.Amount { if a.Amount.IsInt64() { + vestingMetrics.accountAmount.Record(goCtx, a.Amount.Int64(), otelmetric.WithAttributes(attribute.String("denom_class", telemetry.DenomClass(a.Denom)))) + // TODO(PLT-353): remove once vesting_account_amount verified telemetry.SetGaugeWithLabels( []string{"tx", "msg", "create_vesting_account"}, float32(a.Amount.Int64()), diff --git a/sei-cosmos/x/bank/keeper/metrics.go b/sei-cosmos/x/bank/keeper/metrics.go new file mode 100644 index 0000000000..bca6d444d7 --- /dev/null +++ b/sei-cosmos/x/bank/keeper/metrics.go @@ -0,0 +1,27 @@ +package keeper + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_x_bank_keeper") + + bankMetrics = struct { + sendAmount metric.Int64Gauge + }{ + sendAmount: must(meter.Int64Gauge( + "send_amount", + metric.WithDescription("Amount sent in the last MsgSend transaction by denomination"), + metric.WithUnit("{usei}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-cosmos/x/bank/keeper/msg_server.go b/sei-cosmos/x/bank/keeper/msg_server.go index 32148376ba..b4447fb140 100644 --- a/sei-cosmos/x/bank/keeper/msg_server.go +++ b/sei-cosmos/x/bank/keeper/msg_server.go @@ -9,6 +9,8 @@ import ( sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" sdkerrors "github.com/sei-protocol/sei-chain/sei-cosmos/types/errors" "github.com/sei-protocol/sei-chain/sei-cosmos/x/bank/types" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" ) type msgServer struct { @@ -56,6 +58,8 @@ func (k msgServer) Send(goCtx context.Context, msg *types.MsgSend) (*types.MsgSe defer func() { for _, a := range msg.Amount { if a.Amount.IsInt64() { + bankMetrics.sendAmount.Record(goCtx, a.Amount.Int64(), otelmetric.WithAttributes(attribute.String("denom_class", telemetry.DenomClass(a.Denom)))) + // TODO(PLT-353): remove once bank_send_amount verified telemetry.SetGaugeWithLabels( []string{"tx", "msg", "send"}, float32(a.Amount.Int64()), diff --git a/sei-cosmos/x/distribution/keeper/metrics.go b/sei-cosmos/x/distribution/keeper/metrics.go new file mode 100644 index 0000000000..0c8956eb2c --- /dev/null +++ b/sei-cosmos/x/distribution/keeper/metrics.go @@ -0,0 +1,33 @@ +package keeper + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_x_distribution_keeper") + + distributionMetrics = struct { + withdrawRewardAmount metric.Int64Gauge + withdrawCommissionAmount metric.Int64Gauge + }{ + withdrawRewardAmount: must(meter.Int64Gauge( + "withdraw_reward_amount", + metric.WithDescription("Amount withdrawn as delegation rewards in the last withdrawal transaction by denomination"), + metric.WithUnit("{usei}"), + )), + withdrawCommissionAmount: must(meter.Int64Gauge( + "withdraw_commission_amount", + metric.WithDescription("Amount withdrawn as validator commission in the last withdrawal transaction by denomination"), + metric.WithUnit("{usei}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-cosmos/x/distribution/keeper/msg_server.go b/sei-cosmos/x/distribution/keeper/msg_server.go index 44ab91a9db..0310a0a02a 100644 --- a/sei-cosmos/x/distribution/keeper/msg_server.go +++ b/sei-cosmos/x/distribution/keeper/msg_server.go @@ -8,6 +8,8 @@ import ( "github.com/sei-protocol/sei-chain/sei-cosmos/telemetry" sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" "github.com/sei-protocol/sei-chain/sei-cosmos/x/distribution/types" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" ) type msgServer struct { @@ -68,6 +70,8 @@ func (k msgServer) WithdrawDelegatorReward(goCtx context.Context, msg *types.Msg defer func() { for _, a := range amount { if a.Amount.IsInt64() { + distributionMetrics.withdrawRewardAmount.Record(goCtx, a.Amount.Int64(), otelmetric.WithAttributes(attribute.String("denom_class", telemetry.DenomClass(a.Denom)))) + // TODO(PLT-353): remove once distribution_withdraw_reward_amount verified telemetry.SetGaugeWithLabels( []string{"tx", "msg", "withdraw_reward"}, float32(a.Amount.Int64()), @@ -102,6 +106,8 @@ func (k msgServer) WithdrawValidatorCommission(goCtx context.Context, msg *types defer func() { for _, a := range amount { if a.Amount.IsInt64() { + distributionMetrics.withdrawCommissionAmount.Record(goCtx, a.Amount.Int64(), otelmetric.WithAttributes(attribute.String("denom_class", telemetry.DenomClass(a.Denom)))) + // TODO(PLT-353): remove once distribution_withdraw_commission_amount verified telemetry.SetGaugeWithLabels( []string{"tx", "msg", "withdraw_commission"}, float32(a.Amount.Int64()), diff --git a/sei-cosmos/x/gov/keeper/metrics.go b/sei-cosmos/x/gov/keeper/metrics.go new file mode 100644 index 0000000000..f2559a2f10 --- /dev/null +++ b/sei-cosmos/x/gov/keeper/metrics.go @@ -0,0 +1,39 @@ +package keeper + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_x_gov_keeper") + + govMetrics = struct { + proposalTotal metric.Int64Counter + voteTotal metric.Int64Counter + depositTotal metric.Int64Counter + }{ + proposalTotal: must(meter.Int64Counter( + "proposal", + metric.WithDescription("Number of governance proposals submitted"), + metric.WithUnit("{count}"), + )), + voteTotal: must(meter.Int64Counter( + "vote", + metric.WithDescription("Number of governance votes cast by proposal"), + metric.WithUnit("{count}"), + )), + depositTotal: must(meter.Int64Counter( + "deposit", + metric.WithDescription("Number of governance deposits made by proposal"), + metric.WithUnit("{count}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-cosmos/x/gov/keeper/msg_server.go b/sei-cosmos/x/gov/keeper/msg_server.go index 82672539ac..7847fc6455 100644 --- a/sei-cosmos/x/gov/keeper/msg_server.go +++ b/sei-cosmos/x/gov/keeper/msg_server.go @@ -31,7 +31,11 @@ func (k msgServer) SubmitProposal(goCtx context.Context, msg *types.MsgSubmitPro return nil, err } - defer telemetry.IncrCounter(1, types.ModuleName, "proposal") + defer func() { + govMetrics.proposalTotal.Add(goCtx, 1) + // TODO(PLT-353): remove once gov_proposal_total verified + telemetry.IncrCounter(1, types.ModuleName, "proposal") + }() votingStarted, err := k.AddDeposit(ctx, proposal.ProposalId, msg.GetProposer(), msg.GetInitialDeposit()) if err != nil { @@ -71,13 +75,17 @@ func (k msgServer) Vote(goCtx context.Context, msg *types.MsgVote) (*types.MsgVo return nil, err } - defer telemetry.IncrCounterWithLabels( - []string{types.ModuleName, "vote"}, - 1, - []metrics.Label{ - telemetry.NewLabel("proposal_id", strconv.FormatUint(msg.ProposalId, 10)), - }, - ) + defer func() { + govMetrics.voteTotal.Add(goCtx, 1) + // TODO(PLT-353): remove once gov_vote_total verified + telemetry.IncrCounterWithLabels( + []string{types.ModuleName, "vote"}, + 1, + []metrics.Label{ + telemetry.NewLabel("proposal_id", strconv.FormatUint(msg.ProposalId, 10)), + }, + ) + }() ctx.EventManager().EmitEvent( sdk.NewEvent( @@ -101,13 +109,17 @@ func (k msgServer) VoteWeighted(goCtx context.Context, msg *types.MsgVoteWeighte return nil, err } - defer telemetry.IncrCounterWithLabels( - []string{types.ModuleName, "vote"}, - 1, - []metrics.Label{ - telemetry.NewLabel("proposal_id", strconv.FormatUint(msg.ProposalId, 10)), - }, - ) + defer func() { + govMetrics.voteTotal.Add(goCtx, 1) + // TODO(PLT-353): remove once gov_vote_total verified + telemetry.IncrCounterWithLabels( + []string{types.ModuleName, "vote"}, + 1, + []metrics.Label{ + telemetry.NewLabel("proposal_id", strconv.FormatUint(msg.ProposalId, 10)), + }, + ) + }() ctx.EventManager().EmitEvent( sdk.NewEvent( @@ -131,13 +143,17 @@ func (k msgServer) Deposit(goCtx context.Context, msg *types.MsgDeposit) (*types return nil, err } - defer telemetry.IncrCounterWithLabels( - []string{types.ModuleName, "deposit"}, - 1, - []metrics.Label{ - telemetry.NewLabel("proposal_id", strconv.FormatUint(msg.ProposalId, 10)), - }, - ) + defer func() { + govMetrics.depositTotal.Add(goCtx, 1) + // TODO(PLT-353): remove once gov_deposit_total verified + telemetry.IncrCounterWithLabels( + []string{types.ModuleName, "deposit"}, + 1, + []metrics.Label{ + telemetry.NewLabel("proposal_id", strconv.FormatUint(msg.ProposalId, 10)), + }, + ) + }() ctx.EventManager().EmitEvent( sdk.NewEvent( diff --git a/sei-cosmos/x/staking/keeper/metrics.go b/sei-cosmos/x/staking/keeper/metrics.go new file mode 100644 index 0000000000..042a6204fc --- /dev/null +++ b/sei-cosmos/x/staking/keeper/metrics.go @@ -0,0 +1,57 @@ +package keeper + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_x_staking_keeper") + + stakingMetrics = struct { + delegateTotal metric.Int64Counter + delegateAmount metric.Int64Gauge + redelegateTotal metric.Int64Counter + redelegateAmount metric.Int64Gauge + undelegateTotal metric.Int64Counter + undelegateAmount metric.Int64Gauge + }{ + delegateTotal: must(meter.Int64Counter( + "delegate", + metric.WithDescription("Number of delegation transactions"), + metric.WithUnit("{count}"), + )), + delegateAmount: must(meter.Int64Gauge( + "delegate_amount", + metric.WithDescription("Amount delegated in the last delegation transaction"), + metric.WithUnit("{usei}"), + )), + redelegateTotal: must(meter.Int64Counter( + "redelegate", + metric.WithDescription("Number of redelegation transactions"), + metric.WithUnit("{count}"), + )), + redelegateAmount: must(meter.Int64Gauge( + "redelegate_amount", + metric.WithDescription("Amount redelegated in the last redelegation transaction"), + metric.WithUnit("{usei}"), + )), + undelegateTotal: must(meter.Int64Counter( + "undelegate", + metric.WithDescription("Number of undelegation transactions"), + metric.WithUnit("{count}"), + )), + undelegateAmount: must(meter.Int64Gauge( + "undelegate_amount", + metric.WithDescription("Amount undelegated in the last undelegation transaction"), + metric.WithUnit("{usei}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-cosmos/x/staking/keeper/msg_server.go b/sei-cosmos/x/staking/keeper/msg_server.go index 72de845384..d8549e8554 100644 --- a/sei-cosmos/x/staking/keeper/msg_server.go +++ b/sei-cosmos/x/staking/keeper/msg_server.go @@ -225,7 +225,11 @@ func (k msgServer) Delegate(goCtx context.Context, msg *types.MsgDelegate) (*typ if msg.Amount.Amount.IsInt64() { defer func() { + stakingMetrics.delegateTotal.Add(goCtx, 1) + // TODO(PLT-353): remove once staking_delegate_total verified telemetry.IncrCounter(1, types.ModuleName, "delegate") + stakingMetrics.delegateAmount.Record(goCtx, msg.Amount.Amount.Int64()) + // TODO(PLT-353): remove once staking_delegate_amount verified telemetry.SetGaugeWithLabels( []string{"tx", "msg", msg.Type()}, float32(msg.Amount.Amount.Int64()), @@ -290,7 +294,11 @@ func (k msgServer) BeginRedelegate(goCtx context.Context, msg *types.MsgBeginRed if msg.Amount.Amount.IsInt64() { defer func() { + stakingMetrics.redelegateTotal.Add(goCtx, 1) + // TODO(PLT-353): remove once staking_redelegate_total verified telemetry.IncrCounter(1, types.ModuleName, "redelegate") + stakingMetrics.redelegateAmount.Record(goCtx, msg.Amount.Amount.Int64()) + // TODO(PLT-353): remove once staking_redelegate_amount verified telemetry.SetGaugeWithLabels( []string{"tx", "msg", msg.Type()}, float32(msg.Amount.Amount.Int64()), @@ -352,7 +360,11 @@ func (k msgServer) Undelegate(goCtx context.Context, msg *types.MsgUndelegate) ( if msg.Amount.Amount.IsInt64() { defer func() { + stakingMetrics.undelegateTotal.Add(goCtx, 1) + // TODO(PLT-353): remove once staking_undelegate_total verified telemetry.IncrCounter(1, types.ModuleName, "undelegate") + stakingMetrics.undelegateAmount.Record(goCtx, msg.Amount.Amount.Int64()) + // TODO(PLT-353): remove once staking_undelegate_amount verified telemetry.SetGaugeWithLabels( []string{"tx", "msg", msg.Type()}, float32(msg.Amount.Amount.Int64()), diff --git a/sei-cosmos/x/upgrade/abci.go b/sei-cosmos/x/upgrade/abci.go index 695e4a102c..b36699be40 100644 --- a/sei-cosmos/x/upgrade/abci.go +++ b/sei-cosmos/x/upgrade/abci.go @@ -11,6 +11,8 @@ import ( "github.com/sei-protocol/sei-chain/sei-cosmos/x/upgrade/keeper" "github.com/sei-protocol/sei-chain/sei-cosmos/x/upgrade/types" "github.com/sei-protocol/seilog" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" ) var logger = seilog.NewLogger("cosmos", "x", "upgrade") @@ -27,7 +29,12 @@ func BeginBlocker(k keeper.Keeper, ctx sdk.Context) { if ctx.IsTracing() { return } - defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) + beginBlockerStart := time.Now() + defer func() { + upgradeMetrics.beginBlockerDuration.Record(ctx.Context(), time.Since(beginBlockerStart).Seconds()) + // TODO(PLT-353): remove once upgrade_begin_blocker_duration verified + telemetry.ModuleMeasureSince(types.ModuleName, beginBlockerStart, telemetry.MetricKeyBeginBlocker) + }() plan, planFound := k.GetUpgradePlan(ctx) @@ -50,6 +57,10 @@ func BeginBlocker(k keeper.Keeper, ctx sdk.Context) { return } + upgradeMetrics.planHeight.Record(ctx.Context(), plan.Height, otelmetric.WithAttributes( + attribute.String("name", plan.Name), + )) + // TODO(PLT-353): remove once upgrade_plan_height verified telemetry.SetGaugeWithLabels( []string{"cosmos", "upgrade", "plan", "height"}, float32(plan.Height), diff --git a/sei-cosmos/x/upgrade/keeper/keeper.go b/sei-cosmos/x/upgrade/keeper/keeper.go index c5623f738f..e4b18ba5ed 100644 --- a/sei-cosmos/x/upgrade/keeper/keeper.go +++ b/sei-cosmos/x/upgrade/keeper/keeper.go @@ -11,6 +11,8 @@ import ( "github.com/armon/go-metrics" tmos "github.com/sei-protocol/sei-chain/sei-tendermint/libs/os" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" "github.com/sei-protocol/sei-chain/sei-cosmos/codec" "github.com/sei-protocol/sei-chain/sei-cosmos/store/prefix" @@ -198,6 +200,10 @@ func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { bz := k.cdc.MustMarshal(&plan) store.Set(types.PlanKey(), bz) + upgradeKeeperMetrics.pendingPlanHeight.Record(ctx.Context(), plan.Height, otelmetric.WithAttributes( + attribute.String("name", plan.Name), + )) + // TODO(PLT-353): remove once upgrade_pending_plan_height verified telemetry.SetGaugeWithLabels( []string{"cosmos", "upgrade", "plan", "height"}, float32(plan.Height), diff --git a/sei-cosmos/x/upgrade/keeper/metrics.go b/sei-cosmos/x/upgrade/keeper/metrics.go new file mode 100644 index 0000000000..737225bc86 --- /dev/null +++ b/sei-cosmos/x/upgrade/keeper/metrics.go @@ -0,0 +1,27 @@ +package keeper + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_x_upgrade_keeper") + + upgradeKeeperMetrics = struct { + pendingPlanHeight metric.Int64Gauge + }{ + pendingPlanHeight: must(meter.Int64Gauge( + "upgrade_pending_plan_height", + metric.WithDescription("Height of a pending upgrade plan at schedule time by name"), + metric.WithUnit("{block}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-cosmos/x/upgrade/metrics.go b/sei-cosmos/x/upgrade/metrics.go new file mode 100644 index 0000000000..871dcc5922 --- /dev/null +++ b/sei-cosmos/x/upgrade/metrics.go @@ -0,0 +1,39 @@ +package upgrade + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("seicosmos_x_upgrade") + + // finerGrainedBuckets units are in seconds + finerGrainedBuckets = metric.WithExplicitBucketBoundaries( + 0.000025, 0.000050, 0.0001, 0.0005, 0.001, 0.0025, 0.005, 0.010, 0.020, 0.050, 0.075, 0.1, 0.25, 0.5, 1, 10, + ) + + upgradeMetrics = struct { + beginBlockerDuration metric.Float64Histogram + planHeight metric.Int64Gauge + }{ + beginBlockerDuration: must(meter.Float64Histogram( + "begin_blocker_duration", + metric.WithDescription("Duration of upgrade begin-blocker execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + planHeight: must(meter.Int64Gauge( + "plan_height", + metric.WithDescription("Scheduled upgrade plan height by name"), + metric.WithUnit("{block}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/sei-ibc-go/modules/core/03-connection/types/msgs_test.go b/sei-ibc-go/modules/core/03-connection/types/msgs_test.go index cce1e42564..7b8fafc7b8 100644 --- a/sei-ibc-go/modules/core/03-connection/types/msgs_test.go +++ b/sei-ibc-go/modules/core/03-connection/types/msgs_test.go @@ -1,6 +1,7 @@ package types_test import ( + "context" "fmt" "testing" "time" @@ -59,7 +60,7 @@ func (suite *MsgTestSuite) SetupTest() { kvStore.Set([]byte("KEY"), []byte("VALUE")) _ = store.Commit(true) - res := store.Query(abci.RequestQuery{ + res := store.Query(context.Background(), abci.RequestQuery{ Path: fmt.Sprintf("/%s/key", storeKey.Name()), Data: []byte("KEY"), Prove: true, diff --git a/sei-ibc-go/modules/core/04-channel/types/msgs_test.go b/sei-ibc-go/modules/core/04-channel/types/msgs_test.go index 4db77e42bc..624bcdbdb5 100644 --- a/sei-ibc-go/modules/core/04-channel/types/msgs_test.go +++ b/sei-ibc-go/modules/core/04-channel/types/msgs_test.go @@ -1,6 +1,7 @@ package types_test import ( + "context" "fmt" "testing" @@ -83,7 +84,7 @@ func (suite *TypesTestSuite) SetupTest() { kvStore.Set([]byte("KEY"), []byte("VALUE")) _ = store.Commit(true) - res := store.Query(abci.RequestQuery{ + res := store.Query(context.Background(), abci.RequestQuery{ Path: fmt.Sprintf("/%s/key", storeKey.Name()), Data: []byte("KEY"), Prove: true, diff --git a/sei-ibc-go/modules/core/23-commitment/types/merkle_test.go b/sei-ibc-go/modules/core/23-commitment/types/merkle_test.go index ef62ead5a3..816d261e18 100644 --- a/sei-ibc-go/modules/core/23-commitment/types/merkle_test.go +++ b/sei-ibc-go/modules/core/23-commitment/types/merkle_test.go @@ -1,6 +1,7 @@ package types_test import ( + "context" "fmt" "testing" @@ -14,7 +15,7 @@ func (suite *MerkleTestSuite) TestVerifyMembership() { suite.iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE")) cid := suite.store.Commit(true) - res := suite.store.Query(abci.RequestQuery{ + res := suite.store.Query(context.Background(), abci.RequestQuery{ Path: fmt.Sprintf("/%s/key", suite.storeKey.Name()), // required path to get key/value+proof Data: []byte("MYKEY"), Prove: true, @@ -79,7 +80,7 @@ func (suite *MerkleTestSuite) TestVerifyNonMembership() { cid := suite.store.Commit(true) // Get Proof - res := suite.store.Query(abci.RequestQuery{ + res := suite.store.Query(context.Background(), abci.RequestQuery{ Path: fmt.Sprintf("/%s/key", suite.storeKey.Name()), // required path to get key/value+proof Data: []byte("MYABSENTKEY"), Prove: true,