feat(x/tx): unknown field filtering (#15557)

This commit is contained in:
Matt Kocubinski 2023-03-28 13:01:41 -05:00 committed by GitHub
parent 22621995b5
commit 383fed4c6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 29195 additions and 1 deletions

View File

@ -40,4 +40,4 @@ Ref: https://keepachangelog.com/en/1.0.0/
## Improvements
* [#15302](https://github.com/cosmos/cosmos-sdk/pull/15302) Add support for a custom registry (e.g. gogo's MergedRegistry) to be plugged into SIGN_MODE_TEXTUAL.
* [#15557](https://github.com/cosmos/cosmos-sdk/pull/15557) Implement unknown field filtering.

11
x/tx/decode/errors.go Normal file
View File

@ -0,0 +1,11 @@
package decode
import "cosmossdk.io/errors"
const (
txCodespace = "tx"
)
var (
ErrUnknownField = errors.Register(txCodespace, 2, "unknown protobuf field")
)

161
x/tx/decode/unknown.go Normal file
View File

@ -0,0 +1,161 @@
package decode
import (
"errors"
"fmt"
"strings"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/known/anypb"
)
const bit11NonCritical = 1 << 10
var anyDesc = (&anypb.Any{}).ProtoReflect().Descriptor()
var anyFullName = anyDesc.FullName()
// RejectUnknownFieldsStrict operates by the same rules as RejectUnknownFields, but returns an error if any unknown
// non-critical fields are encountered.
func RejectUnknownFieldsStrict(bz []byte, msg protoreflect.MessageDescriptor, resolver protodesc.Resolver) error {
var _, err = RejectUnknownFields(bz, msg, false, resolver)
return err
}
// RejectUnknownFields rejects any bytes bz with an error that has unknown fields for the provided proto.Message type with an
// option to allow non-critical fields (specified as those fields with bit 11) to pass through. In either case, the
// hasUnknownNonCriticals will be set to true if non-critical fields were encountered during traversal. This flag can be
// used to treat a message with non-critical field different in different security contexts (such as transaction signing).
// This function traverses inside of messages nested via google.protobuf.Any. It does not do any deserialization of the proto.Message.
// An AnyResolver must be provided for traversing inside google.protobuf.Any's.
func RejectUnknownFields(bz []byte, desc protoreflect.MessageDescriptor, allowUnknownNonCriticals bool, resolver protodesc.Resolver) (hasUnknownNonCriticals bool, err error) {
if len(bz) == 0 {
return hasUnknownNonCriticals, nil
}
fields := desc.Fields()
for len(bz) > 0 {
tagNum, wireType, m := protowire.ConsumeTag(bz)
if m < 0 {
return hasUnknownNonCriticals, errors.New("invalid length")
}
fieldDesc := fields.ByNumber(tagNum)
if fieldDesc == nil {
isCriticalField := tagNum&bit11NonCritical == 0
if !isCriticalField {
hasUnknownNonCriticals = true
}
if isCriticalField || !allowUnknownNonCriticals {
// The tag is critical, so report it.
return hasUnknownNonCriticals, ErrUnknownField.Wrapf(
"%s: {TagNum: %d, WireType:%q}",
desc.FullName(), tagNum, WireTypeToString(wireType))
}
}
// Skip over the bytes that store fieldNumber and wireType bytes.
bz = bz[m:]
n := protowire.ConsumeFieldValue(tagNum, wireType, bz)
if n < 0 {
err = fmt.Errorf("could not consume field value for tagNum: %d, wireType: %q; %w",
tagNum, WireTypeToString(wireType), protowire.ParseError(n))
return hasUnknownNonCriticals, err
}
fieldBytes := bz[:n]
bz = bz[n:]
// An unknown but non-critical field
if fieldDesc == nil {
continue
}
fieldMessage := fieldDesc.Message()
// not message or group kind
if fieldMessage == nil {
continue
}
// consume length prefix of nested message
_, o := protowire.ConsumeVarint(fieldBytes)
fieldBytes = fieldBytes[o:]
var err error
if fieldMessage.FullName() == anyFullName {
// Firstly typecheck types.Any to ensure nothing snuck in.
hasUnknownNonCriticalsChild, err := RejectUnknownFields(fieldBytes, anyDesc, allowUnknownNonCriticals, resolver)
hasUnknownNonCriticals = hasUnknownNonCriticals || hasUnknownNonCriticalsChild
if err != nil {
return hasUnknownNonCriticals, err
}
var a anypb.Any
if err = proto.Unmarshal(fieldBytes, &a); err != nil {
return hasUnknownNonCriticals, err
}
msgName := protoreflect.FullName(strings.TrimPrefix(a.TypeUrl, "/"))
msgDesc, err := resolver.FindDescriptorByName(msgName)
if err != nil {
return hasUnknownNonCriticals, err
}
fieldMessage = msgDesc.(protoreflect.MessageDescriptor)
fieldBytes = a.Value
}
hasUnknownNonCriticalsChild, err := RejectUnknownFields(fieldBytes, fieldMessage, allowUnknownNonCriticals, resolver)
hasUnknownNonCriticals = hasUnknownNonCriticals || hasUnknownNonCriticalsChild
if err != nil {
return hasUnknownNonCriticals, err
}
}
return hasUnknownNonCriticals, nil
}
// errUnknownField represents an error indicating that we encountered
// a field that isn't available in the target proto.Message.
type errUnknownField struct {
Desc protoreflect.MessageDescriptor
TagNum protowire.Number
WireType protowire.Type
}
// String implements fmt.Stringer.
func (twt *errUnknownField) String() string {
return fmt.Sprintf("errUnknownField %q: {TagNum: %d, WireType:%q}",
twt.Desc.FullName(), twt.TagNum, WireTypeToString(twt.WireType))
}
// Error implements the error interface.
func (twt *errUnknownField) Error() string {
return twt.String()
}
var _ error = (*errUnknownField)(nil)
// WireTypeToString returns a string representation of the given protowire.Type.
func WireTypeToString(wt protowire.Type) string {
switch wt {
case 0:
return "varint"
case 1:
return "fixed64"
case 2:
return "bytes"
case 3:
return "start_group"
case 4:
return "end_group"
case 5:
return "fixed32"
default:
return fmt.Sprintf("unknown type: %d", wt)
}
}

674
x/tx/decode/unknown_test.go Normal file
View File

@ -0,0 +1,674 @@
package decode_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/known/anypb"
"cosmossdk.io/x/tx/decode"
"cosmossdk.io/x/tx/internal/testpb"
)
func errUnknownField(typ string, tagNum int, wireType protowire.Type) error {
var wt string
if wireType >= 0 && wireType < 6 {
wt = decode.WireTypeToString(wireType)
}
return decode.ErrUnknownField.Wrapf("%s: {TagNum: %d, WireType:%q}", typ, tagNum, wt)
}
func errMismatchedField(typ string, wireType protowire.Type) error {
return fmt.Errorf("invalid wire type %s for field %s", decode.WireTypeToString(wireType), typ)
}
var ProtoResolver = protoregistry.GlobalFiles
func TestRejectUnknownFieldsRepeated(t *testing.T) {
tests := []struct {
name string
in proto.Message
recv proto.Message
wantErr error
allowUnknownNonCriticals bool
hasUnknownNonCriticals bool
}{
{
name: "Unknown field in midst of repeated values",
in: &testpb.TestVersion2{
C: []*testpb.TestVersion2{
{
C: []*testpb.TestVersion2{
{
Sum: &testpb.TestVersion2_F{
F: &testpb.TestVersion2{
A: &testpb.TestVersion2{
B: &testpb.TestVersion2{
H: []*testpb.TestVersion1{
{
X: 0x01,
},
},
},
},
},
},
},
{
Sum: &testpb.TestVersion2_F{
F: &testpb.TestVersion2{
A: &testpb.TestVersion2{
B: &testpb.TestVersion2{
H: []*testpb.TestVersion1{
{
X: 0x02,
},
},
},
},
},
},
},
{
Sum: &testpb.TestVersion2_F{
F: &testpb.TestVersion2{
NewField_: 411,
},
},
},
},
},
},
},
recv: new(testpb.TestVersion1),
wantErr: errUnknownField(
"testpb.TestVersion1",
25,
0),
},
{
name: "Unknown field in midst of repeated values, allowUnknownNonCriticals set",
allowUnknownNonCriticals: true,
in: &testpb.TestVersion2{
C: []*testpb.TestVersion2{
{
C: []*testpb.TestVersion2{
{
Sum: &testpb.TestVersion2_F{
F: &testpb.TestVersion2{
A: &testpb.TestVersion2{
B: &testpb.TestVersion2{
H: []*testpb.TestVersion1{
{
X: 0x01,
},
},
},
},
},
},
},
{
Sum: &testpb.TestVersion2_F{
F: &testpb.TestVersion2{
A: &testpb.TestVersion2{
B: &testpb.TestVersion2{
H: []*testpb.TestVersion1{
{
X: 0x02,
},
},
},
},
},
},
},
{
Sum: &testpb.TestVersion2_F{
F: &testpb.TestVersion2{
NewField_: 411,
},
},
},
},
},
},
},
recv: new(testpb.TestVersion1),
wantErr: errUnknownField(
"testpb.TestVersion1",
25,
0),
},
{
name: "Unknown field in midst of repeated values, non-critical field to be rejected",
in: &testpb.TestVersion3{
C: []*testpb.TestVersion3{
{
C: []*testpb.TestVersion3{
{
Sum: &testpb.TestVersion3_F{
F: &testpb.TestVersion3{
A: &testpb.TestVersion3{
B: &testpb.TestVersion3{
X: 0x01,
},
},
},
},
},
{
Sum: &testpb.TestVersion3_F{
F: &testpb.TestVersion3{
A: &testpb.TestVersion3{
B: &testpb.TestVersion3{
X: 0x02,
},
},
},
},
},
{
Sum: &testpb.TestVersion3_F{
F: &testpb.TestVersion3{
NonCriticalField: "non-critical",
},
},
},
},
},
},
},
recv: new(testpb.TestVersion1),
wantErr: errUnknownField(
"testpb.TestVersion1",
1031,
2),
hasUnknownNonCriticals: true,
},
{
name: "Unknown field in midst of repeated values, non-critical field ignored",
allowUnknownNonCriticals: true,
in: &testpb.TestVersion3{
C: []*testpb.TestVersion3{
{
C: []*testpb.TestVersion3{
{
Sum: &testpb.TestVersion3_F{
F: &testpb.TestVersion3{
A: &testpb.TestVersion3{
B: &testpb.TestVersion3{
X: 0x01,
},
},
},
},
},
{
Sum: &testpb.TestVersion3_F{
F: &testpb.TestVersion3{
A: &testpb.TestVersion3{
B: &testpb.TestVersion3{
X: 0x02,
},
},
},
},
},
{
Sum: &testpb.TestVersion3_F{
F: &testpb.TestVersion3{
NonCriticalField: "non-critical",
},
},
},
},
},
},
},
recv: new(testpb.TestVersion1),
wantErr: nil,
hasUnknownNonCriticals: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
protoBlob, err := proto.Marshal(tt.in)
if err != nil {
t.Fatal(err)
}
desc := tt.recv.ProtoReflect().Descriptor()
hasUnknownNonCriticals, gotErr := decode.RejectUnknownFields(
protoBlob, desc, tt.allowUnknownNonCriticals, ProtoResolver)
if tt.wantErr != nil {
require.EqualError(t, gotErr, tt.wantErr.Error())
} else {
require.NoError(t, gotErr)
}
require.Equal(t, tt.hasUnknownNonCriticals, hasUnknownNonCriticals)
})
}
}
func TestRejectUnknownFields_allowUnknownNonCriticals(t *testing.T) {
tests := []struct {
name string
in proto.Message
allowUnknownNonCriticals bool
wantErr error
}{
{
name: "Field that's in the reserved range, should fail by default",
in: &testpb.Customer2{
Id: 289,
Reserved: 99,
},
wantErr: errUnknownField(
"testpb.Customer1",
1047,
0),
},
{
name: "Field that's in the reserved range, toggle allowUnknownNonCriticals",
allowUnknownNonCriticals: true,
in: &testpb.Customer2{
Id: 289,
Reserved: 99,
},
wantErr: nil,
},
{
name: "Unknown fields that are critical, but with allowUnknownNonCriticals set",
allowUnknownNonCriticals: true,
in: &testpb.Customer2{
Id: 289,
City: testpb.Customer2_PaloAlto,
},
wantErr: errUnknownField(
"testpb.Customer1",
6,
0),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
blob, err := proto.Marshal(tt.in)
if err != nil {
t.Fatalf("Failed to marshal input: %v", err)
}
c1 := new(testpb.Customer1).ProtoReflect().Descriptor()
_, gotErr := decode.RejectUnknownFields(blob, c1, tt.allowUnknownNonCriticals, ProtoResolver)
if tt.wantErr != nil {
require.EqualError(t, gotErr, tt.wantErr.Error())
} else {
require.NoError(t, gotErr)
}
})
}
}
func TestRejectUnknownFieldsNested(t *testing.T) {
tests := []struct {
name string
in proto.Message
recv proto.Message
wantErr error
}{
{
name: "TestVersion3 from TestVersionFD1",
in: &testpb.TestVersion2{
X: 5,
Sum: &testpb.TestVersion2_E{
E: 100,
},
H: []*testpb.TestVersion1{
{X: 999},
{X: -55},
{
X: 102,
Sum: &testpb.TestVersion1_F{
F: &testpb.TestVersion1{
X: 4,
},
},
},
},
K: &testpb.Customer1{
Id: 45,
Name: "customer1",
SubscriptionFee: 99,
},
},
recv: new(testpb.TestVersionFD1),
wantErr: errUnknownField(
"testpb.TestVersionFD1",
12,
2),
},
{
name: "Alternating oneofs",
in: &testpb.TestVersion3{
Sum: &testpb.TestVersion3_E{
E: 99,
},
},
recv: new(testpb.TestVersion3LoneOneOfValue),
wantErr: nil,
},
{
name: "Alternating oneofs mismatched field",
in: &testpb.TestVersion3{
Sum: &testpb.TestVersion3_F{
F: &testpb.TestVersion3{
X: 99,
},
},
},
recv: new(testpb.TestVersion3LoneOneOfValue),
wantErr: errUnknownField(
"testpb.TestVersion3LoneOneOfValue",
7,
2),
},
{
name: "Discrepancy in a deeply nested one of field",
in: &testpb.TestVersion3{
Sum: &testpb.TestVersion3_F{
F: &testpb.TestVersion3{
Sum: &testpb.TestVersion3_F{
F: &testpb.TestVersion3{
X: 19,
Sum: &testpb.TestVersion3_E{
E: 99,
},
},
},
},
},
},
recv: new(testpb.TestVersion3LoneNesting),
wantErr: errUnknownField(
"testpb.TestVersion3LoneNesting",
6,
0),
},
{
name: "unknown field types.Any in G",
in: &testpb.TestVersion3{
G: &anypb.Any{
TypeUrl: "/testpb.TestVersion1",
Value: mustMarshal(&testpb.TestVersion2{
Sum: &testpb.TestVersion2_F{
F: &testpb.TestVersion2{
NewField_: 999,
},
},
}),
},
},
recv: new(testpb.TestVersion3),
wantErr: errUnknownField(
"testpb.TestVersion1",
25, 0),
},
{
name: "types.Any with extra fields",
in: &testpb.TestVersionFD1WithExtraAny{
G: &testpb.AnyWithExtra{
A: &anypb.Any{
TypeUrl: "/testpb.TestVersion1",
Value: mustMarshal(&testpb.TestVersion2{
Sum: &testpb.TestVersion2_F{
F: &testpb.TestVersion2{
NewField_: 999,
},
},
}),
},
B: 3,
C: 2,
},
},
recv: new(testpb.TestVersion3),
wantErr: errUnknownField(
"google.protobuf.Any",
3,
0),
},
{
name: "mismatched types.Any in G",
in: &testpb.TestVersion1{
G: &anypb.Any{
TypeUrl: "/testpb.TestVersion4LoneNesting",
Value: mustMarshal(&testpb.TestVersion3LoneNesting_Inner1{
Inner: &testpb.TestVersion3LoneNesting_Inner1_InnerInner{
Id: "ID",
City: "Gotham",
},
}),
},
},
recv: new(testpb.TestVersion1),
// behavior change from previous implementation: we allow mismatched wire -> proto types,
// but this will still error on ConsumeFieldValue
wantErr: fmt.Errorf(`could not consume field value for tagNum: 8, wireType: "unknown type: 7"; proto: cannot parse reserved wire type`),
},
{
name: "From nested proto message, message index 0",
in: &testpb.TestVersion3LoneNesting{
Inner1: &testpb.TestVersion3LoneNesting_Inner1{
Id: 10,
Name: "foo",
Inner: &testpb.TestVersion3LoneNesting_Inner1_InnerInner{
Id: "ID",
City: "Palo Alto",
},
},
},
recv: new(testpb.TestVersion4LoneNesting),
wantErr: nil,
},
{
name: "From nested proto message, message index 1",
in: &testpb.TestVersion3LoneNesting{
Inner2: &testpb.TestVersion3LoneNesting_Inner2{
Id: "ID",
Country: "Maldives",
Inner: &testpb.TestVersion3LoneNesting_Inner2_InnerInner{
Id: "ID",
City: "Unknown",
},
},
},
recv: new(testpb.TestVersion4LoneNesting),
wantErr: nil,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
protoBlob, err := proto.Marshal(tt.in)
if err != nil {
t.Fatal(err)
}
desc := tt.recv.ProtoReflect().Descriptor()
gotErr := decode.RejectUnknownFieldsStrict(protoBlob, desc, ProtoResolver)
if tt.wantErr != nil {
require.EqualError(t, gotErr, tt.wantErr.Error())
} else {
require.NoError(t, gotErr)
}
})
}
}
func TestRejectUnknownFieldsFlat(t *testing.T) {
tests := []struct {
name string
in proto.Message
wantErr error
}{
{
name: "Oneof with same field number, shouldn't complain",
in: &testpb.Customer3{
Id: 68,
Name: "ACME3",
Payment: &testpb.Customer3_CreditCardNo{
CreditCardNo: "123-XXXX-XXX881",
},
},
wantErr: nil,
},
{
name: "Oneof with different field number, should fail",
in: &testpb.Customer3{
Id: 68,
Name: "ACME3",
Payment: &testpb.Customer3_ChequeNo{
ChequeNo: "123XXXXXXX881",
},
},
wantErr: errUnknownField(
"testpb.Customer1",
8, 2),
},
{
name: "Any in a field, the extra field will be serialized so should fail",
in: &testpb.Customer2{
Miscellaneous: &anypb.Any{},
},
wantErr: errUnknownField(
"testpb.Customer1",
10,
2),
},
{
name: "With a nested struct as a field",
in: &testpb.Customer3{
Id: 289,
Original: &testpb.Customer1{
Id: 991,
},
},
wantErr: errUnknownField(
"testpb.Customer1",
9,
2),
},
{
name: "An extra field that's non-existent in Customer1",
in: &testpb.Customer2{
Id: 289,
Name: "Customer1",
Industry: 5299,
Fewer: 199.9,
},
wantErr: errUnknownField("testpb.Customer1", 4, 5),
},
{
name: "Using a field that's in the reserved range, should fail by default",
in: &testpb.Customer2{
Id: 289,
Reserved: 99,
},
wantErr: errUnknownField(
"testpb.Customer1",
1047,
0),
},
{
name: "Only fields matching",
in: &testpb.Customer2{
Id: 289,
Name: "CustomerCustomerCustomerCustomerCustomer11111Customer1",
},
// behavior change from previous implementation: we allow mismatched wire -> proto types.
// wantErr: errMismatchedField("testpb.Customer1", 4, 5),
},
{
name: "Extra field that's non-existent in Customer1, along with Reserved set",
in: &testpb.Customer2{
Id: 289,
Name: "Customer1",
Industry: 5299,
Fewer: 199.9,
Reserved: 819,
},
wantErr: errUnknownField("testpb.Customer1", 4, 5),
},
{
name: "Using enumerated field",
in: &testpb.Customer2{
Id: 289,
Name: "Customer1",
Industry: 5299,
City: testpb.Customer2_PaloAlto,
},
wantErr: errUnknownField("testpb.Customer1", 6, 0),
},
{
name: "multiple extraneous fields",
in: &testpb.Customer2{
Id: 289,
Name: "Customer1",
Industry: 5299,
City: testpb.Customer2_PaloAlto,
Fewer: 45,
},
wantErr: errUnknownField("testpb.Customer1", 4, 5),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
blob, err := proto.Marshal(tt.in)
if err != nil {
t.Fatalf("Failed to marshal input: %v", err)
}
c1 := new(testpb.Customer1)
c1Desc := c1.ProtoReflect().Descriptor()
//err = proto.Unmarshal(blob, c1)
//require.NoError(t, err)
gotErr := decode.RejectUnknownFieldsStrict(blob, c1Desc, ProtoResolver)
if tt.wantErr != nil {
require.EqualError(t, gotErr, tt.wantErr.Error())
} else {
require.NoError(t, gotErr)
}
})
}
}
// Issue https://github.com/cosmos/cosmos-sdk/issues/7222, we need to ensure that repeated
// uint64 are recognized as packed.
func TestPackedEncoding(t *testing.T) {
data := &testpb.TestRepeatedUints{Nums: []uint64{12, 13}}
marshalled, err := proto.Marshal(data)
require.NoError(t, err)
unmarshalled := data.ProtoReflect().Descriptor()
_, err = decode.RejectUnknownFields(marshalled, unmarshalled, false, ProtoResolver)
require.NoError(t, err)
}
func mustMarshal(msg proto.Message) []byte {
blob, err := proto.Marshal(msg)
if err != nil {
panic(err)
}
return blob
}

