feat: Add tx encode and decode endpoints for amino txs (#13882)
* add proto changes * make proto-gen * wip: adds tests * wip: tests * remove consoles * wip: fix something * fix: encode amino tests * add decode amino tests * wip: address requested changes * update proto inline docs * address review comments Co-authored-by: Amaury M <1293565+amaurym@users.noreply.github.com> Co-authored-by: Julien Robert <julien@rbrt.fr> Co-authored-by: atheeshp <59333759+atheeshp@users.noreply.github.com>
This commit is contained in:
parent
00ad3ecedc
commit
e260fc1c89
@ -58,10 +58,13 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
### Improvements
|
||||
|
||||
* [13882] (https://github.com/cosmos/cosmos-sdk/pull/13882) Add tx `encode` and `decode` endpoints to amino tx service.
|
||||
> Note: These endpoints encodes and decodes only amino txs.
|
||||
* (config) [#13894](https://github.com/cosmos/cosmos-sdk/pull/13894) Support state streaming configuration in `app.toml` template and default configuration.
|
||||
* (x/nft) [#13836](https://github.com/cosmos/cosmos-sdk/pull/13836) Remove the validation for `classID` and `nftID` from the NFT module.
|
||||
* [#13789](https://github.com/cosmos/cosmos-sdk/pull/13789) Add tx `encode` and `decode` endpoints to tx service.
|
||||
> Note: This endpoint will only encode proto messages, Amino encoding is not supported.
|
||||
> Note: These endpoints will only encode and decode proto messages, Amino encoding and decoding is not supported.
|
||||
* [#13826](https://github.com/cosmos/cosmos-sdk/pull/13826) Support custom `GasConfig` configuration for applications.
|
||||
* [#13619](https://github.com/cosmos/cosmos-sdk/pull/13619) Add new function called LogDeferred to report errors in defers. Use the function in x/bank files.
|
||||
* (tools) [#13603](https://github.com/cosmos/cosmos-sdk/pull/13603) Rename cosmovisor package name to `cosmossdk.io/tools/cosmovisor`. The new tool directory contains Cosmos SDK tools.
|
||||
* (deps) [#13397](https://github.com/cosmos/cosmos-sdk/pull/13397) Bump Go version minimum requirement to `1.19`.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -42,6 +42,14 @@ type ServiceClient interface {
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
TxEncode(ctx context.Context, in *TxEncodeRequest, opts ...grpc.CallOption) (*TxEncodeResponse, error)
|
||||
// TxEncodeAmino encodes an amino transaction.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
TxEncodeAmino(ctx context.Context, in *TxEncodeAminoRequest, opts ...grpc.CallOption) (*TxEncodeAminoResponse, error)
|
||||
// TxDecodeAmino decodes an amino transaction.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
TxDecodeAmino(ctx context.Context, in *TxDecodeAminoRequest, opts ...grpc.CallOption) (*TxDecodeAminoResponse, error)
|
||||
}
|
||||
|
||||
type serviceClient struct {
|
||||
@ -115,6 +123,24 @@ func (c *serviceClient) TxEncode(ctx context.Context, in *TxEncodeRequest, opts
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *serviceClient) TxEncodeAmino(ctx context.Context, in *TxEncodeAminoRequest, opts ...grpc.CallOption) (*TxEncodeAminoResponse, error) {
|
||||
out := new(TxEncodeAminoResponse)
|
||||
err := c.cc.Invoke(ctx, "/cosmos.tx.v1beta1.Service/TxEncodeAmino", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *serviceClient) TxDecodeAmino(ctx context.Context, in *TxDecodeAminoRequest, opts ...grpc.CallOption) (*TxDecodeAminoResponse, error) {
|
||||
out := new(TxDecodeAminoResponse)
|
||||
err := c.cc.Invoke(ctx, "/cosmos.tx.v1beta1.Service/TxDecodeAmino", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ServiceServer is the server API for Service service.
|
||||
// All implementations must embed UnimplementedServiceServer
|
||||
// for forward compatibility
|
||||
@ -139,6 +165,14 @@ type ServiceServer interface {
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
TxEncode(context.Context, *TxEncodeRequest) (*TxEncodeResponse, error)
|
||||
// TxEncodeAmino encodes an amino transaction.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
TxEncodeAmino(context.Context, *TxEncodeAminoRequest) (*TxEncodeAminoResponse, error)
|
||||
// TxDecodeAmino decodes an amino transaction.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
TxDecodeAmino(context.Context, *TxDecodeAminoRequest) (*TxDecodeAminoResponse, error)
|
||||
mustEmbedUnimplementedServiceServer()
|
||||
}
|
||||
|
||||
@ -167,6 +201,12 @@ func (UnimplementedServiceServer) TxDecode(context.Context, *TxDecodeRequest) (*
|
||||
func (UnimplementedServiceServer) TxEncode(context.Context, *TxEncodeRequest) (*TxEncodeResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method TxEncode not implemented")
|
||||
}
|
||||
func (UnimplementedServiceServer) TxEncodeAmino(context.Context, *TxEncodeAminoRequest) (*TxEncodeAminoResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method TxEncodeAmino not implemented")
|
||||
}
|
||||
func (UnimplementedServiceServer) TxDecodeAmino(context.Context, *TxDecodeAminoRequest) (*TxDecodeAminoResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method TxDecodeAmino not implemented")
|
||||
}
|
||||
func (UnimplementedServiceServer) mustEmbedUnimplementedServiceServer() {}
|
||||
|
||||
// UnsafeServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
@ -306,6 +346,42 @@ func _Service_TxEncode_Handler(srv interface{}, ctx context.Context, dec func(in
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Service_TxEncodeAmino_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(TxEncodeAminoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServiceServer).TxEncodeAmino(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/cosmos.tx.v1beta1.Service/TxEncodeAmino",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServiceServer).TxEncodeAmino(ctx, req.(*TxEncodeAminoRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Service_TxDecodeAmino_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(TxDecodeAminoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServiceServer).TxDecodeAmino(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/cosmos.tx.v1beta1.Service/TxDecodeAmino",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServiceServer).TxDecodeAmino(ctx, req.(*TxDecodeAminoRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Service_ServiceDesc is the grpc.ServiceDesc for Service service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@ -341,6 +417,14 @@ var Service_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "TxEncode",
|
||||
Handler: _Service_TxEncode_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "TxEncodeAmino",
|
||||
Handler: _Service_TxEncodeAmino_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "TxDecodeAmino",
|
||||
Handler: _Service_TxDecodeAmino_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "cosmos/tx/v1beta1/service.proto",
|
||||
|
||||
@ -58,6 +58,24 @@ service Service {
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
// TxEncodeAmino encodes an Amino transaction from JSON to encoded bytes.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
rpc TxEncodeAmino(TxEncodeAminoRequest) returns (TxEncodeAminoResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/cosmos/tx/v1beta1/encode/amino"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
// TxDecodeAmino decodes an Amino transaction from encoded bytes to JSON.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
rpc TxDecodeAmino(TxDecodeAminoRequest) returns (TxDecodeAminoResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/cosmos/tx/v1beta1/decode/amino"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// GetTxsEventRequest is the request type for the Service.TxsByEvents
|
||||
@ -208,7 +226,7 @@ message TxDecodeResponse {
|
||||
cosmos.tx.v1beta1.Tx tx = 1;
|
||||
}
|
||||
|
||||
// TxEncodeResponse is the request type for the Service.TxEncode
|
||||
// TxEncodeRequest is the request type for the Service.TxEncode
|
||||
// RPC method.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
@ -225,3 +243,35 @@ message TxEncodeResponse {
|
||||
// tx_bytes is the encoded transaction bytes.
|
||||
bytes tx_bytes = 1;
|
||||
}
|
||||
|
||||
// TxEncodeAminoRequest is the request type for the Service.TxEncodeAmino
|
||||
// RPC method.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
message TxEncodeAminoRequest {
|
||||
string amino_json = 1;
|
||||
}
|
||||
|
||||
// TxEncodeAminoResponse is the response type for the Service.TxEncodeAmino
|
||||
// RPC method.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
message TxEncodeAminoResponse {
|
||||
bytes amino_binary = 1;
|
||||
}
|
||||
|
||||
// TxDecodeAminoRequest is the request type for the Service.TxDecodeAmino
|
||||
// RPC method.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
message TxDecodeAminoRequest {
|
||||
bytes amino_binary = 1;
|
||||
}
|
||||
|
||||
// TxDecodeAminoResponse is the response type for the Service.TxDecodeAmino
|
||||
// RPC method.
|
||||
//
|
||||
// Since: cosmos-sdk 0.47
|
||||
message TxDecodeAminoResponse {
|
||||
string amino_json = 1;
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
|
||||
authtest "github.com/cosmos/cosmos-sdk/x/auth/client/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
)
|
||||
@ -772,6 +773,7 @@ func (s IntegrationTestSuite) TestGetBlockWithTxs_GRPCGateway() {
|
||||
}
|
||||
|
||||
func (s IntegrationTestSuite) TestTxEncode_GRPC() {
|
||||
val := s.network.Validators[0]
|
||||
txBuilder := s.mkTxBuilder()
|
||||
protoTx, err := txBuilderToProtoTx(txBuilder)
|
||||
s.Require().NoError(err)
|
||||
@ -784,7 +786,7 @@ func (s IntegrationTestSuite) TestTxEncode_GRPC() {
|
||||
}{
|
||||
{"nil request", nil, true, "request cannot be nil"},
|
||||
{"empty request", &tx.TxEncodeRequest{}, true, "invalid empty tx"},
|
||||
{"valid request with tx bytes", &tx.TxEncodeRequest{Tx: protoTx}, false, ""},
|
||||
{"valid tx request", &tx.TxEncodeRequest{Tx: protoTx}, false, ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -798,6 +800,10 @@ func (s IntegrationTestSuite) TestTxEncode_GRPC() {
|
||||
} else {
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEmpty(res.GetTxBytes())
|
||||
|
||||
tx, err := val.ClientCtx.TxConfig.TxDecoder()(res.TxBytes)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(protoTx.GetMsgs(), tx.GetMsgs())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -816,7 +822,7 @@ func (s *IntegrationTestSuite) TestTxEncode_GRPCGateway() {
|
||||
expErrMsg string
|
||||
}{
|
||||
{"empty request", &tx.TxEncodeRequest{}, true, "invalid empty tx"},
|
||||
{"valid request with tx bytes", &tx.TxEncodeRequest{Tx: protoTx}, false, ""},
|
||||
{"valid tx request", &tx.TxEncodeRequest{Tx: protoTx}, false, ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -829,7 +835,13 @@ func (s *IntegrationTestSuite) TestTxEncode_GRPCGateway() {
|
||||
if tc.expErr {
|
||||
s.Require().Contains(string(res), tc.expErrMsg)
|
||||
} else {
|
||||
var result tx.TxEncodeResponse
|
||||
err := val.ClientCtx.Codec.UnmarshalJSON(res, &result)
|
||||
s.Require().NoError(err)
|
||||
|
||||
tx, err := val.ClientCtx.TxConfig.TxDecoder()(result.TxBytes)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(protoTx.GetMsgs(), tx.GetMsgs())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -867,6 +879,11 @@ func (s IntegrationTestSuite) TestTxDecode_GRPC() {
|
||||
} else {
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEmpty(res.GetTx())
|
||||
|
||||
txb := authtx.WrapTx(res.Tx)
|
||||
tx, err := val.ClientCtx.TxConfig.TxEncoder()(txb.GetTx())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(encodedTx, tx)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -876,10 +893,10 @@ func (s IntegrationTestSuite) TestTxDecode_GRPCGateway() {
|
||||
val := s.network.Validators[0]
|
||||
txBuilder := s.mkTxBuilder()
|
||||
|
||||
txBytes, err := val.ClientCtx.TxConfig.TxEncoder()(txBuilder.GetTx())
|
||||
encodedTxBytes, err := val.ClientCtx.TxConfig.TxEncoder()(txBuilder.GetTx())
|
||||
s.Require().NoError(err)
|
||||
|
||||
invalidTxBytes := append(txBytes, byte(0o00))
|
||||
invalidTxBytes := append(encodedTxBytes, byte(0o00))
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
@ -889,7 +906,7 @@ func (s IntegrationTestSuite) TestTxDecode_GRPCGateway() {
|
||||
}{
|
||||
{"empty request", &tx.TxDecodeRequest{}, true, "invalid empty tx bytes"},
|
||||
{"invalid tx bytes", &tx.TxDecodeRequest{TxBytes: invalidTxBytes}, true, "tx parse error"},
|
||||
{"valid request with tx_bytes", &tx.TxDecodeRequest{TxBytes: txBytes}, false, ""},
|
||||
{"valid request with tx_bytes", &tx.TxDecodeRequest{TxBytes: encodedTxBytes}, false, ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@ -902,7 +919,187 @@ func (s IntegrationTestSuite) TestTxDecode_GRPCGateway() {
|
||||
if tc.expErr {
|
||||
s.Require().Contains(string(res), tc.expErrMsg)
|
||||
} else {
|
||||
var result tx.TxDecodeResponse
|
||||
err := val.ClientCtx.Codec.UnmarshalJSON(res, &result)
|
||||
s.Require().NoError(err)
|
||||
|
||||
txb := authtx.WrapTx(result.Tx)
|
||||
tx, err := val.ClientCtx.TxConfig.TxEncoder()(txb.GetTx())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(encodedTxBytes, tx)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s IntegrationTestSuite) TestTxEncodeAmino_GRPC() {
|
||||
val := s.network.Validators[0]
|
||||
txBuilder := s.mkTxBuilder()
|
||||
stdTx, err := clienttx.ConvertTxToStdTx(val.ClientCtx.LegacyAmino, txBuilder.GetTx())
|
||||
s.Require().NoError(err)
|
||||
txJSONBytes, err := val.ClientCtx.LegacyAmino.MarshalJSON(stdTx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *tx.TxEncodeAminoRequest
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"nil request", nil, true, "request cannot be nil"},
|
||||
{"empty request", &tx.TxEncodeAminoRequest{}, true, "invalid empty tx json"},
|
||||
{"invalid request", &tx.TxEncodeAminoRequest{AminoJson: "invalid tx json"}, true, "invalid request"},
|
||||
{"valid request with amino-json", &tx.TxEncodeAminoRequest{AminoJson: string(txJSONBytes)}, false, ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
s.Run(tc.name, func() {
|
||||
res, err := s.queryClient.TxEncodeAmino(context.Background(), tc.req)
|
||||
if tc.expErr {
|
||||
s.Require().Error(err)
|
||||
s.Require().Contains(err.Error(), tc.expErrMsg)
|
||||
s.Require().Empty(res)
|
||||
} else {
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEmpty(res.GetAminoBinary())
|
||||
|
||||
var tx legacytx.StdTx
|
||||
stdTxConfig := legacytx.StdTxConfig{Cdc: val.ClientCtx.LegacyAmino}
|
||||
stdTxConfig.Cdc.Unmarshal(res.AminoBinary, &tx)
|
||||
s.Require().Equal(tx.GetMsgs(), stdTx.GetMsgs())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TestTxEncodeAmino_GRPCGateway() {
|
||||
val := s.network.Validators[0]
|
||||
txBuilder := s.mkTxBuilder()
|
||||
stdTx, err := clienttx.ConvertTxToStdTx(val.ClientCtx.LegacyAmino, txBuilder.GetTx())
|
||||
s.Require().NoError(err)
|
||||
txJSONBytes, err := val.ClientCtx.LegacyAmino.MarshalJSON(stdTx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *tx.TxEncodeAminoRequest
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"empty request", &tx.TxEncodeAminoRequest{}, true, "invalid empty tx json"},
|
||||
{"invalid request", &tx.TxEncodeAminoRequest{AminoJson: "invalid tx json"}, true, "invalid request"},
|
||||
{"valid request with amino-json", &tx.TxEncodeAminoRequest{AminoJson: string(txJSONBytes)}, false, ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
req, err := val.ClientCtx.Codec.MarshalJSON(tc.req)
|
||||
s.Require().NoError(err)
|
||||
|
||||
res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/encode/amino", val.APIAddress), "application/json", req)
|
||||
s.Require().NoError(err)
|
||||
if tc.expErr {
|
||||
s.Require().Contains(string(res), tc.expErrMsg)
|
||||
} else {
|
||||
var result tx.TxEncodeAminoResponse
|
||||
err := val.ClientCtx.Codec.UnmarshalJSON(res, &result)
|
||||
s.Require().NoError(err)
|
||||
|
||||
var newStdTx legacytx.StdTx
|
||||
stdTxConfig := legacytx.StdTxConfig{Cdc: val.ClientCtx.LegacyAmino}
|
||||
stdTxConfig.Cdc.Unmarshal(result.AminoBinary, &newStdTx)
|
||||
s.Require().Equal(newStdTx.GetMsgs(), stdTx.GetMsgs())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s IntegrationTestSuite) TestTxDecodeAmino_GRPC() {
|
||||
val := s.network.Validators[0]
|
||||
txBuilder := s.mkTxBuilder()
|
||||
|
||||
stdTx, err := clienttx.ConvertTxToStdTx(val.ClientCtx.LegacyAmino, txBuilder.GetTx())
|
||||
s.Require().NoError(err)
|
||||
stdTxConfig := legacytx.StdTxConfig{Cdc: val.ClientCtx.LegacyAmino}
|
||||
encodedTx, err := stdTxConfig.Cdc.Marshal(stdTx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
invalidTxBytes := append(encodedTx, byte(0o00))
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *tx.TxDecodeAminoRequest
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"nil request", nil, true, "request cannot be nil"},
|
||||
{"empty request", &tx.TxDecodeAminoRequest{}, true, "invalid empty tx bytes"},
|
||||
{"invalid tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: invalidTxBytes}, true, "invalid request"},
|
||||
{"valid request with tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: encodedTx}, false, ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
s.Run(tc.name, func() {
|
||||
res, err := s.queryClient.TxDecodeAmino(context.Background(), tc.req)
|
||||
if tc.expErr {
|
||||
s.Require().Error(err)
|
||||
s.Require().Contains(err.Error(), tc.expErrMsg)
|
||||
s.Require().Empty(res)
|
||||
} else {
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotEmpty(res.GetAminoJson())
|
||||
|
||||
var tx legacytx.StdTx
|
||||
err := stdTxConfig.Cdc.UnmarshalJSON([]byte(res.GetAminoJson()), &tx)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(stdTx.GetMsgs(), tx.GetMsgs())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s IntegrationTestSuite) TestTxDecodeAmino_GRPCGateway() {
|
||||
val := s.network.Validators[0]
|
||||
txBuilder := s.mkTxBuilder()
|
||||
|
||||
stdTx, err := clienttx.ConvertTxToStdTx(val.ClientCtx.LegacyAmino, txBuilder.GetTx())
|
||||
s.Require().NoError(err)
|
||||
stdTxConfig := legacytx.StdTxConfig{Cdc: val.ClientCtx.LegacyAmino}
|
||||
encodedTx, err := stdTxConfig.Cdc.Marshal(stdTx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
invalidTxBytes := append(encodedTx, byte(0o00))
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *tx.TxDecodeAminoRequest
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"empty request", &tx.TxDecodeAminoRequest{}, true, "invalid empty tx bytes"},
|
||||
{"invalid tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: invalidTxBytes}, true, "invalid request"},
|
||||
{"valid request with tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: encodedTx}, false, ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
req, err := val.ClientCtx.Codec.MarshalJSON(tc.req)
|
||||
s.Require().NoError(err)
|
||||
|
||||
res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/decode/amino", val.APIAddress), "application/json", req)
|
||||
s.Require().NoError(err)
|
||||
if tc.expErr {
|
||||
s.Require().Contains(string(res), tc.expErrMsg)
|
||||
} else {
|
||||
var result tx.TxDecodeAminoResponse
|
||||
err := val.ClientCtx.Codec.UnmarshalJSON(res, &result)
|
||||
s.Require().NoError(err)
|
||||
|
||||
var newStdTx legacytx.StdTx
|
||||
stdTxConfig.Cdc.UnmarshalJSON([]byte(result.AminoJson), &newStdTx)
|
||||
s.Require().Equal(newStdTx.GetMsgs(), stdTx.GetMsgs())
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -930,6 +1127,7 @@ func (s IntegrationTestSuite) mkTxBuilder() client.TxBuilder {
|
||||
txBuilder.SetFeeAmount(feeAmount)
|
||||
txBuilder.SetGasLimit(gasLimit)
|
||||
txBuilder.SetMemo("foobar")
|
||||
s.Require().Equal([]sdk.AccAddress{val.Address}, txBuilder.GetTx().GetSigners())
|
||||
|
||||
// setup txFactory
|
||||
txFactory := clienttx.Factory{}.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -331,6 +331,74 @@ func local_request_Service_TxEncode_0(ctx context.Context, marshaler runtime.Mar
|
||||
|
||||
}
|
||||
|
||||
func request_Service_TxEncodeAmino_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq TxEncodeAminoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.TxEncodeAmino(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_TxEncodeAmino_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq TxEncodeAminoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.TxEncodeAmino(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_Service_TxDecodeAmino_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq TxDecodeAminoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.TxDecodeAmino(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_TxDecodeAmino_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq TxDecodeAminoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.TxDecodeAmino(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterServiceHandlerServer registers the http handlers for service Service to "mux".
|
||||
// UnaryRPC :call ServiceServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
@ -498,6 +566,52 @@ func RegisterServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, se
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Service_TxEncodeAmino_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Service_TxEncodeAmino_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_TxEncodeAmino_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Service_TxDecodeAmino_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Service_TxDecodeAmino_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_TxDecodeAmino_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -679,6 +793,46 @@ func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Service_TxEncodeAmino_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Service_TxEncodeAmino_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_TxEncodeAmino_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Service_TxDecodeAmino_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Service_TxDecodeAmino_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_TxDecodeAmino_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -696,6 +850,10 @@ var (
|
||||
pattern_Service_TxDecode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "tx", "v1beta1", "decode"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Service_TxEncode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "tx", "v1beta1", "encode"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Service_TxEncodeAmino_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "tx", "v1beta1", "encode", "amino"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
|
||||
pattern_Service_TxDecodeAmino_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "tx", "v1beta1", "decode", "amino"}, "", runtime.AssumeColonVerbOpt(false)))
|
||||
)
|
||||
|
||||
var (
|
||||
@ -712,4 +870,8 @@ var (
|
||||
forward_Service_TxDecode_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_TxEncode_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_TxEncodeAmino_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_TxDecodeAmino_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
|
||||
@ -19,6 +19,7 @@ import (
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/types/query"
|
||||
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
|
||||
)
|
||||
|
||||
// baseAppSimulateFn is the signature of the Baseapp#Simulate function.
|
||||
@ -271,6 +272,28 @@ func (s txServer) TxEncode(ctx context.Context, req *txtypes.TxEncodeRequest) (*
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TxEncodeAmino implements the ServiceServer.TxEncodeAmino RPC method.
|
||||
func (s txServer) TxEncodeAmino(ctx context.Context, req *txtypes.TxEncodeAminoRequest) (*txtypes.TxEncodeAminoResponse, error) {
|
||||
if req.AminoJson == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid empty tx json")
|
||||
}
|
||||
|
||||
var stdTx legacytx.StdTx
|
||||
err := s.clientCtx.LegacyAmino.UnmarshalJSON([]byte(req.AminoJson), &stdTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encodedBytes, err := s.clientCtx.LegacyAmino.Marshal(stdTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &txtypes.TxEncodeAminoResponse{
|
||||
AminoBinary: encodedBytes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TxDecode implements the ServiceServer.TxDecode RPC method.
|
||||
func (s txServer) TxDecode(ctx context.Context, req *txtypes.TxDecodeRequest) (*txtypes.TxDecodeResponse, error) {
|
||||
if req.TxBytes == nil {
|
||||
@ -292,6 +315,28 @@ func (s txServer) TxDecode(ctx context.Context, req *txtypes.TxDecodeRequest) (*
|
||||
return nil, fmt.Errorf("expected %T, got %T", &wrapper{}, txb)
|
||||
}
|
||||
|
||||
// TxDecodeAmino implements the ServiceServer.TxDecodeAmino RPC method.
|
||||
func (s txServer) TxDecodeAmino(ctx context.Context, req *txtypes.TxDecodeAminoRequest) (*txtypes.TxDecodeAminoResponse, error) {
|
||||
if req.AminoBinary == nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "invalid empty tx bytes")
|
||||
}
|
||||
|
||||
var stdTx legacytx.StdTx
|
||||
err := s.clientCtx.LegacyAmino.Unmarshal(req.AminoBinary, &stdTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := s.clientCtx.LegacyAmino.MarshalJSON(stdTx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &txtypes.TxDecodeAminoResponse{
|
||||
AminoJson: string(res),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RegisterTxService registers the tx service on the gRPC router.
|
||||
func RegisterTxService(
|
||||
qrt gogogrpc.Server,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user