@@ -24,100 +24,109 @@ var _ gogogrpc.ClientConn = Context{}
2424var protoCodec = encoding .GetCodec (proto .Name )
2525
2626// Invoke implements the grpc ClientConn.Invoke method
27- func (ctx Context ) Invoke (grpcCtx gocontext.Context , method string , args , reply interface {}, opts ... grpc.CallOption ) (err error ) {
27+ func (ctx Context ) Invoke (grpcCtx gocontext.Context , method string , req , reply interface {}, opts ... grpc.CallOption ) (err error ) {
2828 // Two things can happen here:
2929 // 1. either we're broadcasting a Tx, in which call we call Tendermint's broadcast endpoint directly,
3030 // 2. or we are querying for state, in which case we call ABCI's Query.
3131
32- // In both cases, we don't allow empty request args (it will panic unexpectedly).
33- if reflect .ValueOf (args ).IsNil () {
32+ // In both cases, we don't allow empty request req (it will panic unexpectedly).
33+ if reflect .ValueOf (req ).IsNil () {
3434 return sdkerrors .Wrap (sdkerrors .ErrInvalidRequest , "request cannot be nil" )
3535 }
3636
3737 // Case 1. Broadcasting a Tx.
38- if isBroadcast (method ) {
39- req , ok := args .(* tx.BroadcastTxRequest )
38+ if reqProto , ok := req .(* tx.BroadcastTxRequest ); ok {
4039 if ! ok {
41- return sdkerrors .Wrapf (sdkerrors .ErrInvalidRequest , "expected %T, got %T" , (* tx .BroadcastTxRequest )(nil ), args )
40+ return sdkerrors .Wrapf (sdkerrors .ErrInvalidRequest , "expected %T, got %T" , (* tx .BroadcastTxRequest )(nil ), req )
4241 }
43- res , ok := reply .(* tx.BroadcastTxResponse )
42+ resProto , ok := reply .(* tx.BroadcastTxResponse )
4443 if ! ok {
45- return sdkerrors .Wrapf (sdkerrors .ErrInvalidRequest , "expected %T, got %T" , (* tx .BroadcastTxResponse )(nil ), args )
44+ return sdkerrors .Wrapf (sdkerrors .ErrInvalidRequest , "expected %T, got %T" , (* tx .BroadcastTxResponse )(nil ), req )
4645 }
4746
48- broadcastRes , err := TxServiceBroadcast (grpcCtx , ctx , req )
47+ broadcastRes , err := TxServiceBroadcast (grpcCtx , ctx , reqProto )
4948 if err != nil {
5049 return err
5150 }
52- * res = * broadcastRes
51+ * resProto = * broadcastRes
5352
5453 return err
5554 }
5655
5756 // Case 2. Querying state.
58- reqBz , err := protoCodec .Marshal (args )
57+ inMd , _ := metadata .FromOutgoingContext (grpcCtx )
58+ abciRes , outMd , err := RunGRPCQuery (ctx , grpcCtx , method , req , inMd )
5959 if err != nil {
6060 return err
6161 }
6262
63+ err = protoCodec .Unmarshal (abciRes .Value , reply )
64+ if err != nil {
65+ return err
66+ }
67+
68+ for _ , callOpt := range opts {
69+ header , ok := callOpt .(grpc.HeaderCallOption )
70+ if ! ok {
71+ continue
72+ }
73+
74+ * header .HeaderAddr = outMd
75+ }
76+
77+ if ctx .InterfaceRegistry != nil {
78+ return types .UnpackInterfaces (reply , ctx .InterfaceRegistry )
79+ }
80+
81+ return nil
82+ }
83+
84+ // NewStream implements the grpc ClientConn.NewStream method
85+ func (Context ) NewStream (gocontext.Context , * grpc.StreamDesc , string , ... grpc.CallOption ) (grpc.ClientStream , error ) {
86+ return nil , fmt .Errorf ("streaming rpc not supported" )
87+ }
88+
89+ // RunGRPCQuery runs a gRPC query from the clientCtx, given all necessary
90+ // arguments for the gRPC method, and returns the ABCI response. It is used
91+ // to factorize code between client (Invoke) and server (RegisterGRPCServer)
92+ // gRPC handlers.
93+ func RunGRPCQuery (ctx Context , grpcCtx gocontext.Context , method string , req interface {}, md metadata.MD ) (abci.ResponseQuery , metadata.MD , error ) {
94+ reqBz , err := protoCodec .Marshal (req )
95+ if err != nil {
96+ return abci.ResponseQuery {}, nil , err
97+ }
98+
6399 // parse height header
64- md , _ := metadata .FromOutgoingContext (grpcCtx )
65100 if heights := md .Get (grpctypes .GRPCBlockHeightHeader ); len (heights ) > 0 {
66101 height , err := strconv .ParseInt (heights [0 ], 10 , 64 )
67102 if err != nil {
68- return err
103+ return abci. ResponseQuery {}, nil , err
69104 }
70105 if height < 0 {
71- return sdkerrors .Wrapf (
106+ return abci. ResponseQuery {}, nil , sdkerrors .Wrapf (
72107 sdkerrors .ErrInvalidRequest ,
73108 "client.Context.Invoke: height (%d) from %q must be >= 0" , height , grpctypes .GRPCBlockHeightHeader )
74109 }
75110
76111 ctx = ctx .WithHeight (height )
77112 }
78113
79- req := abci.RequestQuery {
114+ abciReq := abci.RequestQuery {
80115 Path : method ,
81116 Data : reqBz ,
82117 }
83118
84- res , err := ctx .QueryABCI (req )
119+ abciRes , err := ctx .QueryABCI (abciReq )
85120 if err != nil {
86- return err
87- }
88-
89- err = protoCodec .Unmarshal (res .Value , reply )
90- if err != nil {
91- return err
121+ return abci.ResponseQuery {}, nil , err
92122 }
93123
94124 // Create header metadata. For now the headers contain:
95125 // - block height
96126 // We then parse all the call options, if the call option is a
97127 // HeaderCallOption, then we manually set the value of that header to the
98128 // metadata.
99- md = metadata .Pairs (grpctypes .GRPCBlockHeightHeader , strconv .FormatInt (res .Height , 10 ))
100- for _ , callOpt := range opts {
101- header , ok := callOpt .(grpc.HeaderCallOption )
102- if ! ok {
103- continue
104- }
105-
106- * header .HeaderAddr = md
107- }
108-
109- if ctx .InterfaceRegistry != nil {
110- return types .UnpackInterfaces (reply , ctx .InterfaceRegistry )
111- }
112-
113- return nil
114- }
115-
116- // NewStream implements the grpc ClientConn.NewStream method
117- func (Context ) NewStream (gocontext.Context , * grpc.StreamDesc , string , ... grpc.CallOption ) (grpc.ClientStream , error ) {
118- return nil , fmt .Errorf ("streaming rpc not supported" )
119- }
129+ md = metadata .Pairs (grpctypes .GRPCBlockHeightHeader , strconv .FormatInt (abciRes .Height , 10 ))
120130
121- func isBroadcast (method string ) bool {
122- return method == "/cosmos.tx.v1beta1.Service/BroadcastTx"
131+ return abciRes , md , nil
123132}
0 commit comments