diff --git a/go.mod b/go.mod index 4172c355..cac8be5d 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,8 @@ go 1.22 toolchain go1.22.5 +replace github.com/gnolang/gno => github.com/linhpn99/gno v1.0.0 + require ( github.com/99designs/gqlgen v0.17.49 github.com/cockroachdb/pebble v1.1.1 @@ -15,11 +17,13 @@ require ( github.com/olahol/melody v1.2.1 github.com/peterbourgon/ff/v3 v3.4.0 github.com/pkg/errors v0.9.1 + github.com/rs/cors v1.11.0 github.com/stretchr/testify v1.9.0 github.com/vektah/gqlparser/v2 v2.5.16 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 golang.org/x/sync v0.7.0 + ) require ( diff --git a/go.sum b/go.sum index af368e53..29227d74 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= -github.com/gnolang/gno v0.1.1 h1:t41S0SWIUa3syI7XpRAuCneCgRc8gOJ2g8DkUedF72U= -github.com/gnolang/gno v0.1.1/go.mod h1:BTaBNeaoY/W95NN6QA4RCoQ6Z7mi8M+Zb1I1wMWGg2w= github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 h1:GKvsK3oLWG9B1GL7WP/VqwM6C92j5tIvB844oggL9Lk= github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216/go.mod h1:xJhtEL7ahjM1WJipt89gel8tHzfIl/LyMY+lCYh38d8= github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= @@ -143,6 +141,8 @@ github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/linhpn99/gno v1.0.0 h1:2f+fX2c03jbD82mQJjbPk0oRLcyIKJPNLPFFoBpPX7A= +github.com/linhpn99/gno v1.0.0/go.mod h1:BTaBNeaoY/W95NN6QA4RCoQ6Z7mi8M+Zb1I1wMWGg2w= github.com/madz-lab/insertion-queue v0.0.0-20230520191346-295d3348f63a h1:KxTVE11SAJzp+PnqaCw0Rzb/of6mQexpTIyZwM/JTJU= github.com/madz-lab/insertion-queue v0.0.0-20230520191346-295d3348f63a/go.mod h1:kWWMMyVnsC79rIkENl7FQUU2EQql12s8ETwjsDBiMtA= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -180,6 +180,8 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= diff --git a/serve/graph/generated.go b/serve/graph/generated.go index a95c1c62..bc39ff95 100644 --- a/serve/graph/generated.go +++ b/serve/graph/generated.go @@ -124,6 +124,10 @@ type ComplexityRoot struct { Send func(childComplexity int) int } + MsgNoop struct { + Caller func(childComplexity int) int + } + MsgRun struct { Caller func(childComplexity int) int Package func(childComplexity int) int @@ -527,6 +531,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.MsgCall.Send(childComplexity), true + case "MsgNoop.caller": + if e.complexity.MsgNoop.Caller == nil { + break + } + + return e.complexity.MsgNoop.Caller(childComplexity), true + case "MsgRun.caller": if e.complexity.MsgRun.Caller == nil { break @@ -781,6 +792,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputMemPackageInput, ec.unmarshalInputMsgAddPackageInput, ec.unmarshalInputMsgCallInput, + ec.unmarshalInputMsgNoopInput, ec.unmarshalInputMsgRunInput, ec.unmarshalInputTransactionBankMessageInput, ec.unmarshalInputTransactionFilter, @@ -3030,6 +3042,50 @@ func (ec *executionContext) fieldContext_MsgCall_args(ctx context.Context, field return fc, nil } +func (ec *executionContext) _MsgNoop_caller(ctx context.Context, field graphql.CollectedField, obj *model.MsgNoop) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_MsgNoop_caller(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Caller, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_MsgNoop_caller(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "MsgNoop", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _MsgRun_caller(ctx context.Context, field graphql.CollectedField, obj *model.MsgRun) (ret graphql.Marshaler) { fc, err := ec.fieldContext_MsgRun_caller(ctx, field) if err != nil { @@ -6899,6 +6955,33 @@ func (ec *executionContext) unmarshalInputMsgCallInput(ctx context.Context, obj return it, nil } +func (ec *executionContext) unmarshalInputMsgNoopInput(ctx context.Context, obj interface{}) (model.MsgNoopInput, error) { + var it model.MsgNoopInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"caller"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "caller": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("caller")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Caller = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputMsgRunInput(ctx context.Context, obj interface{}) (model.MsgRunInput, error) { var it model.MsgRunInput asMap := map[string]interface{}{} @@ -7133,7 +7216,7 @@ func (ec *executionContext) unmarshalInputTransactionVmMessageInput(ctx context. asMap[k] = v } - fieldsInOrder := [...]string{"exec", "add_package", "run"} + fieldsInOrder := [...]string{"exec", "add_package", "run", "no_op"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -7161,6 +7244,13 @@ func (ec *executionContext) unmarshalInputTransactionVmMessageInput(ctx context. return it, err } it.Run = data + case "no_op": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("no_op")) + data, err := ec.unmarshalOMsgNoopInput2ᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐMsgNoopInput(ctx, v) + if err != nil { + return it, err + } + it.NoOp = data } } @@ -7226,6 +7316,13 @@ func (ec *executionContext) _MessageValue(ctx context.Context, sel ast.Selection return graphql.Null } return ec._MsgRun(ctx, sel, obj) + case model.MsgNoop: + return ec._MsgNoop(ctx, sel, &obj) + case *model.MsgNoop: + if obj == nil { + return graphql.Null + } + return ec._MsgNoop(ctx, sel, obj) case model.UnexpectedMessage: return ec._UnexpectedMessage(ctx, sel, &obj) case *model.UnexpectedMessage: @@ -7798,6 +7895,45 @@ func (ec *executionContext) _MsgCall(ctx context.Context, sel ast.SelectionSet, return out } +var msgNoopImplementors = []string{"MsgNoop", "MessageValue"} + +func (ec *executionContext) _MsgNoop(ctx context.Context, sel ast.SelectionSet, obj *model.MsgNoop) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, msgNoopImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("MsgNoop") + case "caller": + out.Values[i] = ec._MsgNoop_caller(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var msgRunImplementors = []string{"MsgRun", "MessageValue"} func (ec *executionContext) _MsgRun(ctx context.Context, sel ast.SelectionSet, obj *model.MsgRun) graphql.Marshaler { @@ -9525,6 +9661,14 @@ func (ec *executionContext) unmarshalOMsgCallInput2ᚖgithubᚗcomᚋgnolangᚋt return &res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) unmarshalOMsgNoopInput2ᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐMsgNoopInput(ctx context.Context, v interface{}) (*model.MsgNoopInput, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputMsgNoopInput(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalOMsgRunInput2ᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐMsgRunInput(ctx context.Context, v interface{}) (*model.MsgRunInput, error) { if v == nil { return nil, nil diff --git a/serve/graph/model/models_gen.go b/serve/graph/model/models_gen.go index e3e953cb..8bbbaddc 100644 --- a/serve/graph/model/models_gen.go +++ b/serve/graph/model/models_gen.go @@ -244,6 +244,24 @@ type MsgCallInput struct { Args []string `json:"args,omitempty"` } +// `MsgNoop` is a message with a message router of `vm` and a message type of `no_op`. +// `MsgNoop is the execute nothing`. +type MsgNoop struct { + // the bech32 address of the function caller. + // ex) `g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` + Caller string `json:"caller"` +} + +func (MsgNoop) IsMessageValue() {} + +// `MsgNoopInput` represents input parameters required when the message type is `no_op`. +type MsgNoopInput struct { + // the bech32 address of the function caller. + // You can filter by the function caller's address. + // ex) `g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` + Caller *string `json:"caller,omitempty"` +} + // `MsgRun` is a message with a message router of `vm` and a message type of `run`. // `MsgRun is the execute arbitrary Gno code tx message`. type MsgRun struct { @@ -328,7 +346,7 @@ type TransactionFilter struct { // `TransactionMessageInput` can be configured as a filter with a transaction message's `router` and `type` and `parameters(bank / vm)`. type TransactionMessageInput struct { // The type of transaction message. - // The value of `typeUrl` can be `send`, `exec`, `add_package`, `run`. + // The value of `typeUrl` can be `send`, `exec`, `add_package`, `run`, `no_op`. TypeURL *MessageType `json:"type_url,omitempty"` // The route of transaction message. // The value of `route` can be `bank`, `vm`. @@ -347,6 +365,8 @@ type TransactionVMMessageInput struct { AddPackage *MsgAddPackageInput `json:"add_package,omitempty"` // `MsgRunInput` represents input parameters required when the message type is `run`. Run *MsgRunInput `json:"run,omitempty"` + // `MsgNoopInput` represents input parameters required when the message type is `no_op`. + NoOp *MsgNoopInput `json:"no_op,omitempty"` } // The `TxFee` has information about the fee used in the transaction and the maximum gas fee specified by the user. @@ -417,7 +437,7 @@ func (e MessageRoute) MarshalGQL(w io.Writer) { } // `MessageType` is message type of the transaction. -// `MessageType` has the values `send`, `exec`, `add_package`, and `run`. +// `MessageType` has the values `send`, `exec`, `add_package`, `run` and `no_op`. type MessageType string const ( @@ -433,6 +453,9 @@ const ( // The route value for this message type is `vm`, and the value for transactional messages is `MsgRun`. // This is a transactional message that executes an arbitrary Gno-coded TX message. MessageTypeRun MessageType = "run" + // The route value for this message type is `vm`, and the value for transactional messages is `MsgNoop`. + // This is a transactional message that executes nothing. + MessageTypeNoOp MessageType = "no_op" ) var AllMessageType = []MessageType{ @@ -440,11 +463,12 @@ var AllMessageType = []MessageType{ MessageTypeExec, MessageTypeAddPackage, MessageTypeRun, + MessageTypeNoOp, } func (e MessageType) IsValid() bool { switch e { - case MessageTypeSend, MessageTypeExec, MessageTypeAddPackage, MessageTypeRun: + case MessageTypeSend, MessageTypeExec, MessageTypeAddPackage, MessageTypeRun, MessageTypeNoOp: return true } return false diff --git a/serve/graph/model/transaction.go b/serve/graph/model/transaction.go index 68828f91..7971becd 100644 --- a/serve/graph/model/transaction.go +++ b/serve/graph/model/transaction.go @@ -231,7 +231,14 @@ func NewTransactionMessage(message std.Msg) *TransactionMessage { TypeURL: MessageTypeRun.String(), Value: makeVMMsgRun(message), } + case MessageTypeNoOp.String(): + contentMessage = &TransactionMessage{ + Route: MessageRouteVM.String(), + TypeURL: MessageTypeNoOp.String(), + Value: makeVMMsgNoop(message), + } } + } if contentMessage == nil { @@ -261,6 +268,10 @@ func (tm *TransactionMessage) VMMsgRun() MsgRun { return tm.Value.(MsgRun) } +func (tm *TransactionMessage) VMMsgNoop() MsgNoop { + return tm.Value.(MsgNoop) +} + func makeEvent(abciEvent abci.Event) (Event, error) { data, err := json.Marshal(abciEvent) if err != nil { @@ -356,6 +367,17 @@ func makeVMMsgRun(value std.Msg) MsgRun { } } +func makeVMMsgNoop(value std.Msg) MsgNoop { + decodedMessage, err := cast[vm.MsgNoop](value) + if err != nil { + return MsgNoop{} + } + + return MsgNoop{ + Caller: decodedMessage.Caller.String(), + } +} + func makeUnexpectedMessage(value std.Msg) UnexpectedMessage { raw, err := json.Marshal(value) if err != nil { diff --git a/serve/graph/schema/filter/transaction_filter.graphql b/serve/graph/schema/filter/transaction_filter.graphql index 7b0f01ce..5c9621fa 100644 --- a/serve/graph/schema/filter/transaction_filter.graphql +++ b/serve/graph/schema/filter/transaction_filter.graphql @@ -126,7 +126,7 @@ Transaction's message to filter Transactions. input TransactionMessageInput { """ The type of transaction message. - The value of `typeUrl` can be `send`, `exec`, `add_package`, `run`. + The value of `typeUrl` can be `send`, `exec`, `add_package`, `run`, `no_op`. """ type_url: MessageType @@ -200,6 +200,11 @@ input TransactionVmMessageInput { `MsgRunInput` represents input parameters required when the message type is `run`. """ run: MsgRunInput + + """ + `MsgNoopInput` represents input parameters required when the message type is `no_op`. + """ + no_op: MsgNoopInput } """ @@ -284,6 +289,18 @@ input MsgRunInput { package: MemPackageInput } +""" +`MsgNoopInput` represents input parameters required when the message type is `no_op`. +""" +input MsgNoopInput { + """ + the bech32 address of the function caller. + You can filter by the function caller's address. + ex) `g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` + """ + caller: String +} + """ `MemPackageInput` represents a package stored in memory. """ diff --git a/serve/graph/schema/types/transaction.graphql b/serve/graph/schema/types/transaction.graphql index 6ca1e7a8..e10e83de 100644 --- a/serve/graph/schema/types/transaction.graphql +++ b/serve/graph/schema/types/transaction.graphql @@ -74,7 +74,7 @@ enum MessageRoute { """ `MessageType` is message type of the transaction. -`MessageType` has the values `send`, `exec`, `add_package`, and `run`. +`MessageType` has the values `send`, `exec`, `add_package`, `run` and `no_op`. """ enum MessageType { """ @@ -100,12 +100,18 @@ enum MessageType { This is a transactional message that executes an arbitrary Gno-coded TX message. """ run + + """ + The route value for this message type is `vm`, and the value for transactional messages is `MsgNoop`. + This is a transactional message that executes nothing. + """ + no_op } type TransactionMessage { """ The type of transaction message. - The value of `typeUrl` can be `send`, `exec`, `add_package`, `run`. + The value of `typeUrl` can be `send`, `exec`, `add_package`, `run`, `no_op`. """ typeUrl: String! @@ -117,12 +123,12 @@ type TransactionMessage { """ MessageValue is the content of the transaction. - `value` can be of type `BankMsgSend`, `MsgCall`, `MsgAddPackage`, `MsgRun`, `UnexpectedMessage`. + `value` can be of type `BankMsgSend`, `MsgCall`, `MsgAddPackage`, `MsgRun`, `MsgNoop, `UnexpectedMessage`. """ value: MessageValue! } -union MessageValue = BankMsgSend | MsgCall | MsgAddPackage | MsgRun | UnexpectedMessage +union MessageValue = BankMsgSend | MsgCall | MsgAddPackage | MsgRun | MsgNoop | UnexpectedMessage """ `BankMsgSend` is a message with a message router of `bank` and a message type of `send`. @@ -227,6 +233,18 @@ type MsgRun { package: MemPackage! } +""" +`MsgNoop` is a message with a message router of `vm` and a message type of `no_op`. +`MsgNoop is the execute nothing`. +""" +type MsgNoop { + """ + the bech32 address of the function caller. + ex) `g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` + """ + caller: String! +} + """ `UnexpectedMessage` is an Undefined Message, which is a message that decoding failed. """ diff --git a/serve/graph/transaction_filter.go b/serve/graph/transaction_filter.go index aefb3013..1c88ac61 100644 --- a/serve/graph/transaction_filter.go +++ b/serve/graph/transaction_filter.go @@ -295,6 +295,10 @@ func filteredTransactionMessageBy( if !filteredMessageOfMsgRunBy(tm.VMMsgRun(), messageInput.VMParam) { return false } + case model.MessageTypeNoOp.String(): + if !filteredMessageOfMsgNoOpBy(tm.VMMsgNoop(), messageInput.VMParam) { + return false + } default: return false } @@ -442,3 +446,21 @@ func filteredMessageOfMsgRunBy(messageValue model.MsgRun, vmMessageInput *model. return true } + +// `filteredMessageOfMsgNoOpBy` checks the conditions of a message of type MsgNoop +func filteredMessageOfMsgNoOpBy(messageValue model.MsgNoop, vmMessageInput *model.TransactionVMMessageInput) bool { + params := vmMessageInput + if params == nil { + return true + } + + if params.NoOp == nil { + return false + } + + if params.NoOp.Caller != nil && deref(params.NoOp.Caller) != messageValue.Caller { + return false + } + + return true +}