github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/auth/client/utils/service.go (about) 1 package utils 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 gogogrpc "github.com/gogo/protobuf/grpc" 9 10 "github.com/gogo/protobuf/proto" 11 "google.golang.org/grpc/codes" 12 "google.golang.org/grpc/status" 13 14 cliContext "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context" 15 codectypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/types" 16 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 17 typeadapter "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/ibc-adapter" 18 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/query" 19 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/tx" 20 ) 21 22 var _ tx.ServiceServer = txServer{} 23 24 const ( 25 eventFormat = "{eventType}.{eventAttribute}={value}" 26 ) 27 28 type baseAppSimulateFn func(txBytes []byte) (types.GasInfo, *types.Result, error) 29 30 // txServer is the server for the protobuf Tx service. 31 type txServer struct { 32 clientCtx cliContext.CLIContext 33 simulate baseAppSimulateFn 34 interfaceRegistry codectypes.InterfaceRegistry 35 } 36 37 // NewTxServer creates a new Tx service server. 38 func NewTxServer(clientCtx cliContext.CLIContext, simulate baseAppSimulateFn, interfaceRegistry codectypes.InterfaceRegistry) tx.ServiceServer { 39 return txServer{ 40 clientCtx: clientCtx, 41 simulate: simulate, 42 interfaceRegistry: interfaceRegistry, 43 } 44 } 45 46 func (t txServer) Simulate(ctx context.Context, req *tx.SimulateRequest) (*tx.SimulateResponse, error) { 47 if req == nil { 48 return nil, status.Error(codes.InvalidArgument, "invalid empty tx") 49 } 50 51 txBytes := req.TxBytes 52 if txBytes == nil && req.Tx != nil { 53 // This block is for backwards-compatibility. 54 // We used to support passing a `Tx` in req. But if we do that, sig 55 // verification might not pass, because the .Marshal() below might not 56 // be the same marshaling done by the client. 57 var err error 58 txBytes, err = proto.Marshal(req.Tx) 59 if err != nil { 60 return nil, status.Errorf(codes.InvalidArgument, "invalid tx; %v", err) 61 } 62 } 63 64 if txBytes == nil { 65 return nil, status.Errorf(codes.InvalidArgument, "empty txBytes is not allowed") 66 } 67 68 gasInfo, res, err := t.simulate(txBytes) 69 if err != nil { 70 return nil, err 71 } 72 73 return &tx.SimulateResponse{ 74 GasInfo: &typeadapter.GasInfo{ 75 GasWanted: gasInfo.GasWanted, 76 GasUsed: gasInfo.GasUsed, 77 }, 78 Result: ConvCM39SimulateResultTCM40(res), 79 }, nil 80 } 81 82 func (t txServer) GetTx(ctx context.Context, req *tx.GetTxRequest) (*tx.GetTxResponse, error) { 83 if req == nil { 84 return nil, status.Error(codes.InvalidArgument, "request cannot be nil") 85 } 86 87 if len(req.Hash) == 0 { 88 return nil, status.Error(codes.InvalidArgument, "tx hash cannot be empty") 89 } 90 91 result, err := Query40Tx(t.clientCtx, req.Hash) 92 if nil != err { 93 return nil, err 94 } 95 96 protoTx, ok := result.Tx.GetCachedValue().(*tx.Tx) 97 if !ok { 98 return nil, status.Errorf(codes.Internal, "expected %T, got %T", tx.Tx{}, result.Tx.GetCachedValue()) 99 } 100 101 return &tx.GetTxResponse{ 102 Tx: protoTx, 103 TxResponse: result, 104 }, nil 105 } 106 107 func (t txServer) BroadcastTx(ctx context.Context, request *tx.BroadcastTxRequest) (*tx.BroadcastTxResponse, error) { 108 resp, err := cliContext.TxServiceBroadcast(ctx, t.clientCtx, request) 109 if nil != err { 110 return nil, err 111 } 112 ret := new(tx.BroadcastTxResponse) 113 ret.HandleResponse(t.clientCtx.CodecProy, resp) 114 return ret, nil 115 } 116 117 func (t txServer) GetTxsEvent(ctx context.Context, req *tx.GetTxsEventRequest) (*tx.GetTxsEventResponse, error) { 118 if req == nil { 119 return nil, status.Error(codes.InvalidArgument, "request cannot be nil") 120 } 121 122 page := 1 123 // Tendermint node.TxSearch that is used for querying txs defines pages starting from 1, 124 // so we default to 1 if not provided in the request. 125 limit := query.DefaultLimit 126 127 if len(req.Events) == 0 { 128 return nil, status.Error(codes.InvalidArgument, "must declare at least one event to search") 129 } 130 131 for _, event := range req.Events { 132 if !strings.Contains(event, "=") || strings.Count(event, "=") > 1 { 133 return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid event; event %s should be of the format: %s", event, eventFormat)) 134 } 135 } 136 137 result, err := Query40TxsByEvents(t.clientCtx, req.Events, page, limit) 138 if err != nil { 139 return nil, err 140 } 141 142 // Create a proto codec, we need it to unmarshal the tx bytes. 143 txsList := make([]*tx.Tx, len(result.Txs)) 144 145 for i, txx := range result.Txs { 146 protoTx, ok := txx.Tx.GetCachedValue().(*tx.Tx) 147 if !ok { 148 return nil, status.Errorf(codes.Internal, "expected %T, got %T", tx.Tx{}, txx.Tx.GetCachedValue()) 149 } 150 151 txsList[i] = protoTx 152 } 153 154 return &tx.GetTxsEventResponse{ 155 Txs: txsList, 156 TxResponses: result.Txs, 157 }, nil 158 } 159 160 // RegisterTxService registers the tx service on the gRPC router. 161 func RegisterTxService( 162 qrt gogogrpc.Server, 163 clientCtx cliContext.CLIContext, 164 simulateFn baseAppSimulateFn, 165 interfaceRegistry codectypes.InterfaceRegistry, 166 ) { 167 tx.RegisterServiceServer( 168 qrt, 169 NewTxServer(clientCtx, simulateFn, interfaceRegistry), 170 ) 171 }