View File

@ -5,6 +5,7 @@ go 1.20
require (
cosmossdk.io/api v0.3.2-0.20230313131911-55bf5d4efbe7
cosmossdk.io/core v0.6.1
cosmossdk.io/errors v1.0.0-beta.7
cosmossdk.io/math v1.0.0
github.com/cosmos/cosmos-proto v1.0.0-beta.3
github.com/google/go-cmp v0.5.9

View File

@ -2,6 +2,8 @@ cosmossdk.io/api v0.3.2-0.20230313131911-55bf5d4efbe7 h1:4LrWK+uGP5IxznxtHHsHD+Z
cosmossdk.io/api v0.3.2-0.20230313131911-55bf5d4efbe7/go.mod h1:yVns7mKgcsG+hZW/3C5FdJtC6QYWdFIcRlKb9+5HV5g=
cosmossdk.io/core v0.6.1 h1:OBy7TI2W+/gyn2z40vVvruK3di+cAluinA6cybFbE7s=
cosmossdk.io/core v0.6.1/go.mod h1:g3MMBCBXtxbDWBURDVnJE7XML4BG5qENhs0gzkcpuFA=
cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w=
cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE=
cosmossdk.io/math v1.0.0 h1:ro9w7eKx23om2tZz/VM2Pf+z2WAbGX1yDQQOJ6iGeJw=
cosmossdk.io/math v1.0.0/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k=
github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o=

View File

@ -0,0 +1,306 @@
syntax = "proto3";
package testpb;
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "cosmos/tx/v1beta1/tx.proto";
message Customer1 {
int32 id = 1;
string name = 2;
float subscription_fee = 3;
string payment = 7;
}
message Customer2 {
int32 id = 1;
int32 industry = 2;
string name = 3;
float fewer = 4;
int64 reserved = 1047;
enum City {
Laos = 0;
LosAngeles = 1;
PaloAlto = 2;
Moscow = 3;
Nairobi = 4;
}
City city = 6;
google.protobuf.Any miscellaneous = 10;
}
message Nested4A {
int32 id = 1;
string name = 2;
}
message Nested3A {
int32 id = 1;
string name = 2;
repeated Nested4A a4 = 4;
map<int64, Nested4A> index = 5;
}
message Nested2A {
int32 id = 1;
string name = 2;
Nested3A nested = 3;
}
message Nested1A {
int32 id = 1;
Nested2A nested = 2;
}
message Nested4B {
int32 id = 1;
int32 age = 2;
string name = 3;
}
message Nested3B {
int32 id = 1;
int32 age = 2;
string name = 3;
repeated Nested4B b4 = 4;
}
message Nested2B {
int32 id = 1;
double fee = 2;
Nested3B nested = 3;
string route = 4;
}
message Nested1B {
int32 id = 1;
Nested2B nested = 2;
int32 age = 3;
}
message Customer3 {
int32 id = 1;
string name = 2;
float sf = 3;
float surcharge = 4;
string destination = 5;
oneof payment {
string credit_card_no = 7;
string cheque_no = 8;
}
Customer1 original = 9;
}
message TestVersion1 {
int64 x = 1;
TestVersion1 a = 2;
TestVersion1 b = 3; // [(gogoproto.nullable) = false] generates invalid recursive structs;
repeated TestVersion1 c = 4;
repeated TestVersion1 d = 5 [(gogoproto.nullable) = false];
oneof sum {
int32 e = 6;
TestVersion1 f = 7;
}
google.protobuf.Any g = 8;
repeated TestVersion1 h = 9; // [(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
}
message TestVersion2 {
int64 x = 1;
TestVersion2 a = 2;
TestVersion2 b = 3; // [(gogoproto.nullable) = false];
repeated TestVersion2 c = 4;
repeated TestVersion2 d = 5; // [(gogoproto.nullable) = false];
oneof sum {
int32 e = 6;
TestVersion2 f = 7;
}
google.protobuf.Any g = 8;
repeated TestVersion1 h = 9; // [(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
uint64 new_field = 25;
}
message TestVersion3 {
int64 x = 1;
TestVersion3 a = 2;
TestVersion3 b = 3; // [(gogoproto.nullable) = false];
repeated TestVersion3 c = 4;
repeated TestVersion3 d = 5; // [(gogoproto.nullable) = false];
oneof sum {
int32 e = 6;
TestVersion3 f = 7;
}
google.protobuf.Any g = 8;
repeated TestVersion1 h = 9; //[(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
string non_critical_field = 1031;
}
message TestVersion3LoneOneOfValue {
int64 x = 1;
TestVersion3 a = 2;
TestVersion3 b = 3; // [(gogoproto.nullable) = false];
repeated TestVersion3 c = 4;
repeated TestVersion3 d = 5; // [(gogoproto.nullable) = false];
oneof sum {
int32 e = 6;
}
google.protobuf.Any g = 8;
repeated TestVersion1 h = 9; //[(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
string non_critical_field = 1031;
}
message TestVersion3LoneNesting {
int64 x = 1;
TestVersion3 a = 2;
TestVersion3 b = 3; // [(gogoproto.nullable) = false];
repeated TestVersion3 c = 4;
repeated TestVersion3 d = 5; // [(gogoproto.nullable) = false];
oneof sum {
TestVersion3LoneNesting f = 7;
}
google.protobuf.Any g = 8;
repeated TestVersion1 h = 9; //[(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
string non_critical_field = 1031;
message Inner1 {
int64 id = 1;
string name = 2;
message InnerInner {
string id = 1;
string city = 2;
}
InnerInner inner = 3;
}
Inner1 inner1 = 14;
message Inner2 {
string id = 1;
string country = 2;
message InnerInner {
string id = 1;
string city = 2;
}
InnerInner inner = 3;
}
Inner2 inner2 = 15;
}
message TestVersion4LoneNesting {
int64 x = 1;
TestVersion3 a = 2;
TestVersion3 b = 3; // [(gogoproto.nullable) = false];
repeated TestVersion3 c = 4;
repeated TestVersion3 d = 5; // [(gogoproto.nullable) = false];
oneof sum {
TestVersion3LoneNesting f = 7;
}
google.protobuf.Any g = 8;
repeated TestVersion1 h = 9; //[(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
string non_critical_field = 1031;
message Inner1 {
int64 id = 1;
string name = 2;
message InnerInner {
int64 id = 1;
string city = 2;
}
InnerInner inner = 3;
}
Inner1 inner1 = 14;
message Inner2 {
string id = 1;
string country = 2;
message InnerInner {
string id = 1;
int64 value = 2;
}
InnerInner inner = 3;
}
Inner2 inner2 = 15;
}
message TestVersionFD1 {
int64 x = 1;
TestVersion1 a = 2;
oneof sum {
int32 e = 6;
TestVersion1 f = 7;
}
google.protobuf.Any g = 8;
repeated TestVersion1 h = 9; // [(gogoproto.castrepeated) = "TestVersion1"];
}
message TestVersionFD1WithExtraAny {
int64 x = 1;
TestVersion1 a = 2;
oneof sum {
int32 e = 6;
TestVersion1 f = 7;
}
AnyWithExtra g = 8;
repeated TestVersion1 h = 9; // [(gogoproto.castrepeated) = "TestVersion1"];
}
message AnyWithExtra {
google.protobuf.Any a = 1 [(gogoproto.embed) = true];
int64 b = 3;
int64 c = 4;
}
message TestUpdatedTxRaw {
bytes body_bytes = 1;
bytes auth_info_bytes = 2;
repeated bytes signatures = 3;
bytes new_field_5 = 5;
bytes new_field_1024 = 1024;
}
message TestUpdatedTxBody {
repeated google.protobuf.Any messages = 1;
string memo = 2;
int64 timeout_height = 3;
uint64 some_new_field = 4;
string some_new_field_non_critical_field = 1050;
repeated google.protobuf.Any extension_options = 1023;
repeated google.protobuf.Any non_critical_extension_options = 2047;
}
message TestUpdatedAuthInfo {
repeated cosmos.tx.v1beta1.SignerInfo signer_infos = 1;
cosmos.tx.v1beta1.Fee fee = 2;
bytes new_field_3 = 3;
bytes new_field_1024 = 1024;
}
message TestRepeatedUints {
repeated uint64 nums = 1;
}

File diff suppressed because it is too large Load Diff