Add GetTx gRPC endpoint (#7688)

* Add empty TxByHash

* Fix search & replace

* Renname to GetTx

* Make getTx grpc work

* Hash as string

* Add todo comment

* /tx

* Make tests pass

* Put into function

* Add changelog

* Fix lint

* RegisterTxService in server

* Remove comment

* Update proto/cosmos/tx/v1beta1/service.proto

Co-authored-by: Cory <cjlevinson@gmail.com>

* Create new protoCdc

* Move tx service to x/auth

* Small tweaks

* Link gh issue

* Fix lint

* Update x/auth/tx/service.go

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

Co-authored-by: Cory <cjlevinson@gmail.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: SaReN <sahithnarahari@gmail.com>
This commit is contained in:
Amaury Martiny 2020-10-30 13:32:02 +01:00 committed by GitHub
parent b2bc32f3c9
commit 1961935fc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1710 additions and 1078 deletions

View File

@ -51,11 +51,13 @@ Ref: https://keepachangelog.com/en/1.0.0/
* `Validator.ConsensusPubkey` type changed from `string` to `codectypes.Any`.
* `MsgCreateValidator.Pubkey` type changed from `string` to `codectypes.Any`.
* Deprecating and renaming `MakeEncodingConfig` to `MakeTestEncodingConfig` (both in `simapp` and `simapp/params` packages).
* (tx) [\#7688](https://github.com/cosmos/cosmos-sdk/pull/7688) The gRPC simulate service method has been moved from `cosmos.base.v1beta1.simulate` to `cosmos.tx.v1beta1`, as a method in the Tx service.
### Features
* (codec) [\#7519](https://github.com/cosmos/cosmos-sdk/pull/7519) `InterfaceRegistry` now inherits `jsonpb.AnyResolver`, and has a `RegisterCustomTypeURL` method to support ADR 031 packing of `Any`s. `AnyResolver` is now a required parameter to `RejectUnknownFields`.
* (baseapp) [\#7519](https://github.com/cosmos/cosmos-sdk/pull/7519) Add `ServiceMsgRouter` to BaseApp to handle routing of protobuf service `Msg`s. The two new types defined in ADR 031, `sdk.ServiceMsg` and `sdk.MsgRequest` are introduced with this router.
* (tx) [\#7688](https://github.com/cosmos/cosmos-sdk/pull/7688) Add a new Tx gRPC service with methods `Simulate` and `GetTx` (by hash).
### Bug Fixes

View File

@ -10,7 +10,6 @@ import (
"google.golang.org/grpc/encoding/proto"
"github.com/cosmos/cosmos-sdk/client/grpc/reflection"
"github.com/cosmos/cosmos-sdk/client/grpc/simulate"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -128,14 +127,3 @@ func (qrt *GRPCQueryRouter) SetInterfaceRegistry(interfaceRegistry codectypes.In
reflection.NewReflectionServiceServer(interfaceRegistry),
)
}
// RegisterSimulateService registers the simulate service on the gRPC router.
func (qrt *GRPCQueryRouter) RegisterSimulateService(
simulateFn simulate.BaseAppSimulateFn,
interfaceRegistry codectypes.InterfaceRegistry,
) {
simulate.RegisterSimulateServiceServer(
qrt,
simulate.NewSimulateServer(simulateFn, interfaceRegistry),
)
}

View File

@ -1,55 +0,0 @@
package simulate
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// BaseAppSimulateFn is the signature of the Baseapp#Simulate function.
type BaseAppSimulateFn func(txBytes []byte) (sdk.GasInfo, *sdk.Result, error)
type simulateServer struct {
simulate BaseAppSimulateFn
interfaceRegistry codectypes.InterfaceRegistry
}
// NewSimulateServer creates a new SimulateServer.
func NewSimulateServer(simulate BaseAppSimulateFn, interfaceRegistry codectypes.InterfaceRegistry) SimulateServiceServer {
return simulateServer{
simulate: simulate,
interfaceRegistry: interfaceRegistry,
}
}
var _ SimulateServiceServer = simulateServer{}
// Simulate implements the SimulateService.Simulate RPC method.
func (s simulateServer) Simulate(ctx context.Context, req *SimulateRequest) (*SimulateResponse, error) {
if req.Tx == nil {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx")
}
err := req.Tx.UnpackInterfaces(s.interfaceRegistry)
if err != nil {
return nil, err
}
txBytes, err := req.Tx.Marshal()
if err != nil {
return nil, err
}
gasInfo, result, err := s.simulate(txBytes)
if err != nil {
return nil, err
}
return &SimulateResponse{
GasInfo: &gasInfo,
Result: result,
}, nil
}

View File

@ -1,679 +0,0 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: cosmos/base/simulate/v1beta1/simulate.proto
package simulate
import (
context "context"
fmt "fmt"
types "github.com/cosmos/cosmos-sdk/types"
tx "github.com/cosmos/cosmos-sdk/types/tx"
grpc1 "github.com/gogo/protobuf/grpc"
proto "github.com/gogo/protobuf/proto"
_ "google.golang.org/genproto/googleapis/api/annotations"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// SimulateRequest is the request type for the SimulateServiceService.Simulate
// RPC method.
type SimulateRequest struct {
// tx is the transaction to simulate.
Tx *tx.Tx `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"`
}
func (m *SimulateRequest) Reset() { *m = SimulateRequest{} }
func (m *SimulateRequest) String() string { return proto.CompactTextString(m) }
func (*SimulateRequest) ProtoMessage() {}
func (*SimulateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_503c836d80bb2d47, []int{0}
}
func (m *SimulateRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *SimulateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_SimulateRequest.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *SimulateRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_SimulateRequest.Merge(m, src)
}
func (m *SimulateRequest) XXX_Size() int {
return m.Size()
}
func (m *SimulateRequest) XXX_DiscardUnknown() {
xxx_messageInfo_SimulateRequest.DiscardUnknown(m)
}
var xxx_messageInfo_SimulateRequest proto.InternalMessageInfo
func (m *SimulateRequest) GetTx() *tx.Tx {
if m != nil {
return m.Tx
}
return nil
}
// SimulateResponse is the response type for the
// SimulateServiceService.SimulateRPC method.
type SimulateResponse struct {
// gas_info is the information about gas used in the simulation.
GasInfo *types.GasInfo `protobuf:"bytes,1,opt,name=gas_info,json=gasInfo,proto3" json:"gas_info,omitempty"`
// result is the result of the simulation.
Result *types.Result `protobuf:"bytes,2,opt,name=result,proto3" json:"result,omitempty"`
}
func (m *SimulateResponse) Reset() { *m = SimulateResponse{} }
func (m *SimulateResponse) String() string { return proto.CompactTextString(m) }
func (*SimulateResponse) ProtoMessage() {}
func (*SimulateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_503c836d80bb2d47, []int{1}
}
func (m *SimulateResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *SimulateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_SimulateResponse.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *SimulateResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_SimulateResponse.Merge(m, src)
}
func (m *SimulateResponse) XXX_Size() int {
return m.Size()
}
func (m *SimulateResponse) XXX_DiscardUnknown() {
xxx_messageInfo_SimulateResponse.DiscardUnknown(m)
}
var xxx_messageInfo_SimulateResponse proto.InternalMessageInfo
func (m *SimulateResponse) GetGasInfo() *types.GasInfo {
if m != nil {
return m.GasInfo
}
return nil
}
func (m *SimulateResponse) GetResult() *types.Result {
if m != nil {
return m.Result
}
return nil
}
func init() {
proto.RegisterType((*SimulateRequest)(nil), "cosmos.base.simulate.v1beta1.SimulateRequest")
proto.RegisterType((*SimulateResponse)(nil), "cosmos.base.simulate.v1beta1.SimulateResponse")
}
func init() {
proto.RegisterFile("cosmos/base/simulate/v1beta1/simulate.proto", fileDescriptor_503c836d80bb2d47)
}
var fileDescriptor_503c836d80bb2d47 = []byte{
// 351 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xbf, 0x4b, 0xf3, 0x40,
0x18, 0xc7, 0x7b, 0x19, 0xfa, 0x96, 0x7b, 0x87, 0xf7, 0x25, 0x20, 0x94, 0x50, 0x42, 0x8d, 0x28,
0x05, 0xe9, 0x1d, 0xad, 0x4b, 0x07, 0x27, 0x17, 0x11, 0xb7, 0xd4, 0xc9, 0x45, 0x2e, 0xf1, 0x1a,
0x0f, 0xd3, 0xbb, 0x98, 0x7b, 0x52, 0x32, 0x3b, 0x3a, 0x09, 0x4e, 0xfe, 0x11, 0xfe, 0x1f, 0x8e,
0x05, 0x17, 0x47, 0x69, 0xfd, 0x43, 0xa4, 0xc9, 0x25, 0x2d, 0x82, 0xd2, 0x29, 0xb9, 0xe7, 0xf9,
0x7c, 0xbf, 0xcf, 0x2f, 0x7c, 0x18, 0x2a, 0x3d, 0x55, 0x9a, 0x06, 0x4c, 0x73, 0xaa, 0xc5, 0x34,
0x8b, 0x19, 0x70, 0x3a, 0x1b, 0x04, 0x1c, 0xd8, 0xa0, 0x0e, 0x90, 0x24, 0x55, 0xa0, 0xec, 0x4e,
0x09, 0x93, 0x15, 0x4c, 0xea, 0x9c, 0x81, 0x9d, 0x4e, 0xa4, 0x54, 0x14, 0x73, 0xca, 0x12, 0x41,
0x99, 0x94, 0x0a, 0x18, 0x08, 0x25, 0x75, 0xa9, 0x75, 0xf6, 0x36, 0x0b, 0xb1, 0x20, 0x14, 0x75,
0x91, 0xd5, 0xc3, 0x40, 0x8e, 0x81, 0x20, 0xaf, 0xb3, 0x90, 0x97, 0x39, 0x6f, 0x84, 0xff, 0x8d,
0x4d, 0x49, 0x9f, 0xdf, 0x65, 0x5c, 0x83, 0xbd, 0x8f, 0x2d, 0xc8, 0xdb, 0xa8, 0x8b, 0x7a, 0x7f,
0x87, 0x3b, 0xc4, 0x34, 0x07, 0x79, 0xd5, 0x11, 0xb9, 0xc8, 0x7d, 0x0b, 0x72, 0xef, 0x01, 0xe1,
0xff, 0x6b, 0xa9, 0x4e, 0x94, 0xd4, 0xdc, 0x3e, 0xc6, 0xad, 0x88, 0xe9, 0x2b, 0x21, 0x27, 0xca,
0x38, 0xec, 0x92, 0xcd, 0xf1, 0x8a, 0xae, 0x2a, 0xa3, 0x53, 0xa6, 0xcf, 0xe4, 0x44, 0xf9, 0x7f,
0xa2, 0xf2, 0xc7, 0x1e, 0xe1, 0x66, 0xca, 0x75, 0x16, 0x43, 0xdb, 0x2a, 0xb4, 0xdd, 0x9f, 0xb5,
0x7e, 0xc1, 0xf9, 0x86, 0x1f, 0xbe, 0xa0, 0xf5, 0x1c, 0x63, 0x9e, 0xce, 0x44, 0xc8, 0xed, 0x67,
0x84, 0x5b, 0x55, 0xcc, 0xee, 0x93, 0xdf, 0xb6, 0x4c, 0xbe, 0xed, 0xc0, 0x21, 0xdb, 0xe2, 0xe5,
0xdc, 0x1e, 0xb9, 0x7f, 0xfb, 0x7c, 0xb2, 0x7a, 0xde, 0x01, 0xdd, 0xea, 0xf2, 0x27, 0xe7, 0xaf,
0x0b, 0x17, 0xcd, 0x17, 0x2e, 0xfa, 0x58, 0xb8, 0xe8, 0x71, 0xe9, 0x36, 0xe6, 0x4b, 0xb7, 0xf1,
0xbe, 0x74, 0x1b, 0x97, 0x83, 0x48, 0xc0, 0x4d, 0x16, 0x90, 0x50, 0x4d, 0x2b, 0xaf, 0xf2, 0xd3,
0xd7, 0xd7, 0xb7, 0x34, 0x8c, 0x05, 0x97, 0x40, 0xa3, 0x34, 0x09, 0x6b, 0xb3, 0xa0, 0x59, 0x9c,
0xf2, 0xe8, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x7d, 0x16, 0xed, 0x90, 0x76, 0x02, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// SimulateServiceClient is the client API for SimulateService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type SimulateServiceClient interface {
// Simulate simulates executing a transaction for estimating gas usage.
Simulate(ctx context.Context, in *SimulateRequest, opts ...grpc.CallOption) (*SimulateResponse, error)
}
type simulateServiceClient struct {
cc grpc1.ClientConn
}
func NewSimulateServiceClient(cc grpc1.ClientConn) SimulateServiceClient {
return &simulateServiceClient{cc}
}
func (c *simulateServiceClient) Simulate(ctx context.Context, in *SimulateRequest, opts ...grpc.CallOption) (*SimulateResponse, error) {
out := new(SimulateResponse)
err := c.cc.Invoke(ctx, "/cosmos.base.simulate.v1beta1.SimulateService/Simulate", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// SimulateServiceServer is the server API for SimulateService service.
type SimulateServiceServer interface {
// Simulate simulates executing a transaction for estimating gas usage.
Simulate(context.Context, *SimulateRequest) (*SimulateResponse, error)
}
// UnimplementedSimulateServiceServer can be embedded to have forward compatible implementations.
type UnimplementedSimulateServiceServer struct {
}
func (*UnimplementedSimulateServiceServer) Simulate(ctx context.Context, req *SimulateRequest) (*SimulateResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Simulate not implemented")
}
func RegisterSimulateServiceServer(s grpc1.Server, srv SimulateServiceServer) {
s.RegisterService(&_SimulateService_serviceDesc, srv)
}
func _SimulateService_Simulate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SimulateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SimulateServiceServer).Simulate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cosmos.base.simulate.v1beta1.SimulateService/Simulate",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SimulateServiceServer).Simulate(ctx, req.(*SimulateRequest))
}
return interceptor(ctx, in, info, handler)
}
var _SimulateService_serviceDesc = grpc.ServiceDesc{
ServiceName: "cosmos.base.simulate.v1beta1.SimulateService",
HandlerType: (*SimulateServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Simulate",
Handler: _SimulateService_Simulate_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "cosmos/base/simulate/v1beta1/simulate.proto",
}
func (m *SimulateRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *SimulateRequest) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *SimulateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.Tx != nil {
{
size, err := m.Tx.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintSimulate(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *SimulateResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *SimulateResponse) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *SimulateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.Result != nil {
{
size, err := m.Result.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintSimulate(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
}
if m.GasInfo != nil {
{
size, err := m.GasInfo.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintSimulate(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintSimulate(dAtA []byte, offset int, v uint64) int {
offset -= sovSimulate(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *SimulateRequest) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Tx != nil {
l = m.Tx.Size()
n += 1 + l + sovSimulate(uint64(l))
}
return n
}
func (m *SimulateResponse) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.GasInfo != nil {
l = m.GasInfo.Size()
n += 1 + l + sovSimulate(uint64(l))
}
if m.Result != nil {
l = m.Result.Size()
n += 1 + l + sovSimulate(uint64(l))
}
return n
}
func sovSimulate(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozSimulate(x uint64) (n int) {
return sovSimulate(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *SimulateRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSimulate
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: SimulateRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: SimulateRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Tx", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSimulate
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthSimulate
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthSimulate
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Tx == nil {
m.Tx = &tx.Tx{}
}
if err := m.Tx.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipSimulate(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthSimulate
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthSimulate
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *SimulateResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSimulate
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: SimulateResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: SimulateResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field GasInfo", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSimulate
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthSimulate
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthSimulate
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.GasInfo == nil {
m.GasInfo = &types.GasInfo{}
}
if err := m.GasInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSimulate
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthSimulate
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthSimulate
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Result == nil {
m.Result = &types.Result{}
}
if err := m.Result.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipSimulate(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthSimulate
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthSimulate
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipSimulate(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowSimulate
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowSimulate
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowSimulate
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthSimulate
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupSimulate
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthSimulate
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthSimulate = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowSimulate = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupSimulate = fmt.Errorf("proto: unexpected end of group")
)

View File

@ -1,166 +0,0 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: cosmos/base/simulate/v1beta1/simulate.proto
/*
Package simulate is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package simulate
import (
"context"
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var (
filter_SimulateService_Simulate_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_SimulateService_Simulate_0(ctx context.Context, marshaler runtime.Marshaler, client SimulateServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SimulateRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SimulateService_Simulate_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.Simulate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_SimulateService_Simulate_0(ctx context.Context, marshaler runtime.Marshaler, server SimulateServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SimulateRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SimulateService_Simulate_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.Simulate(ctx, &protoReq)
return msg, metadata, err
}
// RegisterSimulateServiceHandlerServer registers the http handlers for service SimulateService to "mux".
// UnaryRPC :call SimulateServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterSimulateServiceHandlerFromEndpoint instead.
func RegisterSimulateServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server SimulateServiceServer) error {
mux.Handle("POST", pattern_SimulateService_Simulate_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.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_SimulateService_Simulate_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_SimulateService_Simulate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterSimulateServiceHandlerFromEndpoint is same as RegisterSimulateServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterSimulateServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterSimulateServiceHandler(ctx, mux, conn)
}
// RegisterSimulateServiceHandler registers the http handlers for service SimulateService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterSimulateServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterSimulateServiceHandlerClient(ctx, mux, NewSimulateServiceClient(conn))
}
// RegisterSimulateServiceHandlerClient registers the http handlers for service SimulateService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "SimulateServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "SimulateServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "SimulateServiceClient" to call the correct interceptors.
func RegisterSimulateServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client SimulateServiceClient) error {
mux.Handle("POST", pattern_SimulateService_Simulate_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_SimulateService_Simulate_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_SimulateService_Simulate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_SimulateService_Simulate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 2}, []string{"cosmos", "base", "simulate", "v1beta1"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_SimulateService_Simulate_0 = runtime.ForwardResponseMessage
)

View File

@ -1,119 +0,0 @@
package simulate_test
import (
"context"
"testing"
"github.com/stretchr/testify/suite"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/grpc/simulate"
"github.com/cosmos/cosmos-sdk/client/tx"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
type IntegrationTestSuite struct {
suite.Suite
app *simapp.SimApp
clientCtx client.Context
queryClient simulate.SimulateServiceClient
sdkCtx sdk.Context
}
func (s *IntegrationTestSuite) SetupSuite() {
app := simapp.Setup(true)
sdkCtx := app.BaseApp.NewContext(true, tmproto.Header{})
app.AccountKeeper.SetParams(sdkCtx, authtypes.DefaultParams())
app.BankKeeper.SetParams(sdkCtx, banktypes.DefaultParams())
// Set up TxConfig.
encodingConfig := simapp.MakeTestEncodingConfig()
clientCtx := client.Context{}.WithTxConfig(encodingConfig.TxConfig)
// Create new simulation server.
srv := simulate.NewSimulateServer(app.BaseApp.Simulate, encodingConfig.InterfaceRegistry)
queryHelper := baseapp.NewQueryServerTestHelper(sdkCtx, app.InterfaceRegistry())
simulate.RegisterSimulateServiceServer(queryHelper, srv)
queryClient := simulate.NewSimulateServiceClient(queryHelper)
s.app = app
s.clientCtx = clientCtx
s.queryClient = queryClient
s.sdkCtx = sdkCtx
}
func (s IntegrationTestSuite) TestSimulateService() {
// Create an account with some funds.
priv1, _, addr1 := testdata.KeyTestPubAddr()
acc1 := s.app.AccountKeeper.NewAccountWithAddress(s.sdkCtx, addr1)
err := acc1.SetAccountNumber(0)
s.Require().NoError(err)
s.app.AccountKeeper.SetAccount(s.sdkCtx, acc1)
s.app.BankKeeper.SetBalances(s.sdkCtx, addr1, sdk.Coins{
sdk.NewInt64Coin("atom", 10000000),
})
// Create a test x/bank MsgSend.
coins := sdk.NewCoins(sdk.NewInt64Coin("atom", 10))
_, _, addr2 := testdata.KeyTestPubAddr()
msg := banktypes.NewMsgSend(addr1, addr2, coins)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
memo := "foo"
accSeq, accNum := uint64(0), uint64(0)
// Create a txBuilder.
txBuilder := s.clientCtx.TxConfig.NewTxBuilder()
txBuilder.SetMsgs(msg)
txBuilder.SetMemo(memo)
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
// 1st round: set empty signature
sigV2 := signing.SignatureV2{
PubKey: priv1.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: s.clientCtx.TxConfig.SignModeHandler().DefaultMode(),
Signature: nil,
},
}
txBuilder.SetSignatures(sigV2)
// 2nd round: actually sign
sigV2, err = tx.SignWithPrivKey(
s.clientCtx.TxConfig.SignModeHandler().DefaultMode(),
authsigning.SignerData{ChainID: s.sdkCtx.ChainID(), AccountNumber: accNum, Sequence: accSeq},
txBuilder, priv1, s.clientCtx.TxConfig, accSeq,
)
txBuilder.SetSignatures(sigV2)
any, ok := txBuilder.(codectypes.IntoAny)
s.Require().True(ok)
cached := any.AsAny().GetCachedValue()
txTx, ok := cached.(*txtypes.Tx)
s.Require().True(ok)
res, err := s.queryClient.Simulate(
context.Background(),
&simulate.SimulateRequest{Tx: txTx},
)
s.Require().NoError(err)
// Check the result and gas used are correct.
s.Require().Equal(len(res.GetResult().GetEvents()), 4) // 1 transfer, 3 messages.
s.Require().True(res.GetGasInfo().GetGasUsed() > 0) // Gas used sometimes change, just check it's not empty.
}
func TestSimulateTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}

View File

@ -12,7 +12,6 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
sim "github.com/cosmos/cosmos-sdk/client/grpc/simulate"
"github.com/cosmos/cosmos-sdk/client/input"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
@ -279,7 +278,7 @@ func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) {
return nil, fmt.Errorf("cannot simulate amino tx")
}
simReq := sim.SimulateRequest{Tx: protoTx}
simReq := tx.SimulateRequest{Tx: protoTx}
return simReq.Marshal()
}
@ -288,21 +287,23 @@ func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) {
// simulation response obtained by the query and the adjusted gas amount.
func CalculateGas(
queryFunc func(string, []byte) ([]byte, int64, error), txf Factory, msgs ...sdk.Msg,
) (sim.SimulateResponse, uint64, error) {
) (tx.SimulateResponse, uint64, error) {
txBytes, err := BuildSimTx(txf, msgs...)
if err != nil {
return sim.SimulateResponse{}, 0, err
return tx.SimulateResponse{}, 0, err
}
bz, _, err := queryFunc("/cosmos.base.simulate.v1beta1.SimulateService/Simulate", txBytes)
// TODO This should use the generated tx service Client.
// https://github.com/cosmos/cosmos-sdk/issues/7726
bz, _, err := queryFunc("/cosmos.tx.v1beta1.Service/Simulate", txBytes)
if err != nil {
return sim.SimulateResponse{}, 0, err
return tx.SimulateResponse{}, 0, err
}
var simRes sim.SimulateResponse
var simRes tx.SimulateResponse
if err := simRes.Unmarshal(bz); err != nil {
return sim.SimulateResponse{}, 0, err
return tx.SimulateResponse{}, 0, err
}
return simRes, uint64(txf.GasAdjustment() * float64(simRes.GasInfo.GasUsed)), nil

View File

@ -7,12 +7,12 @@ import (
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/grpc/simulate"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
@ -28,7 +28,7 @@ func TestCalculateGas(t *testing.T) {
if wantErr {
return nil, 0, errors.New("query failed")
}
simRes := &simulate.SimulateResponse{
simRes := &txtypes.SimulateResponse{
GasInfo: &sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed},
Result: &sdk.Result{Data: []byte("tx data"), Log: "log"},
}

View File

@ -1,33 +0,0 @@
syntax = "proto3";
package cosmos.base.simulate.v1beta1;
import "google/api/annotations.proto";
import "cosmos/base/abci/v1beta1/abci.proto";
import "cosmos/tx/v1beta1/tx.proto";
option go_package = "github.com/cosmos/cosmos-sdk/client/grpc/simulate";
// SimulateService defines a gRPC service for simulating transactions.
// It may also support querying and broadcasting in the future.
service SimulateService {
// Simulate simulates executing a transaction for estimating gas usage.
rpc Simulate(SimulateRequest) returns (SimulateResponse) {
option (google.api.http).post = "/cosmos/base/simulate/v1beta1/simulate";
}
}
// SimulateRequest is the request type for the SimulateServiceService.Simulate
// RPC method.
message SimulateRequest {
// tx is the transaction to simulate.
cosmos.tx.v1beta1.Tx tx = 1;
}
// SimulateResponse is the response type for the
// SimulateServiceService.SimulateRPC method.
message SimulateResponse {
// gas_info is the information about gas used in the simulation.
cosmos.base.abci.v1beta1.GasInfo gas_info = 1;
// result is the result of the simulation.
cosmos.base.abci.v1beta1.Result result = 2;
}

View File

@ -0,0 +1,49 @@
syntax = "proto3";
package cosmos.tx.v1beta1;
import "google/api/annotations.proto";
import "cosmos/base/abci/v1beta1/abci.proto";
import "cosmos/tx/v1beta1/tx.proto";
option go_package = "github.com/cosmos/cosmos-sdk/types/tx";
// Service defines a gRPC service for interacting with transactions.
service Service {
// Simulate simulates executing a transaction for estimating gas usage.
rpc Simulate(SimulateRequest) returns (SimulateResponse) {
option (google.api.http).post = "/cosmos/tx/v1beta1/simulate";
}
// GetTx fetches a tx by hash.
rpc GetTx(GetTxRequest) returns (GetTxResponse) {
option (google.api.http).get = "/cosmos/tx/v1beta1/tx/{hash}";
}
}
// SimulateRequest is the request type for the Service.Simulate
// RPC method.
message SimulateRequest {
// tx is the transaction to simulate.
cosmos.tx.v1beta1.Tx tx = 1;
}
// SimulateResponse is the response type for the
// Service.SimulateRPC method.
message SimulateResponse {
// gas_info is the information about gas used in the simulation.
cosmos.base.abci.v1beta1.GasInfo gas_info = 1;
// result is the result of the simulation.
cosmos.base.abci.v1beta1.Result result = 2;
}
// GetTx is the request type for the Service.GetTx
// RPC method.
message GetTxRequest {
// hash is the tx hash to query, encoded as a hex string.
string hash = 1;
}
// GetTxResponse is the response type for the Service.GetTx method.
message GetTxResponse {
// tx is the queried transaction.
cosmos.tx.v1beta1.Tx tx = 1;
}

View File

@ -231,6 +231,9 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App
return err
}
// Add the tx service to the gRPC router.
app.RegisterTxService(clientCtx)
var apiSrv *api.Server
config := config.GetConfig(ctx.Viper)

View File

@ -10,6 +10,7 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/server/config"
)
@ -37,6 +38,10 @@ type (
// RegisterGRPCServer registers gRPC services directly with the gRPC
// server.
RegisterGRPCServer(grpc.Server)
// RegisterTxService registers the gRPC Query service for tx (such as tx
// simulation, fetching txs by hash...).
RegisterTxService(clientCtx client.Context)
}
// AppCreator is a function that allows us to lazily initialize an

View File

@ -22,6 +22,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -32,6 +33,7 @@ import (
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
"github.com/cosmos/cosmos-sdk/x/bank"
@ -134,7 +136,10 @@ var (
}
)
var _ App = (*SimApp)(nil)
var (
_ App = (*SimApp)(nil)
_ servertypes.Application = (*SimApp)(nil)
)
// SimApp extends an ABCI application, but with most of its parameters exported.
// They are exported for convenience in creating helper functions, as object
@ -204,7 +209,6 @@ func NewSimApp(
bApp.SetCommitMultiStoreTracer(traceStore)
bApp.SetAppVersion(version.Version)
bApp.SetInterfaceRegistry(interfaceRegistry)
bApp.GRPCQueryRouter().RegisterSimulateService(bApp.Simulate, interfaceRegistry)
keys := sdk.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey,
@ -544,10 +548,14 @@ func (app *SimApp) SimulationManager() *module.SimulationManager {
func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
clientCtx := apiSvr.ClientCtx
rpc.RegisterRoutes(clientCtx, apiSvr.Router)
// Register legacy tx routes.
authrest.RegisterTxRoutes(clientCtx, apiSvr.Router)
// Register new tx routes from grpc-gateway.
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCRouter)
// Register legacy and grpc-gateway routes for all modules.
ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router)
ModuleBasics.RegisterGRPCGatewayRoutes(apiSvr.ClientCtx, apiSvr.GRPCRouter)
ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCRouter)
// register swagger API from root so that other applications can override easily
if apiConfig.Swagger {
@ -555,6 +563,11 @@ func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APICon
}
}
// RegisterTxService implements the Application.RegisterTxService method.
func (app *SimApp) RegisterTxService(clientCtx client.Context) {
authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry)
}
// RegisterSwaggerAPI registers swagger route with API Server
func RegisterSwaggerAPI(ctx client.Context, rtr *mux.Router) {
statikFS, err := fs.New()

View File

@ -59,10 +59,16 @@ func startInProcess(cfg Config, val *Validator) error {
val.RPCClient = local.New(tmNode)
}
if val.APIAddress != "" {
// We'll need a RPC client if the validator exposes a gRPC or REST endpoint.
if val.APIAddress != "" || val.AppConfig.GRPC.Enable {
val.ClientCtx = val.ClientCtx.
WithClient(val.RPCClient)
// Add the tx service in the gRPC router.
app.RegisterTxService(val.ClientCtx)
}
if val.APIAddress != "" {
apiSrv := api.New(val.ClientCtx, logger.With("module", "api-server"))
app.RegisterAPIRoutes(apiSrv, val.AppConfig.API)

1078
types/tx/service.pb.go Normal file

File diff suppressed because it is too large Load Diff

264
types/tx/service.pb.gw.go Normal file
View File

@ -0,0 +1,264 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: cosmos/tx/v1beta1/service.proto
/*
Package tx is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package tx
import (
"context"
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var (
filter_Service_Simulate_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Service_Simulate_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SimulateRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Service_Simulate_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.Simulate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Service_Simulate_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SimulateRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Service_Simulate_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.Simulate(ctx, &protoReq)
return msg, metadata, err
}
func request_Service_GetTx_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetTxRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["hash"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "hash")
}
protoReq.Hash, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "hash", err)
}
msg, err := client.GetTx(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Service_GetTx_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetTxRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["hash"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "hash")
}
protoReq.Hash, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "hash", err)
}
msg, err := server.GetTx(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.
// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterServiceHandlerFromEndpoint instead.
func RegisterServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ServiceServer) error {
mux.Handle("POST", pattern_Service_Simulate_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.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Service_Simulate_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Service_Simulate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Service_GetTx_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.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Service_GetTx_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Service_GetTx_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterServiceHandlerFromEndpoint is same as RegisterServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterServiceHandler(ctx, mux, conn)
}
// RegisterServiceHandler registers the http handlers for service Service to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterServiceHandlerClient(ctx, mux, NewServiceClient(conn))
}
// RegisterServiceHandlerClient registers the http handlers for service Service
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "ServiceClient" to call the correct interceptors.
func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ServiceClient) error {
mux.Handle("POST", pattern_Service_Simulate_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_Simulate_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_Simulate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Service_GetTx_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_GetTx_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_GetTx_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Service_Simulate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "tx", "v1beta1", "simulate"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_GetTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3}, []string{"cosmos", "tx", "v1beta1", "hash"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_Service_Simulate_0 = runtime.ForwardResponseMessage
forward_Service_GetTx_0 = runtime.ForwardResponseMessage
)

111
x/auth/tx/service.go Normal file
View File

@ -0,0 +1,111 @@
package tx
import (
"context"
"encoding/hex"
gogogrpc "github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
)
// baseAppSimulateFn is the signature of the Baseapp#Simulate function.
type baseAppSimulateFn func(txBytes []byte) (sdk.GasInfo, *sdk.Result, error)
// txServer is the server for the protobuf Tx service.
type txServer struct {
clientCtx client.Context
simulate baseAppSimulateFn
interfaceRegistry codectypes.InterfaceRegistry
}
// NewTxServer creates a new Tx service server.
func NewTxServer(clientCtx client.Context, simulate baseAppSimulateFn, interfaceRegistry codectypes.InterfaceRegistry) txtypes.ServiceServer {
return txServer{
clientCtx: clientCtx,
simulate: simulate,
interfaceRegistry: interfaceRegistry,
}
}
var _ txtypes.ServiceServer = txServer{}
// Simulate implements the ServiceServer.Simulate RPC method.
func (s txServer) Simulate(ctx context.Context, req *txtypes.SimulateRequest) (*txtypes.SimulateResponse, error) {
if req.Tx == nil {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx")
}
err := req.Tx.UnpackInterfaces(s.interfaceRegistry)
if err != nil {
return nil, err
}
txBytes, err := req.Tx.Marshal()
if err != nil {
return nil, err
}
gasInfo, result, err := s.simulate(txBytes)
if err != nil {
return nil, err
}
return &txtypes.SimulateResponse{
GasInfo: &gasInfo,
Result: result,
}, nil
}
// GetTx implements the ServiceServer.GetTx RPC method.
func (s txServer) GetTx(ctx context.Context, req *txtypes.GetTxRequest) (*txtypes.GetTxResponse, error) {
// We get hash as a hex string in the request, convert it to bytes.
hash, err := hex.DecodeString(req.Hash)
if err != nil {
return nil, err
}
// TODO We should also check the proof flag in gRPC header.
// https://github.com/cosmos/cosmos-sdk/issues/7036.
result, err := s.clientCtx.Client.Tx(ctx, hash, false)
if err != nil {
return nil, err
}
// Create a proto codec, we need it to unmarshal the tx bytes.
cdc := codec.NewProtoCodec(s.clientCtx.InterfaceRegistry)
var protoTx txtypes.Tx
if err := cdc.UnmarshalBinaryBare(result.Tx, &protoTx); err != nil {
return nil, err
}
return &txtypes.GetTxResponse{
Tx: &protoTx,
}, nil
}
// RegisterTxService registers the tx service on the gRPC router.
func RegisterTxService(
qrt gogogrpc.Server,
clientCtx client.Context,
simulateFn baseAppSimulateFn,
interfaceRegistry codectypes.InterfaceRegistry,
) {
txtypes.RegisterServiceServer(
qrt,
NewTxServer(clientCtx, simulateFn, interfaceRegistry),
)
}
// RegisterGRPCGatewayRoutes mounts the tx service's GRPC-gateway routes on the
// given Mux.
func RegisterGRPCGatewayRoutes(clientConn gogogrpc.ClientConn, mux *runtime.ServeMux) {
txtypes.RegisterServiceHandlerClient(context.Background(), mux, txtypes.NewServiceClient(clientConn))
}

164
x/auth/tx/service_test.go Normal file
View File

@ -0,0 +1,164 @@
package tx_test
import (
"context"
"fmt"
"testing"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
queryClient tx.ServiceClient
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
cfg := network.DefaultConfig()
cfg.NumValidators = 1
s.cfg = cfg
s.network = network.New(s.T(), cfg)
s.Require().NotNil(s.network)
_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)
s.queryClient = tx.NewServiceClient(s.network.Validators[0].ClientCtx)
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}
func (s IntegrationTestSuite) TestSimulate() {
val := s.network.Validators[0]
// prepare txBuilder with msg
txBuilder := val.ClientCtx.TxConfig.NewTxBuilder()
feeAmount := sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)}
gasLimit := testdata.NewTestGasLimit()
s.Require().NoError(
txBuilder.SetMsgs(&banktypes.MsgSend{
FromAddress: val.Address.String(),
ToAddress: val.Address.String(),
Amount: sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)},
}),
)
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
txBuilder.SetMemo("foobar")
// setup txFactory
txFactory := clienttx.Factory{}.
WithChainID(val.ClientCtx.ChainID).
WithKeybase(val.ClientCtx.Keyring).
WithTxConfig(val.ClientCtx.TxConfig).
WithSignMode(signing.SignMode_SIGN_MODE_DIRECT)
// Sign Tx.
err := authclient.SignTx(txFactory, val.ClientCtx, val.Moniker, txBuilder, false)
s.Require().NoError(err)
// Convert the txBuilder to a tx.Tx.
protoTx, err := txBuilderToProtoTx(txBuilder)
s.Require().NoError(err)
// Run the simulate gRPC query.
res, err := s.queryClient.Simulate(
context.Background(),
&tx.SimulateRequest{Tx: protoTx},
)
s.Require().NoError(err)
// Check the result and gas used are correct.
s.Require().Equal(len(res.GetResult().GetEvents()), 4) // 1 transfer, 3 messages.
s.Require().True(res.GetGasInfo().GetGasUsed() > 0) // Gas used sometimes change, just check it's not empty.
}
func (s IntegrationTestSuite) TestGetTx() {
val := s.network.Validators[0]
// Create a new MsgSend tx from val to itself.
out, err := bankcli.MsgSendExec(
val.ClientCtx,
val.Address,
val.Address,
sdk.NewCoins(
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
fmt.Sprintf("--%s=foobar", flags.FlagMemo),
)
s.Require().NoError(err)
var txRes sdk.TxResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes))
s.Require().Equal(uint32(0), txRes.Code)
s.Require().NoError(s.network.WaitForNextBlock())
// Query the tx via gRPC.
grpcRes, err := s.queryClient.GetTx(
context.Background(),
&tx.GetTxRequest{Hash: txRes.TxHash},
)
s.Require().NoError(err)
s.Require().Equal("foobar", grpcRes.Tx.Body.Memo)
// Query the tx via grpc-gateway.
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/tx/%s", val.APIAddress, txRes.TxHash))
s.Require().NoError(err)
var getTxRes tx.GetTxResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &getTxRes))
s.Require().Equal("foobar", getTxRes.Tx.Body.Memo)
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
// txBuilderToProtoTx converts a txBuilder into a proto tx.Tx.
func txBuilderToProtoTx(txBuilder client.TxBuilder) (*tx.Tx, error) { // nolint
intoAnyTx, ok := txBuilder.(codectypes.IntoAny)
if !ok {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", (codectypes.IntoAny)(nil), intoAnyTx)
}
any := intoAnyTx.AsAny().GetCachedValue()
if any == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "any's cached value is empty")
}
protoTx, ok := any.(*tx.Tx)
if !ok {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", (codectypes.IntoAny)(nil), intoAnyTx)
}
return protoTx, nil
}