From 8d367e6d9a5a2e4ac0928e79e0670df9dc259078 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Mon, 1 Jul 2024 21:09:46 +0700 Subject: [PATCH 01/39] add timestamp field --- api/cosmos/staking/v1beta1/query.pulsar.go | 6 +- api/cosmos/tx/v1beta1/tx.pulsar.go | 251 +++++++++++++++------ proto/cosmos/tx/v1beta1/tx.proto | 11 +- types/tx/tx.pb.go | 212 +++++++++++------ types/tx_msg.go | 10 + x/auth/ante/unordered.go | 36 ++- x/auth/ante/unorderedtx/manager.go | 4 + x/auth/tx/gogotx.go | 6 + x/staking/types/query.pb.go | 6 +- 9 files changed, 382 insertions(+), 160 deletions(-) diff --git a/api/cosmos/staking/v1beta1/query.pulsar.go b/api/cosmos/staking/v1beta1/query.pulsar.go index 4fa56617ac6b..5d38e7fac5e7 100644 --- a/api/cosmos/staking/v1beta1/query.pulsar.go +++ b/api/cosmos/staking/v1beta1/query.pulsar.go @@ -14421,7 +14421,11 @@ type QueryValidatorsResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Validators []*Validator `protobuf:"bytes,1,rep,name=validators,proto3" json:"validators,omitempty"` + Validators []*Validator `protobuf:"bytes,1,rep,name=validators,proto3" json:"validators,omitempty"` + // validator_info contains additional information for each validator. + // The order of the elements in this list corresponds to the order of the elements in the validators list. + // For example, if you want the ValidatorInfo for the third validator in the validators list, + // you should look at the third element in the validator_info list. ValidatorInfo []*ValidatorInfo `protobuf:"bytes,2,rep,name=validator_info,json=validatorInfo,proto3" json:"validator_info,omitempty"` Pagination *v1beta1.PageResponse `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` } diff --git a/api/cosmos/tx/v1beta1/tx.pulsar.go b/api/cosmos/tx/v1beta1/tx.pulsar.go index 56ea5057518a..a5eda20d225e 100644 --- a/api/cosmos/tx/v1beta1/tx.pulsar.go +++ b/api/cosmos/tx/v1beta1/tx.pulsar.go @@ -14,6 +14,7 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" io "io" reflect "reflect" sync "sync" @@ -2768,6 +2769,7 @@ var ( fd_TxBody_memo protoreflect.FieldDescriptor fd_TxBody_timeout_height protoreflect.FieldDescriptor fd_TxBody_unordered protoreflect.FieldDescriptor + fd_TxBody_timeout_timestamp protoreflect.FieldDescriptor fd_TxBody_extension_options protoreflect.FieldDescriptor fd_TxBody_non_critical_extension_options protoreflect.FieldDescriptor ) @@ -2779,6 +2781,7 @@ func init() { fd_TxBody_memo = md_TxBody.Fields().ByName("memo") fd_TxBody_timeout_height = md_TxBody.Fields().ByName("timeout_height") fd_TxBody_unordered = md_TxBody.Fields().ByName("unordered") + fd_TxBody_timeout_timestamp = md_TxBody.Fields().ByName("timeout_timestamp") fd_TxBody_extension_options = md_TxBody.Fields().ByName("extension_options") fd_TxBody_non_critical_extension_options = md_TxBody.Fields().ByName("non_critical_extension_options") } @@ -2872,6 +2875,12 @@ func (x *fastReflection_TxBody) Range(f func(protoreflect.FieldDescriptor, proto return } } + if x.TimeoutTimestamp != nil { + value := protoreflect.ValueOfMessage(x.TimeoutTimestamp.ProtoReflect()) + if !f(fd_TxBody_timeout_timestamp, value) { + return + } + } if len(x.ExtensionOptions) != 0 { value := protoreflect.ValueOfList(&_TxBody_1023_list{list: &x.ExtensionOptions}) if !f(fd_TxBody_extension_options, value) { @@ -2907,6 +2916,8 @@ func (x *fastReflection_TxBody) Has(fd protoreflect.FieldDescriptor) bool { return x.TimeoutHeight != uint64(0) case "cosmos.tx.v1beta1.TxBody.unordered": return x.Unordered != false + case "cosmos.tx.v1beta1.TxBody.timeout_timestamp": + return x.TimeoutTimestamp != nil case "cosmos.tx.v1beta1.TxBody.extension_options": return len(x.ExtensionOptions) != 0 case "cosmos.tx.v1beta1.TxBody.non_critical_extension_options": @@ -2935,6 +2946,8 @@ func (x *fastReflection_TxBody) Clear(fd protoreflect.FieldDescriptor) { x.TimeoutHeight = uint64(0) case "cosmos.tx.v1beta1.TxBody.unordered": x.Unordered = false + case "cosmos.tx.v1beta1.TxBody.timeout_timestamp": + x.TimeoutTimestamp = nil case "cosmos.tx.v1beta1.TxBody.extension_options": x.ExtensionOptions = nil case "cosmos.tx.v1beta1.TxBody.non_critical_extension_options": @@ -2970,6 +2983,9 @@ func (x *fastReflection_TxBody) Get(descriptor protoreflect.FieldDescriptor) pro case "cosmos.tx.v1beta1.TxBody.unordered": value := x.Unordered return protoreflect.ValueOfBool(value) + case "cosmos.tx.v1beta1.TxBody.timeout_timestamp": + value := x.TimeoutTimestamp + return protoreflect.ValueOfMessage(value.ProtoReflect()) case "cosmos.tx.v1beta1.TxBody.extension_options": if len(x.ExtensionOptions) == 0 { return protoreflect.ValueOfList(&_TxBody_1023_list{}) @@ -3012,6 +3028,8 @@ func (x *fastReflection_TxBody) Set(fd protoreflect.FieldDescriptor, value proto x.TimeoutHeight = value.Uint() case "cosmos.tx.v1beta1.TxBody.unordered": x.Unordered = value.Bool() + case "cosmos.tx.v1beta1.TxBody.timeout_timestamp": + x.TimeoutTimestamp = value.Message().Interface().(*timestamppb.Timestamp) case "cosmos.tx.v1beta1.TxBody.extension_options": lv := value.List() clv := lv.(*_TxBody_1023_list) @@ -3046,6 +3064,11 @@ func (x *fastReflection_TxBody) Mutable(fd protoreflect.FieldDescriptor) protore } value := &_TxBody_1_list{list: &x.Messages} return protoreflect.ValueOfList(value) + case "cosmos.tx.v1beta1.TxBody.timeout_timestamp": + if x.TimeoutTimestamp == nil { + x.TimeoutTimestamp = new(timestamppb.Timestamp) + } + return protoreflect.ValueOfMessage(x.TimeoutTimestamp.ProtoReflect()) case "cosmos.tx.v1beta1.TxBody.extension_options": if x.ExtensionOptions == nil { x.ExtensionOptions = []*anypb.Any{} @@ -3086,6 +3109,9 @@ func (x *fastReflection_TxBody) NewField(fd protoreflect.FieldDescriptor) protor return protoreflect.ValueOfUint64(uint64(0)) case "cosmos.tx.v1beta1.TxBody.unordered": return protoreflect.ValueOfBool(false) + case "cosmos.tx.v1beta1.TxBody.timeout_timestamp": + m := new(timestamppb.Timestamp) + return protoreflect.ValueOfMessage(m.ProtoReflect()) case "cosmos.tx.v1beta1.TxBody.extension_options": list := []*anypb.Any{} return protoreflect.ValueOfList(&_TxBody_1023_list{list: &list}) @@ -3177,6 +3203,10 @@ func (x *fastReflection_TxBody) ProtoMethods() *protoiface.Methods { if x.Unordered { n += 2 } + if x.TimeoutTimestamp != nil { + l = options.Size(x.TimeoutTimestamp) + n += 1 + l + runtime.Sov(uint64(l)) + } if len(x.ExtensionOptions) > 0 { for _, e := range x.ExtensionOptions { l = options.Size(e) @@ -3254,6 +3284,20 @@ func (x *fastReflection_TxBody) ProtoMethods() *protoiface.Methods { dAtA[i] = 0xfa } } + if x.TimeoutTimestamp != nil { + encoded, err := options.Marshal(x.TimeoutTimestamp) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x2a + } if x.Unordered { i-- if x.Unordered { @@ -3446,6 +3490,42 @@ func (x *fastReflection_TxBody) ProtoMethods() *protoiface.Methods { } } x.Unordered = bool(v != 0) + case 5: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field TimeoutTimestamp", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if x.TimeoutTimestamp == nil { + x.TimeoutTimestamp = ×tamppb.Timestamp{} + } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.TimeoutTimestamp); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex case 1023: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ExtensionOptions", wireType) @@ -8486,6 +8566,13 @@ type TxBody struct { // will be used to correspond to a height in which the transaction is deemed // valid. Unordered bool `protobuf:"varint,4,opt,name=unordered,proto3" json:"unordered,omitempty"` + // timeout_timestamp is the block time after which this transaction will not + // be processed by the chain. + // + // Note, if unordered=true this value MUST be set + // and will act as a short-lived TTL in which the transaction is deemed valid + // and kept in memory to prevent duplicates. + TimeoutTimestamp *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3" json:"timeout_timestamp,omitempty"` // extension_options are arbitrary options that can be added by chains // when the default options are not sufficient. If any of these are present // and can't be handled, the transaction will be rejected @@ -8544,6 +8631,13 @@ func (x *TxBody) GetUnordered() bool { return false } +func (x *TxBody) GetTimeoutTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.TimeoutTimestamp + } + return nil +} + func (x *TxBody) GetExtensionOptions() []*anypb.Any { if x != nil { return x.ExtensionOptions @@ -9059,58 +9153,65 @@ var file_cosmos_tx_v1beta1_tx_proto_rawDesc = []byte{ 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8d, 0x01, 0x0a, 0x02, 0x54, 0x78, 0x12, 0x2d, 0x0a, - 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x54, 0x78, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x38, 0x0a, 0x09, - 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x61, 0x75, - 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x6e, 0x0a, 0x05, 0x54, 0x78, 0x52, 0x61, 0x77, 0x12, - 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x26, - 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, - 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x07, 0x53, 0x69, 0x67, 0x6e, 0x44, - 0x6f, 0x63, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, 0x65, - 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x62, - 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, - 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x87, 0x02, 0x0a, 0x10, - 0x53, 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x41, 0x75, 0x78, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8d, 0x01, 0x0a, 0x02, 0x54, 0x78, 0x12, 0x2d, + 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x54, 0x78, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x38, 0x0a, + 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x61, + 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x6e, 0x0a, 0x05, 0x54, 0x78, 0x52, 0x61, 0x77, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, - 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, - 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x03, 0x74, 0x69, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2e, 0x54, 0x69, 0x70, 0x42, 0x02, 0x18, 0x01, 0x52, 0x03, 0x74, 0x69, 0x70, - 0x3a, 0x13, 0xd2, 0xb4, 0x2d, 0x0f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, - 0x20, 0x30, 0x2e, 0x34, 0x36, 0x22, 0xb3, 0x02, 0x0a, 0x06, 0x54, 0x78, 0x42, 0x6f, 0x64, 0x79, - 0x12, 0x30, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, - 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, - 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1c, 0x0a, - 0x09, 0x75, 0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x75, 0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x12, 0x42, 0x0a, 0x11, 0x65, + 0x26, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x62, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x49, 0x6e, + 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x07, 0x53, 0x69, 0x67, 0x6e, + 0x44, 0x6f, 0x63, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74, + 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x87, 0x02, 0x0a, + 0x10, 0x53, 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x41, 0x75, + 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, + 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x03, 0x74, 0x69, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x69, 0x70, 0x42, 0x02, 0x18, 0x01, 0x52, 0x03, 0x74, 0x69, + 0x70, 0x3a, 0x13, 0xd2, 0xb4, 0x2d, 0x0f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, + 0x6b, 0x20, 0x30, 0x2e, 0x34, 0x36, 0x22, 0x82, 0x03, 0x0a, 0x06, 0x54, 0x78, 0x42, 0x6f, 0x64, + 0x79, 0x12, 0x30, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x75, 0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x09, 0x75, 0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x12, 0x4d, 0x0a, 0x11, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x42, 0x04, 0x90, 0xdf, 0x1f, 0x01, 0x52, 0x10, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x42, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xff, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x10, 0x65, @@ -9250,9 +9351,10 @@ var file_cosmos_tx_v1beta1_tx_proto_goTypes = []interface{}{ (*ModeInfo_Single)(nil), // 11: cosmos.tx.v1beta1.ModeInfo.Single (*ModeInfo_Multi)(nil), // 12: cosmos.tx.v1beta1.ModeInfo.Multi (*anypb.Any)(nil), // 13: google.protobuf.Any - (*v1beta12.Coin)(nil), // 14: cosmos.base.v1beta1.Coin - (v1beta1.SignMode)(0), // 15: cosmos.tx.signing.v1beta1.SignMode - (*v1beta11.CompactBitArray)(nil), // 16: cosmos.crypto.multisig.v1beta1.CompactBitArray + (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp + (*v1beta12.Coin)(nil), // 15: cosmos.base.v1beta1.Coin + (v1beta1.SignMode)(0), // 16: cosmos.tx.signing.v1beta1.SignMode + (*v1beta11.CompactBitArray)(nil), // 17: cosmos.crypto.multisig.v1beta1.CompactBitArray } var file_cosmos_tx_v1beta1_tx_proto_depIdxs = []int32{ 4, // 0: cosmos.tx.v1beta1.Tx.body:type_name -> cosmos.tx.v1beta1.TxBody @@ -9260,27 +9362,28 @@ var file_cosmos_tx_v1beta1_tx_proto_depIdxs = []int32{ 13, // 2: cosmos.tx.v1beta1.SignDocDirectAux.public_key:type_name -> google.protobuf.Any 9, // 3: cosmos.tx.v1beta1.SignDocDirectAux.tip:type_name -> cosmos.tx.v1beta1.Tip 13, // 4: cosmos.tx.v1beta1.TxBody.messages:type_name -> google.protobuf.Any - 13, // 5: cosmos.tx.v1beta1.TxBody.extension_options:type_name -> google.protobuf.Any - 13, // 6: cosmos.tx.v1beta1.TxBody.non_critical_extension_options:type_name -> google.protobuf.Any - 6, // 7: cosmos.tx.v1beta1.AuthInfo.signer_infos:type_name -> cosmos.tx.v1beta1.SignerInfo - 8, // 8: cosmos.tx.v1beta1.AuthInfo.fee:type_name -> cosmos.tx.v1beta1.Fee - 9, // 9: cosmos.tx.v1beta1.AuthInfo.tip:type_name -> cosmos.tx.v1beta1.Tip - 13, // 10: cosmos.tx.v1beta1.SignerInfo.public_key:type_name -> google.protobuf.Any - 7, // 11: cosmos.tx.v1beta1.SignerInfo.mode_info:type_name -> cosmos.tx.v1beta1.ModeInfo - 11, // 12: cosmos.tx.v1beta1.ModeInfo.single:type_name -> cosmos.tx.v1beta1.ModeInfo.Single - 12, // 13: cosmos.tx.v1beta1.ModeInfo.multi:type_name -> cosmos.tx.v1beta1.ModeInfo.Multi - 14, // 14: cosmos.tx.v1beta1.Fee.amount:type_name -> cosmos.base.v1beta1.Coin - 14, // 15: cosmos.tx.v1beta1.Tip.amount:type_name -> cosmos.base.v1beta1.Coin - 3, // 16: cosmos.tx.v1beta1.AuxSignerData.sign_doc:type_name -> cosmos.tx.v1beta1.SignDocDirectAux - 15, // 17: cosmos.tx.v1beta1.AuxSignerData.mode:type_name -> cosmos.tx.signing.v1beta1.SignMode - 15, // 18: cosmos.tx.v1beta1.ModeInfo.Single.mode:type_name -> cosmos.tx.signing.v1beta1.SignMode - 16, // 19: cosmos.tx.v1beta1.ModeInfo.Multi.bitarray:type_name -> cosmos.crypto.multisig.v1beta1.CompactBitArray - 7, // 20: cosmos.tx.v1beta1.ModeInfo.Multi.mode_infos:type_name -> cosmos.tx.v1beta1.ModeInfo - 21, // [21:21] is the sub-list for method output_type - 21, // [21:21] is the sub-list for method input_type - 21, // [21:21] is the sub-list for extension type_name - 21, // [21:21] is the sub-list for extension extendee - 0, // [0:21] is the sub-list for field type_name + 14, // 5: cosmos.tx.v1beta1.TxBody.timeout_timestamp:type_name -> google.protobuf.Timestamp + 13, // 6: cosmos.tx.v1beta1.TxBody.extension_options:type_name -> google.protobuf.Any + 13, // 7: cosmos.tx.v1beta1.TxBody.non_critical_extension_options:type_name -> google.protobuf.Any + 6, // 8: cosmos.tx.v1beta1.AuthInfo.signer_infos:type_name -> cosmos.tx.v1beta1.SignerInfo + 8, // 9: cosmos.tx.v1beta1.AuthInfo.fee:type_name -> cosmos.tx.v1beta1.Fee + 9, // 10: cosmos.tx.v1beta1.AuthInfo.tip:type_name -> cosmos.tx.v1beta1.Tip + 13, // 11: cosmos.tx.v1beta1.SignerInfo.public_key:type_name -> google.protobuf.Any + 7, // 12: cosmos.tx.v1beta1.SignerInfo.mode_info:type_name -> cosmos.tx.v1beta1.ModeInfo + 11, // 13: cosmos.tx.v1beta1.ModeInfo.single:type_name -> cosmos.tx.v1beta1.ModeInfo.Single + 12, // 14: cosmos.tx.v1beta1.ModeInfo.multi:type_name -> cosmos.tx.v1beta1.ModeInfo.Multi + 15, // 15: cosmos.tx.v1beta1.Fee.amount:type_name -> cosmos.base.v1beta1.Coin + 15, // 16: cosmos.tx.v1beta1.Tip.amount:type_name -> cosmos.base.v1beta1.Coin + 3, // 17: cosmos.tx.v1beta1.AuxSignerData.sign_doc:type_name -> cosmos.tx.v1beta1.SignDocDirectAux + 16, // 18: cosmos.tx.v1beta1.AuxSignerData.mode:type_name -> cosmos.tx.signing.v1beta1.SignMode + 16, // 19: cosmos.tx.v1beta1.ModeInfo.Single.mode:type_name -> cosmos.tx.signing.v1beta1.SignMode + 17, // 20: cosmos.tx.v1beta1.ModeInfo.Multi.bitarray:type_name -> cosmos.crypto.multisig.v1beta1.CompactBitArray + 7, // 21: cosmos.tx.v1beta1.ModeInfo.Multi.mode_infos:type_name -> cosmos.tx.v1beta1.ModeInfo + 22, // [22:22] is the sub-list for method output_type + 22, // [22:22] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name } func init() { file_cosmos_tx_v1beta1_tx_proto_init() } diff --git a/proto/cosmos/tx/v1beta1/tx.proto b/proto/cosmos/tx/v1beta1/tx.proto index b1c45f8063bc..7a015f1cc7f2 100644 --- a/proto/cosmos/tx/v1beta1/tx.proto +++ b/proto/cosmos/tx/v1beta1/tx.proto @@ -8,6 +8,7 @@ import "cosmos/crypto/multisig/v1beta1/multisig.proto"; import "cosmos/base/v1beta1/coin.proto"; import "cosmos/tx/signing/v1beta1/signing.proto"; import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; option go_package = "github.com/cosmos/cosmos-sdk/types/tx"; @@ -122,11 +123,19 @@ message TxBody { // incremented, which allows for fire-and-forget as well as concurrent // transaction execution. // - // Note, when set to true, the existing 'timeout_height' value must be set and + // Note, when set to true, the existing 'timeout_height' or 'timeout_timestamp' value must be set and // will be used to correspond to a height in which the transaction is deemed // valid. bool unordered = 4; + // timeout_timestamp is the block time after which this transaction will not + // be processed by the chain. + // + // Note, if unordered=true this value MUST be set + // and will act as a short-lived TTL in which the transaction is deemed valid + // and kept in memory to prevent duplicates. + google.protobuf.Timestamp timeout_timestamp = 5 [(gogoproto.stdtime) = true]; + // extension_options are arbitrary options that can be added by chains // when the default options are not sufficient. If any of these are present // and can't be handled, the transaction will be rejected diff --git a/types/tx/tx.pb.go b/types/tx/tx.pb.go index f0230d462abb..363d6086469e 100644 --- a/types/tx/tx.pb.go +++ b/types/tx/tx.pb.go @@ -13,16 +13,20 @@ import ( signing "github.com/cosmos/cosmos-sdk/types/tx/signing" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" + github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" any "github.com/cosmos/gogoproto/types/any" + _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" math_bits "math/bits" + time "time" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf +var _ = time.Kitchen // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. @@ -374,6 +378,13 @@ type TxBody struct { // will be used to correspond to a height in which the transaction is deemed // valid. Unordered bool `protobuf:"varint,4,opt,name=unordered,proto3" json:"unordered,omitempty"` + // timeout_timestamp is the block time after which this transaction will not + // be processed by the chain. + // + // Note, if unordered=true this value MUST be set + // and will act as a short-lived TTL in which the transaction is deemed valid + // and kept in memory to prevent duplicates. + TimeoutTimestamp *time.Time `protobuf:"bytes,5,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3,stdtime" json:"timeout_timestamp,omitempty"` // extension_options are arbitrary options that can be added by chains // when the default options are not sufficient. If any of these are present // and can't be handled, the transaction will be rejected @@ -445,6 +456,13 @@ func (m *TxBody) GetUnordered() bool { return false } +func (m *TxBody) GetTimeoutTimestamp() *time.Time { + if m != nil { + return m.TimeoutTimestamp + } + return nil +} + func (m *TxBody) GetExtensionOptions() []*any.Any { if m != nil { return m.ExtensionOptions @@ -1036,77 +1054,79 @@ func init() { func init() { proto.RegisterFile("cosmos/tx/v1beta1/tx.proto", fileDescriptor_96d1575ffde80842) } var fileDescriptor_96d1575ffde80842 = []byte{ - // 1106 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0xcf, 0x6f, 0x1b, 0xc5, - 0x17, 0xf7, 0x7a, 0x6d, 0xc7, 0x7e, 0x4d, 0xfa, 0x63, 0xbe, 0xed, 0x57, 0x8e, 0x4b, 0xdd, 0xe0, - 0xaa, 0x60, 0x55, 0x64, 0xb7, 0x4d, 0x11, 0x94, 0x08, 0x51, 0xec, 0x86, 0x28, 0x55, 0x29, 0x48, - 0x9b, 0x9c, 0x7a, 0x59, 0x8d, 0x77, 0x27, 0xeb, 0x51, 0xbd, 0x33, 0xcb, 0xce, 0x2c, 0x78, 0x8f, - 0x9c, 0x38, 0x21, 0x55, 0x5c, 0x90, 0xf8, 0x0b, 0x10, 0xa7, 0x4a, 0x54, 0xe2, 0x5f, 0x28, 0xb7, - 0x2a, 0x27, 0xc4, 0x01, 0xaa, 0xe4, 0xd0, 0x3f, 0x03, 0xb4, 0xb3, 0xb3, 0x9b, 0xb4, 0x75, 0x1d, - 0x10, 0x48, 0x5c, 0x56, 0x33, 0x6f, 0x3f, 0xef, 0xcd, 0x67, 0xde, 0xfb, 0xcc, 0x7b, 0xd0, 0xf1, - 0xb8, 0x08, 0xb9, 0xb0, 0xe5, 0xd4, 0xfe, 0xfc, 0xda, 0x88, 0x48, 0x7c, 0xcd, 0x96, 0x53, 0x2b, - 0x8a, 0xb9, 0xe4, 0xe8, 0x4c, 0xfe, 0xcf, 0x92, 0x53, 0x4b, 0xff, 0xeb, 0x2c, 0xe7, 0x26, 0x57, - 0x01, 0x6c, 0xfd, 0x5f, 0x6d, 0x3a, 0x67, 0x70, 0x48, 0x19, 0xb7, 0xd5, 0x57, 0x9b, 0xce, 0x06, - 0x3c, 0xe0, 0x39, 0x34, 0x5b, 0x69, 0xeb, 0xaa, 0x3e, 0xd2, 0x8b, 0xd3, 0x48, 0x72, 0x3b, 0x4c, - 0x26, 0x92, 0x0a, 0x1a, 0x94, 0xe7, 0x17, 0x06, 0x0d, 0xef, 0x6a, 0xf8, 0x08, 0x0b, 0x52, 0x62, - 0x3c, 0x4e, 0x99, 0xfe, 0xff, 0xe6, 0xe1, 0x0d, 0x04, 0x0d, 0x18, 0x65, 0x87, 0x91, 0xf4, 0x5e, - 0x03, 0x97, 0x03, 0xce, 0x83, 0x09, 0xb1, 0xd5, 0x6e, 0x94, 0xec, 0xda, 0x98, 0xa5, 0xf9, 0xaf, - 0xde, 0xd7, 0x06, 0x54, 0x77, 0xa6, 0x68, 0x15, 0x6a, 0x23, 0xee, 0xa7, 0x6d, 0x63, 0xc5, 0xe8, - 0x9f, 0x58, 0x5b, 0xb6, 0x5e, 0xba, 0xbf, 0xb5, 0x33, 0x1d, 0x72, 0x3f, 0x75, 0x14, 0x0c, 0xdd, - 0x80, 0x16, 0x4e, 0xe4, 0xd8, 0xa5, 0x6c, 0x97, 0xb7, 0xab, 0xca, 0xe7, 0xfc, 0x0c, 0x9f, 0x41, - 0x22, 0xc7, 0xb7, 0xd9, 0x2e, 0x77, 0x9a, 0x58, 0xaf, 0x50, 0x17, 0x20, 0xe3, 0x86, 0x65, 0x12, - 0x13, 0xd1, 0x36, 0x57, 0xcc, 0xfe, 0xa2, 0x73, 0xc4, 0xd2, 0x63, 0x50, 0xdf, 0x99, 0x3a, 0xf8, - 0x0b, 0x74, 0x01, 0x20, 0x3b, 0xca, 0x1d, 0xa5, 0x92, 0x08, 0xc5, 0x6b, 0xd1, 0x69, 0x65, 0x96, - 0x61, 0x66, 0x40, 0x6f, 0xc0, 0xa9, 0x92, 0x81, 0xc6, 0x54, 0x15, 0x66, 0xa9, 0x38, 0x2a, 0xc7, - 0x1d, 0x77, 0xde, 0x37, 0x06, 0x2c, 0x6c, 0xd3, 0x80, 0x6d, 0x70, 0xef, 0xdf, 0x3a, 0x72, 0x19, - 0x9a, 0xde, 0x18, 0x53, 0xe6, 0x52, 0xbf, 0x6d, 0xae, 0x18, 0xfd, 0x96, 0xb3, 0xa0, 0xf6, 0xb7, - 0x7d, 0x74, 0x19, 0x4e, 0x62, 0xcf, 0xe3, 0x09, 0x93, 0x2e, 0x4b, 0xc2, 0x11, 0x89, 0xdb, 0xb5, - 0x15, 0xa3, 0x5f, 0x73, 0x96, 0xb4, 0xf5, 0x13, 0x65, 0xec, 0x7d, 0x55, 0x85, 0xd3, 0x9a, 0xd4, - 0x06, 0x8d, 0x89, 0x27, 0x07, 0xc9, 0xf4, 0x38, 0x76, 0xd7, 0x01, 0xa2, 0x64, 0x34, 0xa1, 0x9e, - 0x7b, 0x9f, 0xa4, 0xba, 0x26, 0x67, 0xad, 0xbc, 0xf0, 0x56, 0x51, 0x78, 0x6b, 0xc0, 0x52, 0xa7, - 0x95, 0xe3, 0xee, 0x90, 0xf4, 0x9f, 0x53, 0x45, 0x1d, 0x68, 0x0a, 0xf2, 0x59, 0x42, 0x98, 0x47, - 0xda, 0x75, 0x05, 0x28, 0xf7, 0xe8, 0x2d, 0x30, 0x25, 0x8d, 0xda, 0x0d, 0xc5, 0xe5, 0xff, 0xb3, - 0x34, 0x45, 0xa3, 0x61, 0xb5, 0x6d, 0x38, 0x19, 0x6c, 0xfd, 0x7f, 0x7b, 0x8f, 0x56, 0x4f, 0xe5, - 0x98, 0x55, 0xe1, 0xdf, 0x5f, 0xb9, 0x6a, 0xbd, 0xfd, 0x4e, 0xef, 0xc7, 0x2a, 0x34, 0x72, 0xe5, - 0xa1, 0xab, 0xd0, 0x0c, 0x89, 0x10, 0x38, 0x50, 0xb7, 0x37, 0x5f, 0x79, 0xbd, 0x12, 0x85, 0x10, - 0xd4, 0x42, 0x12, 0xe6, 0x02, 0x6d, 0x39, 0x6a, 0x9d, 0x5d, 0x4b, 0xd2, 0x90, 0xf0, 0x44, 0xba, - 0x63, 0x42, 0x83, 0xb1, 0x54, 0xf7, 0xae, 0x39, 0x4b, 0xda, 0xba, 0xa5, 0x8c, 0xe8, 0x35, 0x68, - 0x25, 0x8c, 0xc7, 0x3e, 0x89, 0x89, 0xaf, 0x2e, 0xde, 0x74, 0x0e, 0x0d, 0x68, 0x08, 0x67, 0xc8, - 0x54, 0x12, 0x26, 0x28, 0x67, 0x2e, 0x8f, 0x24, 0xe5, 0x4c, 0xb4, 0xff, 0x58, 0x98, 0x43, 0xea, - 0x74, 0x89, 0xff, 0x34, 0x87, 0xa3, 0x7b, 0xd0, 0x65, 0x9c, 0xb9, 0x5e, 0x4c, 0x25, 0xf5, 0xf0, - 0xc4, 0x9d, 0x11, 0xf0, 0xd4, 0x9c, 0x80, 0xe7, 0x19, 0x67, 0xb7, 0xb4, 0xef, 0x47, 0x2f, 0xc4, - 0xee, 0xfd, 0x64, 0x40, 0xb3, 0x78, 0x7b, 0xe8, 0x43, 0x58, 0xcc, 0xf4, 0x4e, 0x62, 0x25, 0xdc, - 0x22, 0x77, 0x17, 0x66, 0x94, 0x63, 0x5b, 0xc1, 0xd4, 0x83, 0x3d, 0x21, 0xca, 0xb5, 0x40, 0x7d, - 0x30, 0x77, 0x09, 0xd1, 0x9a, 0x9a, 0x55, 0xc7, 0x4d, 0x42, 0x9c, 0x0c, 0x82, 0x6e, 0xe6, 0x15, - 0x37, 0xe7, 0x56, 0xfc, 0xdc, 0xaf, 0x2f, 0x17, 0x5a, 0x8b, 0xa0, 0xf7, 0xad, 0x01, 0x70, 0x48, - 0xe3, 0x05, 0x51, 0x1b, 0x7f, 0x4d, 0xd4, 0x37, 0xa0, 0x15, 0x72, 0x9f, 0x1c, 0xd7, 0x9c, 0xee, - 0x72, 0x9f, 0xe4, 0xcd, 0x29, 0xd4, 0xab, 0xe7, 0xc4, 0x6c, 0x3e, 0x2f, 0xe6, 0xde, 0xd3, 0x2a, - 0x34, 0x0b, 0x17, 0xf4, 0x3e, 0x34, 0x04, 0x65, 0xc1, 0x84, 0x68, 0x4e, 0xbd, 0x39, 0xf1, 0xad, - 0x6d, 0x85, 0xdc, 0xaa, 0x38, 0xda, 0x07, 0xbd, 0x07, 0x75, 0xd5, 0xe9, 0x35, 0xb9, 0xd7, 0xe7, - 0x39, 0xdf, 0xcd, 0x80, 0x5b, 0x15, 0x27, 0xf7, 0xe8, 0x0c, 0xa0, 0x91, 0x87, 0x43, 0xef, 0x42, - 0x2d, 0xe3, 0xad, 0x08, 0x9c, 0x5c, 0xbb, 0x74, 0x24, 0x46, 0xd1, 0xfb, 0x8f, 0x96, 0x35, 0x8b, - 0xe7, 0x28, 0x87, 0xce, 0x03, 0x03, 0xea, 0x2a, 0x2a, 0xba, 0x03, 0xcd, 0x11, 0x95, 0x38, 0x8e, - 0x71, 0x91, 0x5b, 0xbb, 0x08, 0x93, 0x4f, 0x28, 0xab, 0x1c, 0x48, 0x45, 0xac, 0x5b, 0x3c, 0x8c, - 0xb0, 0x27, 0x87, 0x54, 0x0e, 0x32, 0x37, 0xa7, 0x0c, 0x80, 0xd6, 0x01, 0xca, 0xac, 0x67, 0x8d, - 0xd1, 0x3c, 0x2e, 0xed, 0xad, 0x22, 0xed, 0x62, 0x58, 0x07, 0x53, 0x24, 0x61, 0xef, 0xcb, 0x2a, - 0x98, 0x9b, 0x84, 0xa0, 0x14, 0x1a, 0x38, 0xcc, 0x7a, 0x8c, 0xd6, 0x6a, 0x39, 0x8e, 0xb2, 0x41, - 0x78, 0x84, 0x0a, 0x65, 0xc3, 0xcd, 0xc7, 0xbf, 0x5d, 0xac, 0xfc, 0xf0, 0xfb, 0xc5, 0x7e, 0x40, - 0xe5, 0x38, 0x19, 0x59, 0x1e, 0x0f, 0xed, 0x62, 0xc8, 0x96, 0x0a, 0xb3, 0x65, 0x1a, 0x11, 0xa1, - 0x1c, 0xc4, 0x77, 0xcf, 0x1e, 0x5e, 0x59, 0x9c, 0x90, 0x00, 0x7b, 0xa9, 0x9b, 0x8d, 0x52, 0xf1, - 0xfd, 0xb3, 0x87, 0x57, 0x0c, 0x47, 0x1f, 0x88, 0xce, 0x43, 0x2b, 0xc0, 0xc2, 0x9d, 0xd0, 0x90, - 0x4a, 0x55, 0x9e, 0x9a, 0xd3, 0x0c, 0xb0, 0xf8, 0x38, 0xdb, 0x23, 0x0b, 0xea, 0x11, 0x4e, 0x49, - 0x9c, 0xb7, 0xca, 0x61, 0x7b, 0xef, 0xd1, 0xea, 0x59, 0xcd, 0x6c, 0xe0, 0xfb, 0x31, 0x11, 0x62, - 0x5b, 0xc6, 0x94, 0x05, 0x4e, 0x0e, 0x43, 0x6b, 0xb0, 0x10, 0xc4, 0x98, 0x49, 0xdd, 0x3b, 0xe7, - 0x79, 0x14, 0xc0, 0xde, 0xcf, 0x06, 0x98, 0x3b, 0x34, 0xfa, 0x2f, 0x73, 0x70, 0x15, 0x1a, 0x92, - 0x46, 0x11, 0x89, 0xf3, 0xc6, 0x39, 0x87, 0xb5, 0xc6, 0xad, 0x9f, 0xdb, 0x9b, 0xf5, 0xa2, 0x7b, - 0x07, 0x06, 0x2c, 0x0d, 0x92, 0x69, 0xfe, 0x9e, 0x37, 0xb0, 0xc4, 0x59, 0x46, 0x70, 0x1e, 0x41, - 0x09, 0x6e, 0x6e, 0x46, 0x34, 0x10, 0x7d, 0x00, 0xcd, 0x4c, 0xd1, 0xae, 0xcf, 0x3d, 0xfd, 0x60, - 0x2e, 0xbd, 0xa2, 0x77, 0x1d, 0x1d, 0x97, 0xce, 0x82, 0xd0, 0x53, 0xbd, 0x78, 0x28, 0xe6, 0xdf, - 0x7c, 0x28, 0xe8, 0x34, 0x98, 0x82, 0x06, 0xaa, 0x74, 0x8b, 0x4e, 0xb6, 0x9c, 0x39, 0xa2, 0x86, - 0x37, 0x1f, 0xef, 0x77, 0x8d, 0x27, 0xfb, 0x5d, 0xe3, 0xe9, 0x7e, 0xd7, 0x78, 0x70, 0xd0, 0xad, - 0x3c, 0x39, 0xe8, 0x56, 0x7e, 0x39, 0xe8, 0x56, 0xee, 0x5d, 0x3e, 0xbe, 0x20, 0xb6, 0x9c, 0x8e, - 0x1a, 0xaa, 0x91, 0x5d, 0xff, 0x33, 0x00, 0x00, 0xff, 0xff, 0x6d, 0xc2, 0x59, 0x2a, 0x91, 0x0a, - 0x00, 0x00, + // 1143 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xf7, 0x7a, 0x6d, 0xc7, 0x7e, 0x4d, 0xda, 0x64, 0x68, 0x91, 0xe3, 0x52, 0x27, 0xb8, 0x2a, + 0x58, 0x15, 0xd9, 0x6d, 0x53, 0x04, 0xa5, 0x42, 0x14, 0xbb, 0xa5, 0x6a, 0x55, 0x0a, 0xd2, 0x26, + 0xa7, 0x5e, 0x56, 0xe3, 0xdd, 0xc9, 0x7a, 0x54, 0xef, 0xcc, 0xb2, 0x33, 0x0b, 0xde, 0x23, 0x5c, + 0x38, 0x21, 0x55, 0x5c, 0x90, 0xf8, 0x04, 0x88, 0x53, 0x0f, 0x95, 0xf8, 0x0a, 0xe5, 0x56, 0xf5, + 0x84, 0x38, 0xd0, 0xaa, 0x39, 0xf4, 0x63, 0x80, 0x76, 0x76, 0x76, 0x93, 0x26, 0xae, 0x03, 0x02, + 0x89, 0x8b, 0xb5, 0xf3, 0xe6, 0xf7, 0xde, 0xfc, 0xde, 0x7f, 0x43, 0xc7, 0xe3, 0x22, 0xe4, 0xc2, + 0x96, 0x53, 0xfb, 0xcb, 0x8b, 0x23, 0x22, 0xf1, 0x45, 0x5b, 0x4e, 0xad, 0x28, 0xe6, 0x92, 0xa3, + 0x95, 0xfc, 0xce, 0x92, 0x53, 0x4b, 0xdf, 0x75, 0x56, 0x73, 0x91, 0xab, 0x00, 0xb6, 0xbe, 0x57, + 0x87, 0xce, 0x0a, 0x0e, 0x29, 0xe3, 0xb6, 0xfa, 0xd5, 0xa2, 0x93, 0x01, 0x0f, 0x78, 0x0e, 0xcd, + 0xbe, 0xb4, 0x74, 0x43, 0x3f, 0xe9, 0xc5, 0x69, 0x24, 0xb9, 0x1d, 0x26, 0x13, 0x49, 0x05, 0x0d, + 0xca, 0xf7, 0x0b, 0x81, 0x86, 0x77, 0x35, 0x7c, 0x84, 0x05, 0x29, 0x31, 0x1e, 0xa7, 0x4c, 0xdf, + 0xbf, 0xbd, 0xe7, 0x81, 0xa0, 0x01, 0xa3, 0x6c, 0xcf, 0x92, 0x3e, 0x6b, 0xe0, 0x6a, 0xc0, 0x79, + 0x30, 0x21, 0xb6, 0x3a, 0x8d, 0x92, 0x1d, 0x1b, 0xb3, 0x54, 0x5f, 0xad, 0x1d, 0xbc, 0x92, 0x34, + 0x24, 0x42, 0xe2, 0x30, 0xca, 0x01, 0xbd, 0xef, 0x0c, 0xa8, 0x6e, 0x4f, 0xd1, 0x06, 0xd4, 0x46, + 0xdc, 0x4f, 0xdb, 0xc6, 0xba, 0xd1, 0x3f, 0xb6, 0xb9, 0x6a, 0x1d, 0x0a, 0x90, 0xb5, 0x3d, 0x1d, + 0x72, 0x3f, 0x75, 0x14, 0x0c, 0x5d, 0x86, 0x16, 0x4e, 0xe4, 0xd8, 0xa5, 0x6c, 0x87, 0xb7, 0xab, + 0x4a, 0xe7, 0xf4, 0x0c, 0x9d, 0x41, 0x22, 0xc7, 0xb7, 0xd8, 0x0e, 0x77, 0x9a, 0x58, 0x7f, 0xa1, + 0x2e, 0x40, 0x46, 0x1e, 0xcb, 0x24, 0x26, 0xa2, 0x6d, 0xae, 0x9b, 0xfd, 0x45, 0x67, 0x9f, 0xa4, + 0xc7, 0xa0, 0xbe, 0x3d, 0x75, 0xf0, 0x57, 0xe8, 0x0c, 0x40, 0xf6, 0x94, 0x3b, 0x4a, 0x25, 0x11, + 0x8a, 0xd7, 0xa2, 0xd3, 0xca, 0x24, 0xc3, 0x4c, 0x80, 0xde, 0x82, 0x13, 0x25, 0x03, 0x8d, 0xa9, + 0x2a, 0xcc, 0x52, 0xf1, 0x54, 0x8e, 0x3b, 0xea, 0xbd, 0xef, 0x0d, 0x58, 0xd8, 0xa2, 0x01, 0xbb, + 0xce, 0xbd, 0xff, 0xea, 0xc9, 0x55, 0x68, 0x7a, 0x63, 0x4c, 0x99, 0x4b, 0xfd, 0xb6, 0xb9, 0x6e, + 0xf4, 0x5b, 0xce, 0x82, 0x3a, 0xdf, 0xf2, 0xd1, 0x39, 0x38, 0x8e, 0x3d, 0x8f, 0x27, 0x4c, 0xba, + 0x2c, 0x09, 0x47, 0x24, 0x6e, 0xd7, 0xd6, 0x8d, 0x7e, 0xcd, 0x59, 0xd2, 0xd2, 0xcf, 0x94, 0xb0, + 0xf7, 0x6d, 0x15, 0x96, 0x35, 0xa9, 0xeb, 0x34, 0x26, 0x9e, 0x1c, 0x24, 0xd3, 0xa3, 0xd8, 0x5d, + 0x02, 0x88, 0x92, 0xd1, 0x84, 0x7a, 0xee, 0x3d, 0x92, 0xea, 0x9c, 0x9c, 0xb4, 0xf2, 0xf4, 0x5b, + 0x45, 0xfa, 0xad, 0x01, 0x4b, 0x9d, 0x56, 0x8e, 0xbb, 0x4d, 0xd2, 0x7f, 0x4f, 0x15, 0x75, 0xa0, + 0x29, 0xc8, 0x17, 0x09, 0x61, 0x1e, 0x69, 0xd7, 0x15, 0xa0, 0x3c, 0xa3, 0x77, 0xc0, 0x94, 0x34, + 0x6a, 0x37, 0x14, 0x97, 0xd7, 0x67, 0xd5, 0x14, 0x8d, 0x86, 0xd5, 0xb6, 0xe1, 0x64, 0xb0, 0x2b, + 0xaf, 0x3d, 0x79, 0xb8, 0x71, 0x22, 0xc7, 0x6c, 0x08, 0xff, 0xde, 0xfa, 0x05, 0xeb, 0xdd, 0xf7, + 0x7a, 0xdf, 0x98, 0xd0, 0xc8, 0x2b, 0x0f, 0x5d, 0x80, 0x66, 0x48, 0x84, 0xc0, 0x81, 0xf2, 0xde, + 0x7c, 0xa5, 0x7b, 0x25, 0x0a, 0x21, 0xa8, 0x85, 0x24, 0xcc, 0x0b, 0xb4, 0xe5, 0xa8, 0xef, 0xcc, + 0xad, 0xac, 0x05, 0x78, 0x22, 0xdd, 0x31, 0xa1, 0xc1, 0x58, 0x2a, 0xbf, 0x6b, 0xce, 0x92, 0x96, + 0xde, 0x54, 0x42, 0xf4, 0x06, 0xb4, 0x12, 0xc6, 0x63, 0x9f, 0xc4, 0xc4, 0x57, 0x8e, 0x37, 0x9d, + 0x3d, 0x01, 0xba, 0x03, 0x2b, 0x85, 0x91, 0xb2, 0x9f, 0x94, 0xf7, 0xc7, 0x36, 0x3b, 0x87, 0x38, + 0x6d, 0x17, 0x88, 0x61, 0xed, 0xfe, 0xd3, 0x35, 0xc3, 0x59, 0xd6, 0xaa, 0xa5, 0x1c, 0x0d, 0x61, + 0x85, 0x4c, 0x25, 0x61, 0x82, 0x72, 0xe6, 0xf2, 0x48, 0x52, 0xce, 0x44, 0xfb, 0xcf, 0x85, 0x39, + 0x3e, 0x2e, 0x97, 0xf8, 0xcf, 0x73, 0x38, 0xba, 0x0b, 0x5d, 0xc6, 0x99, 0xeb, 0xc5, 0x54, 0x52, + 0x0f, 0x4f, 0xdc, 0x19, 0x06, 0x4f, 0xcc, 0x31, 0x78, 0x9a, 0x71, 0x76, 0x4d, 0xeb, 0x7e, 0x72, + 0xc0, 0x76, 0xef, 0x17, 0x03, 0x9a, 0x45, 0x2b, 0xa3, 0x8f, 0x61, 0x31, 0x6b, 0x1f, 0x12, 0xab, + 0x3e, 0x28, 0x52, 0x71, 0x66, 0x46, 0x76, 0xb7, 0x14, 0x4c, 0xf5, 0xff, 0x31, 0x51, 0x7e, 0x0b, + 0xd4, 0x07, 0x73, 0x87, 0x10, 0x5d, 0xa2, 0xb3, 0xca, 0xe2, 0x06, 0x21, 0x4e, 0x06, 0x41, 0x57, + 0xf3, 0x02, 0x32, 0xe7, 0x16, 0xd0, 0xa9, 0xdf, 0x0f, 0xd7, 0x8d, 0xae, 0xa9, 0xde, 0x0f, 0x06, + 0xc0, 0x1e, 0x8d, 0x03, 0x3d, 0x62, 0xfc, 0xbd, 0x1e, 0xb9, 0x0c, 0xad, 0x90, 0xfb, 0xe4, 0xa8, + 0x59, 0x77, 0x87, 0xfb, 0x24, 0x9f, 0x75, 0xa1, 0xfe, 0x7a, 0xa9, 0x37, 0xcc, 0x97, 0x7b, 0xa3, + 0xf7, 0xac, 0x0a, 0xcd, 0x42, 0x05, 0x7d, 0x08, 0x0d, 0x41, 0x59, 0x30, 0x21, 0x9a, 0x53, 0x6f, + 0x8e, 0x7d, 0x6b, 0x4b, 0x21, 0x6f, 0x56, 0x1c, 0xad, 0x83, 0x3e, 0x80, 0xba, 0xda, 0x2c, 0x9a, + 0xdc, 0x9b, 0xf3, 0x94, 0xef, 0x64, 0xc0, 0x9b, 0x15, 0x27, 0xd7, 0xe8, 0x0c, 0xa0, 0x91, 0x9b, + 0x43, 0xef, 0x43, 0x2d, 0xe3, 0xad, 0x08, 0x1c, 0xdf, 0x3c, 0xbb, 0xcf, 0x46, 0xb1, 0x6b, 0xf6, + 0xa7, 0x35, 0xb3, 0xe7, 0x28, 0x85, 0xce, 0x7d, 0x03, 0xea, 0xca, 0x2a, 0xba, 0x0d, 0xcd, 0x11, + 0x95, 0x38, 0x8e, 0x71, 0x11, 0x5b, 0xbb, 0x30, 0x93, 0x6f, 0x44, 0xab, 0x5c, 0x80, 0x85, 0xad, + 0x6b, 0x3c, 0x8c, 0xb0, 0x27, 0x87, 0x54, 0x0e, 0x32, 0x35, 0xa7, 0x34, 0x80, 0xae, 0x00, 0x94, + 0x51, 0xcf, 0xe6, 0xac, 0x79, 0x54, 0xd8, 0x5b, 0x45, 0xd8, 0xc5, 0xb0, 0x0e, 0xa6, 0x48, 0xc2, + 0xde, 0xd7, 0x55, 0x30, 0x6f, 0x10, 0x82, 0x52, 0x68, 0xe0, 0x30, 0x1b, 0x59, 0xba, 0x56, 0xcb, + 0xed, 0x96, 0x2d, 0xde, 0x7d, 0x54, 0x28, 0x1b, 0xde, 0x78, 0xf4, 0xc7, 0x5a, 0xe5, 0xe7, 0xa7, + 0x6b, 0xfd, 0x80, 0xca, 0x71, 0x32, 0xb2, 0x3c, 0x1e, 0xda, 0xc5, 0x52, 0x2f, 0x2b, 0xcc, 0x96, + 0x69, 0x44, 0x84, 0x52, 0x10, 0x3f, 0xbe, 0x78, 0x70, 0x7e, 0x71, 0x42, 0x02, 0xec, 0xa5, 0x6e, + 0xb6, 0xba, 0xc5, 0x4f, 0x2f, 0x1e, 0x9c, 0x37, 0x1c, 0xfd, 0x20, 0x3a, 0x0d, 0xad, 0x00, 0x0b, + 0x77, 0x42, 0x43, 0x2a, 0x55, 0x7a, 0x6a, 0x4e, 0x33, 0xc0, 0xe2, 0xd3, 0xec, 0x8c, 0x2c, 0xa8, + 0x47, 0x38, 0x25, 0x71, 0x3e, 0x79, 0x87, 0xed, 0x27, 0x0f, 0x37, 0x4e, 0x6a, 0x66, 0x03, 0xdf, + 0x8f, 0x89, 0x10, 0x5b, 0x32, 0xa6, 0x2c, 0x70, 0x72, 0x18, 0xda, 0x84, 0x85, 0x20, 0xc6, 0x4c, + 0xea, 0x51, 0x3c, 0x4f, 0xa3, 0x00, 0xf6, 0x7e, 0x35, 0xc0, 0xdc, 0xa6, 0xd1, 0xff, 0x19, 0x83, + 0x0b, 0xd0, 0x90, 0x34, 0x8a, 0x48, 0x9c, 0xcf, 0xe1, 0x39, 0xac, 0x35, 0xee, 0xca, 0xa9, 0x27, + 0xb3, 0x3a, 0xba, 0xb7, 0x6b, 0xc0, 0xd2, 0x20, 0x99, 0xe6, 0xfd, 0x7c, 0x1d, 0x4b, 0x9c, 0x45, + 0x04, 0xe7, 0x16, 0x54, 0xc1, 0xcd, 0x8d, 0x88, 0x06, 0xa2, 0x8f, 0xa0, 0x99, 0x55, 0xb4, 0xeb, + 0x73, 0x4f, 0x37, 0xcc, 0xd9, 0x57, 0xcc, 0xae, 0xfd, 0xdb, 0xd7, 0x59, 0x10, 0xfa, 0x4f, 0x42, + 0xd1, 0x28, 0xe6, 0x3f, 0x6c, 0x14, 0xb4, 0x0c, 0xa6, 0xa0, 0x81, 0x4a, 0xdd, 0xa2, 0x93, 0x7d, + 0xce, 0xdc, 0x78, 0xc3, 0xab, 0x8f, 0x9e, 0x77, 0x8d, 0xc7, 0xcf, 0xbb, 0xc6, 0xb3, 0xe7, 0x5d, + 0xe3, 0xfe, 0x6e, 0xb7, 0xf2, 0x78, 0xb7, 0x5b, 0xf9, 0x6d, 0xb7, 0x5b, 0xb9, 0x7b, 0xee, 0xe8, + 0x84, 0xd8, 0x72, 0x3a, 0x6a, 0xa8, 0x41, 0x76, 0xe9, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x52, + 0x04, 0x7c, 0xda, 0x01, 0x0b, 0x00, 0x00, } func (m *Tx) Marshal() (dAtA []byte, err error) { @@ -1383,6 +1403,16 @@ func (m *TxBody) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0xfa } } + if m.TimeoutTimestamp != nil { + n5, err5 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(*m.TimeoutTimestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(*m.TimeoutTimestamp):]) + if err5 != nil { + return 0, err5 + } + i -= n5 + i = encodeVarintTx(dAtA, i, uint64(n5)) + i-- + dAtA[i] = 0x2a + } if m.Unordered { i-- if m.Unordered { @@ -1974,6 +2004,10 @@ func (m *TxBody) Size() (n int) { if m.Unordered { n += 2 } + if m.TimeoutTimestamp != nil { + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(*m.TimeoutTimestamp) + n += 1 + l + sovTx(uint64(l)) + } if len(m.ExtensionOptions) > 0 { for _, e := range m.ExtensionOptions { l = e.Size() @@ -3007,6 +3041,42 @@ func (m *TxBody) Unmarshal(dAtA []byte) error { } } m.Unordered = bool(v != 0) + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeoutTimestamp", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.TimeoutTimestamp == nil { + m.TimeoutTimestamp = new(time.Time) + } + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(m.TimeoutTimestamp, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex case 1023: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ExtensionOptions", wireType) diff --git a/types/tx_msg.go b/types/tx_msg.go index 4c0c4042f598..37ff1264d9a0 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "strings" + "time" "google.golang.org/protobuf/reflect/protoreflect" @@ -79,6 +80,14 @@ type ( GetMemo() string } + // TxWithTimeoutHeight extends the Tx interface by allowing a transaction to + // set a height timeout. + TxWithTimeoutTimeStamp interface { + Tx + + GetTimeoutTimeStamp() time.Time + } + // TxWithTimeoutHeight extends the Tx interface by allowing a transaction to // set a height timeout. TxWithTimeoutHeight interface { @@ -91,6 +100,7 @@ type ( // the unordered field, which implicitly relies on TxWithTimeoutHeight. TxWithUnordered interface { TxWithTimeoutHeight + TxWithTimeoutTimeStamp GetUnordered() bool } diff --git a/x/auth/ante/unordered.go b/x/auth/ante/unordered.go index 193f5545125a..bfb52ee25087 100644 --- a/x/auth/ante/unordered.go +++ b/x/auth/ante/unordered.go @@ -2,6 +2,7 @@ package ante import ( "crypto/sha256" + "time" "cosmossdk.io/core/appmodule/v2" "cosmossdk.io/core/transaction" @@ -28,9 +29,10 @@ var _ sdk.AnteDecorator = (*UnorderedTxDecorator)(nil) // chain to ensure that during DeliverTx, the transaction is added to the UnorderedTxManager. type UnorderedTxDecorator struct { // maxUnOrderedTTL defines the maximum TTL a transaction can define. - maxUnOrderedTTL uint64 - txManager *unorderedtx.Manager - env appmodule.Environment + maxUnOrderedTTL uint64 + maxTimeoutDuration time.Duration + txManager *unorderedtx.Manager + env appmodule.Environment } func NewUnorderedTxDecorator(maxTTL uint64, m *unorderedtx.Manager, env appmodule.Environment) *UnorderedTxDecorator { @@ -49,17 +51,27 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne return next(ctx, tx, false) } + timeoutTimestamp := unorderedTx.GetTimeoutTimeStamp() // TTL is defined as a specific block height at which this tx is no longer valid ttl := unorderedTx.GetTimeoutHeight() - - if ttl == 0 { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_height set") - } - if ttl < uint64(ctx.BlockHeight()) { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_height that has already passed") - } - if ttl > uint64(ctx.BlockHeight())+d.maxUnOrderedTTL { - return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) + // if timeout timestamp is set + if !timeoutTimestamp.IsZero() { + if timeoutTimestamp.Before(ctx.BlockTime()) { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_height that has already passed") + } + if timeoutTimestamp.After(ctx.BlockTime().Add(d.maxTimeoutDuration)) { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) + } + } else { + if ttl == 0 { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_height set") + } + if ttl < uint64(ctx.BlockHeight()) { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_height that has already passed") + } + if ttl > uint64(ctx.BlockHeight())+d.maxUnOrderedTTL { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) + } } txHash := sha256.Sum256(ctx.TxBytes()) diff --git a/x/auth/ante/unorderedtx/manager.go b/x/auth/ante/unorderedtx/manager.go index 14fbe018b83b..1c88cf804825 100644 --- a/x/auth/ante/unorderedtx/manager.go +++ b/x/auth/ante/unorderedtx/manager.go @@ -21,6 +21,10 @@ const ( // DefaultMaxUnOrderedTTL defines the default maximum TTL an un-ordered transaction // can set. DefaultMaxUnOrderedTTL = 1024 + // DefaultmaxTimeoutDuration defines the default maximum duration an un-ordered transaction + // can set. + // TODO: need to decide a default value + DefaultmaxTimeoutDuration = time.Minute * 40 dirName = "unordered_txs" fileName = "data" diff --git a/x/auth/tx/gogotx.go b/x/auth/tx/gogotx.go index da129af50461..c56a3a9760eb 100644 --- a/x/auth/tx/gogotx.go +++ b/x/auth/tx/gogotx.go @@ -4,6 +4,7 @@ import ( "fmt" "reflect" "strings" + "time" "github.com/cosmos/gogoproto/proto" "google.golang.org/protobuf/reflect/protoreflect" @@ -177,6 +178,11 @@ func (w *gogoTxWrapper) GetMemo() string { return w.Tx.Body.Memo } // GetTimeoutHeight returns the transaction's timeout height (if set). func (w *gogoTxWrapper) GetTimeoutHeight() uint64 { return w.Tx.Body.TimeoutHeight } +// GetTimeoutHeight returns the transaction's timeout height (if set). +func (w *gogoTxWrapper) GetTimeoutTimeStamp() time.Time { + return w.Tx.Body.TimeoutTimestamp.AsTime() +} + // GetUnordered returns the transaction's unordered field (if set). func (w *gogoTxWrapper) GetUnordered() bool { return w.Tx.Body.Unordered } diff --git a/x/staking/types/query.pb.go b/x/staking/types/query.pb.go index 7d39af987027..bf623cc0ae29 100644 --- a/x/staking/types/query.pb.go +++ b/x/staking/types/query.pb.go @@ -134,7 +134,11 @@ func (m *ValidatorInfo) GetConsensusAddress() string { // QueryValidatorsResponse is response type for the Query/Validators RPC method type QueryValidatorsResponse struct { - Validators []Validator `protobuf:"bytes,1,rep,name=validators,proto3" json:"validators"` + Validators []Validator `protobuf:"bytes,1,rep,name=validators,proto3" json:"validators"` + // validator_info contains additional information for each validator. + // The order of the elements in this list corresponds to the order of the elements in the validators list. + // For example, if you want the ValidatorInfo for the third validator in the validators list, + // you should look at the third element in the validator_info list. ValidatorInfo []ValidatorInfo `protobuf:"bytes,2,rep,name=validator_info,json=validatorInfo,proto3" json:"validator_info"` Pagination *query.PageResponse `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` } From 6de6ec332f48208fe18bbaf869d6190be989d72f Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Thu, 4 Jul 2024 11:57:26 +0700 Subject: [PATCH 02/39] add time based field for tx body --- api/cosmos/tx/v1beta1/tx.pulsar.go | 4 +- client/flags/flags.go | 2 + client/tx/aux_builder.go | 17 ++- client/tx/factory.go | 13 +++ client/tx_config.go | 3 + client/v2/offchain/builder.go | 1 + proto/cosmos/tx/v1beta1/tx.proto | 4 +- types/errors/errors.go | 4 + types/tx/tx.pb.go | 4 +- x/auth/ante/basic.go | 9 ++ x/auth/ante/unordered.go | 38 ++++--- x/auth/ante/unorderedtx/manager.go | 133 +++++++++++++++++------- x/auth/ante/unorderedtx/manager_test.go | 10 +- x/auth/ante/unorderedtx/snapshotter.go | 8 +- x/auth/tx/builder.go | 26 +++-- 15 files changed, 198 insertions(+), 78 deletions(-) diff --git a/api/cosmos/tx/v1beta1/tx.pulsar.go b/api/cosmos/tx/v1beta1/tx.pulsar.go index a5eda20d225e..1043981d63b6 100644 --- a/api/cosmos/tx/v1beta1/tx.pulsar.go +++ b/api/cosmos/tx/v1beta1/tx.pulsar.go @@ -8562,8 +8562,8 @@ type TxBody struct { // incremented, which allows for fire-and-forget as well as concurrent // transaction execution. // - // Note, when set to true, the existing 'timeout_height' value must be set and - // will be used to correspond to a height in which the transaction is deemed + // Note, when set to true, the existing 'timeout_height' or 'timeout_timestamp' value must + // be set and will be used to correspond to a height/time_stamp in which the transaction is deemed // valid. Unordered bool `protobuf:"varint,4,opt,name=unordered,proto3" json:"unordered,omitempty"` // timeout_timestamp is the block time after which this transaction will not diff --git a/client/flags/flags.go b/client/flags/flags.go index 801b7f5796a8..3c1d478f1b5a 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -74,6 +74,7 @@ const ( FlagOffset = "offset" FlagCountTotal = "count-total" FlagTimeoutHeight = "timeout-height" + FlagTimeoutTimestamp = "timeout-timestamp" FlagUnordered = "unordered" FlagKeyAlgorithm = "algo" FlagKeyType = "key-type" @@ -137,6 +138,7 @@ func AddTxFlagsToCmd(cmd *cobra.Command) { f.BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation") f.String(FlagSignMode, "", "Choose sign mode (direct|amino-json|direct-aux|textual), this is an advanced feature") f.Uint64(FlagTimeoutHeight, 0, "Set a block timeout height to prevent the tx from being committed past a certain height") + f.Int64(FlagTimeoutTimestamp, 0, "Set a block timeout timestamp to prevent the tx from being committed past a certain time") f.Bool(FlagUnordered, false, "Enable unordered transaction delivery; must be used in conjunction with --timeout-height") f.String(FlagFeePayer, "", "Fee payer pays fees for the transaction instead of deducting from the signer") f.String(FlagFeeGranter, "", "Fee granter grants fees for the transaction") diff --git a/client/tx/aux_builder.go b/client/tx/aux_builder.go index ade6622f87a0..d7888770ddb1 100644 --- a/client/tx/aux_builder.go +++ b/client/tx/aux_builder.go @@ -2,9 +2,11 @@ package tx import ( "context" + "time" "github.com/cosmos/gogoproto/proto" "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/timestamppb" txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1" txsigning "cosmossdk.io/x/tx/signing" @@ -58,6 +60,14 @@ func (b *AuxTxBuilder) SetTimeoutHeight(height uint64) { b.auxSignerData.SignDoc.BodyBytes = nil } +// SetTimeoutTimestamp sets a timeout timestamp in the tx. +func (b *AuxTxBuilder) SetTimeoutTimestamp(timestamp time.Time) { + b.checkEmptyFields() + + b.body.TimeoutTimestamp = timestamppb.New(timestamp) + b.auxSignerData.SignDoc.BodyBytes = nil +} + // SetMsgs sets an array of Msgs in the tx. func (b *AuxTxBuilder) SetMsgs(msgs ...sdk.Msg) error { anys := make([]*anypb.Any, len(msgs)) @@ -209,9 +219,10 @@ func (b *AuxTxBuilder) GetSignBytes() ([]byte, error) { }) auxBody := &txv1beta1.TxBody{ - Messages: body.Messages, - Memo: body.Memo, - TimeoutHeight: body.TimeoutHeight, + Messages: body.Messages, + Memo: body.Memo, + TimeoutHeight: body.TimeoutHeight, + TimeoutTimestamp: body.TimeoutTimestamp, // AuxTxBuilder has no concern with extension options, so we set them to nil. // This preserves pre-PR#16025 behavior where extension options were ignored, this code path: // https://github.com/cosmos/cosmos-sdk/blob/ac3c209326a26b46f65a6cc6f5b5ebf6beb79b38/client/tx/aux_builder.go#L193 diff --git a/client/tx/factory.go b/client/tx/factory.go index 22053ba3d744..e0a204c553dc 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -6,6 +6,7 @@ import ( "math/big" "os" "strings" + "time" "github.com/cosmos/go-bip39" "github.com/spf13/pflag" @@ -33,6 +34,7 @@ type Factory struct { sequence uint64 gas uint64 timeoutHeight uint64 + timeoutTimestamp time.Time gasAdjustment float64 chainID string fromName string @@ -87,6 +89,8 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e gasAdj := clientCtx.Viper.GetFloat64(flags.FlagGasAdjustment) memo := clientCtx.Viper.GetString(flags.FlagNote) timeoutHeight := clientCtx.Viper.GetUint64(flags.FlagTimeoutHeight) + timestampUnix := clientCtx.Viper.GetInt64(flags.FlagTimeoutTimestamp) + timeoutTimestamp := time.Unix(timestampUnix, 0) unordered := clientCtx.Viper.GetBool(flags.FlagUnordered) gasStr := clientCtx.Viper.GetString(flags.FlagGas) @@ -105,6 +109,7 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e accountNumber: accNum, sequence: accSeq, timeoutHeight: timeoutHeight, + timeoutTimestamp: timeoutTimestamp, unordered: unordered, gasAdjustment: gasAdj, memo: memo, @@ -135,6 +140,7 @@ func (f Factory) Fees() sdk.Coins { return f.fees } func (f Factory) GasPrices() sdk.DecCoins { return f.gasPrices } func (f Factory) AccountRetriever() client.AccountRetriever { return f.accountRetriever } func (f Factory) TimeoutHeight() uint64 { return f.timeoutHeight } +func (f Factory) TimeoutTimestamp() time.Time { return f.timeoutTimestamp } func (f Factory) Unordered() bool { return f.unordered } func (f Factory) FromName() string { return f.fromName } @@ -249,6 +255,12 @@ func (f Factory) WithTimeoutHeight(height uint64) Factory { return f } +// WithTimeoutTimestamp returns a copy of the Factory with an updated timeout timestamp. +func (f Factory) WithTimeoutTimestamp(timestamp time.Time) Factory { + f.timeoutTimestamp = timestamp + return f +} + // WithUnordered returns a copy of the Factory with an updated unordered field. func (f Factory) WithUnordered(v bool) Factory { f.unordered = v @@ -361,6 +373,7 @@ func (f Factory) BuildUnsignedTx(msgs ...sdk.Msg) (client.TxBuilder, error) { tx.SetFeeGranter(f.feeGranter) tx.SetFeePayer(f.feePayer) tx.SetTimeoutHeight(f.TimeoutHeight()) + tx.SetTimeoutTimestamp(f.TimeoutTimestamp()) if etx, ok := tx.(client.ExtendedTxBuilder); ok { etx.SetExtensionOptions(f.extOptions...) diff --git a/client/tx_config.go b/client/tx_config.go index fe60fe4625c1..c41d3de6389a 100644 --- a/client/tx_config.go +++ b/client/tx_config.go @@ -1,6 +1,8 @@ package client import ( + "time" + "cosmossdk.io/x/auth/signing" txsigning "cosmossdk.io/x/tx/signing" @@ -48,6 +50,7 @@ type ( SetFeePayer(feePayer sdk.AccAddress) SetGasLimit(limit uint64) SetTimeoutHeight(height uint64) + SetTimeoutTimestamp(timestamp time.Time) SetUnordered(v bool) SetFeeGranter(feeGranter sdk.AccAddress) AddAuxSignerData(tx.AuxSignerData) error diff --git a/client/v2/offchain/builder.go b/client/v2/offchain/builder.go index c3a8f924ed01..55c5678cd15c 100644 --- a/client/v2/offchain/builder.go +++ b/client/v2/offchain/builder.go @@ -113,6 +113,7 @@ func (b *builder) GetSigningTxData() (txsigning.TxData, error) { Messages: msgs, Memo: body.Memo, TimeoutHeight: body.TimeoutHeight, + TimeoutTimestamp: body.TimeoutTimestamp, ExtensionOptions: extOptions, NonCriticalExtensionOptions: nonCriticalExtOptions, } diff --git a/proto/cosmos/tx/v1beta1/tx.proto b/proto/cosmos/tx/v1beta1/tx.proto index 7a015f1cc7f2..f97d0999e1ec 100644 --- a/proto/cosmos/tx/v1beta1/tx.proto +++ b/proto/cosmos/tx/v1beta1/tx.proto @@ -123,8 +123,8 @@ message TxBody { // incremented, which allows for fire-and-forget as well as concurrent // transaction execution. // - // Note, when set to true, the existing 'timeout_height' or 'timeout_timestamp' value must be set and - // will be used to correspond to a height in which the transaction is deemed + // Note, when set to true, the existing 'timeout_height' or 'timeout_timestamp' value must + // be set and will be used to correspond to a height/time_stamp in which the transaction is deemed // valid. bool unordered = 4; diff --git a/types/errors/errors.go b/types/errors/errors.go index 5e17f2df481a..36bb82ffd957 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -142,4 +142,8 @@ var ( // ErrPanic should only be set when we recovering from a panic ErrPanic = errorsmod.ErrPanic + + // ErrTxTimeout defines an error for when a tx is rejected out due to an + // explicitly set timeout timestamp. + ErrTxTimeout = errorsmod.Register(RootCodespace, 42, "tx timeout") ) diff --git a/types/tx/tx.pb.go b/types/tx/tx.pb.go index 363d6086469e..9ea952ea7f5f 100644 --- a/types/tx/tx.pb.go +++ b/types/tx/tx.pb.go @@ -374,8 +374,8 @@ type TxBody struct { // incremented, which allows for fire-and-forget as well as concurrent // transaction execution. // - // Note, when set to true, the existing 'timeout_height' value must be set and - // will be used to correspond to a height in which the transaction is deemed + // Note, when set to true, the existing 'timeout_height' or 'timeout_timestamp' value must + // be set and will be used to correspond to a height/time_stamp in which the transaction is deemed // valid. Unordered bool `protobuf:"varint,4,opt,name=unordered,proto3" json:"unordered,omitempty"` // timeout_timestamp is the block time after which this transaction will not diff --git a/x/auth/ante/basic.go b/x/auth/ante/basic.go index ff9852698961..ba0e3e70e70e 100644 --- a/x/auth/ante/basic.go +++ b/x/auth/ante/basic.go @@ -2,6 +2,7 @@ package ante import ( "context" + "time" "cosmossdk.io/core/appmodule/v2" "cosmossdk.io/core/transaction" @@ -227,6 +228,7 @@ type ( sdk.Tx GetTimeoutHeight() uint64 + GetTimeoutTimeStamp() time.Time } ) @@ -266,5 +268,12 @@ func (txh TxTimeoutHeightDecorator) ValidateTx(ctx context.Context, tx sdk.Tx) e ) } + timeoutTimestamp := timeoutTx.GetTimeoutTimeStamp() + if timeoutTimestamp.IsZero() && timeoutTimestamp.Before(headerInfo.Time) { + return errorsmod.Wrapf( + sdkerrors.ErrTxTimeout, "block time: %s, timeout timestamp: %s", headerInfo.Time.String(), timeoutTimestamp.String(), + ) + } + return nil } diff --git a/x/auth/ante/unordered.go b/x/auth/ante/unordered.go index bfb52ee25087..1e495328fecd 100644 --- a/x/auth/ante/unordered.go +++ b/x/auth/ante/unordered.go @@ -51,10 +51,15 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne return next(ctx, tx, false) } + txHash := sha256.Sum256(ctx.TxBytes()) + + // check for duplicates + if d.txManager.Contains(txHash) { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "tx %X is duplicated") + } + timeoutTimestamp := unorderedTx.GetTimeoutTimeStamp() // TTL is defined as a specific block height at which this tx is no longer valid - ttl := unorderedTx.GetTimeoutHeight() - // if timeout timestamp is set if !timeoutTimestamp.IsZero() { if timeoutTimestamp.Before(ctx.BlockTime()) { return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_height that has already passed") @@ -62,23 +67,24 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne if timeoutTimestamp.After(ctx.BlockTime().Add(d.maxTimeoutDuration)) { return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) } - } else { - if ttl == 0 { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_height set") - } - if ttl < uint64(ctx.BlockHeight()) { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_height that has already passed") - } - if ttl > uint64(ctx.BlockHeight())+d.maxUnOrderedTTL { - return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) + + if d.env.TransactionService.ExecMode(ctx) == transaction.ExecModeFinalize { + // a new tx included in the block, add the hash to the unordered tx manager + d.txManager.AddTimestamp(txHash, timeoutTimestamp) } - } - txHash := sha256.Sum256(ctx.TxBytes()) + return next(ctx, tx, false) + } - // check for duplicates - if d.txManager.Contains(txHash) { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "tx %X is duplicated") + ttl := unorderedTx.GetTimeoutHeight() + if ttl == 0 && timeoutTimestamp.IsZero() { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_height or timeout_timestamp set") + } + if ttl < uint64(ctx.BlockHeight()) { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_height that has already passed") + } + if ttl > uint64(ctx.BlockHeight())+d.maxUnOrderedTTL { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) } if d.env.TransactionService.ExecMode(ctx) == transaction.ExecModeFinalize { diff --git a/x/auth/ante/unorderedtx/manager.go b/x/auth/ante/unorderedtx/manager.go index 1c88cf804825..1a685c584558 100644 --- a/x/auth/ante/unorderedtx/manager.go +++ b/x/auth/ante/unorderedtx/manager.go @@ -33,11 +33,16 @@ const ( // TxHash defines a transaction hash type alias, which is a fixed array of 32 bytes. type TxHash [32]byte +type blockInfo struct { + blockHeight uint64 + blockTime time.Time +} + // Manager contains the tx hash dictionary for duplicates checking, and expire // them when block production progresses. type Manager struct { // blockCh defines a channel to receive newly committed block heights - blockCh chan uint64 + blockCh chan blockInfo // doneCh allows us to ensure the purgeLoop has gracefully terminated prior to closing doneCh chan struct{} @@ -52,10 +57,15 @@ type Manager struct { dataDir string mu sync.RWMutex - // txHashes defines a map from tx hash -> TTL value, which is used for duplicate + // txHashesBlockHeight defines a map from tx hash -> TTL value defined as block height, which is used for duplicate + // checking and replay protection, as well as purging the map when the TTL is + // expired. + txHashesBlockHeight map[TxHash]uint64 + + // txHashesTimestamp defines a map from tx hash -> TTL value defined as block time, which is used for duplicate // checking and replay protection, as well as purging the map when the TTL is // expired. - txHashes map[TxHash]uint64 + txHashesTimestamp map[TxHash]time.Time } func NewManager(dataDir string) *Manager { @@ -65,10 +75,11 @@ func NewManager(dataDir string) *Manager { } m := &Manager{ - dataDir: dataDir, - blockCh: make(chan uint64, 16), - doneCh: make(chan struct{}), - txHashes: make(map[TxHash]uint64), + dataDir: dataDir, + blockCh: make(chan blockInfo, 16), + doneCh: make(chan struct{}), + txHashesBlockHeight: make(map[TxHash]uint64), + txHashesTimestamp: make(map[TxHash]time.Time), } return m @@ -96,7 +107,11 @@ func (m *Manager) Contains(hash TxHash) bool { m.mu.RLock() defer m.mu.RUnlock() - _, ok := m.txHashes[hash] + _, ok := m.txHashesBlockHeight[hash] + if ok { + return ok + } + _, ok = m.txHashesTimestamp[hash] return ok } @@ -104,14 +119,21 @@ func (m *Manager) Size() int { m.mu.RLock() defer m.mu.RUnlock() - return len(m.txHashes) + return len(m.txHashesBlockHeight) + len(m.txHashesTimestamp) } func (m *Manager) Add(txHash TxHash, ttl uint64) { m.mu.Lock() defer m.mu.Unlock() - m.txHashes[txHash] = ttl + m.txHashesBlockHeight[txHash] = ttl +} + +func (m *Manager) AddTimestamp(txHash TxHash, timestamp time.Time) { + m.mu.Lock() + defer m.mu.Unlock() + + m.txHashesTimestamp[txHash] = timestamp } // OnInit must be called when a node starts up. Typically, this should be called @@ -131,7 +153,7 @@ func (m *Manager) OnInit() error { var ( r = bufio.NewReader(f) - buf = make([]byte, chunkSize) + buf = make([]byte, newChukSize) ) for { n, err := io.ReadFull(r, buf) @@ -142,14 +164,23 @@ func (m *Manager) OnInit() error { return fmt.Errorf("failed to read unconfirmed txs file: %w", err) } } - if n != 32+8 { + if n != 32+8+8 { return fmt.Errorf("read unexpected number of bytes from unconfirmed txs file: %d", n) } var txHash TxHash copy(txHash[:], buf[:txHashSize]) - m.Add(txHash, binary.BigEndian.Uint64(buf[txHashSize:])) + blockHeight := binary.BigEndian.Uint64(buf[txHashSize : txHashSize+ttlSize]) + timeStamp := binary.BigEndian.Uint64(buf[txHashSize+ttlSize:]) + + // if not zero value + if blockHeight != 0 { + m.Add(txHash, blockHeight) + continue + } + + m.AddTimestamp(txHash, time.Unix(int64(timeStamp), 0)) } return nil @@ -157,25 +188,28 @@ func (m *Manager) OnInit() error { // OnNewBlock sends the latest block number to the background purge loop, which // should be called in ABCI Commit event. -func (m *Manager) OnNewBlock(blockHeight uint64) { - m.blockCh <- blockHeight +func (m *Manager) OnNewBlock(blockHeight uint64, blockTime time.Time) { + m.blockCh <- blockInfo{ + blockHeight: blockHeight, + blockTime: blockTime, + } } func (m *Manager) exportSnapshot(height uint64, snapshotWriter func([]byte) error) error { var buf bytes.Buffer w := bufio.NewWriter(&buf) - keys := maps.Keys(m.txHashes) + keys := maps.Keys(m.txHashesBlockHeight) sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i][:], keys[j][:]) < 0 }) for _, txHash := range keys { - ttl := m.txHashes[txHash] + ttl := m.txHashesBlockHeight[txHash] if height > ttl { // skip expired txs that have yet to be purged continue } - chunk := unorderedTxToBytes(txHash, ttl) + chunk := unorderedTxToBytes(txHash, ttl, true) if _, err := w.Write(chunk); err != nil { return fmt.Errorf("failed to write unordered tx to buffer: %w", err) @@ -199,8 +233,16 @@ func (m *Manager) flushToFile() error { defer f.Close() w := bufio.NewWriter(f) - for txHash, ttl := range m.txHashes { - chunk := unorderedTxToBytes(txHash, ttl) + for txHash, ttl := range m.txHashesBlockHeight { + chunk := unorderedTxToBytes(txHash, ttl, true) + + if _, err = w.Write(chunk); err != nil { + return fmt.Errorf("failed to write unordered tx to buffer: %w", err) + } + } + + for txHash, timestamp := range m.txHashesTimestamp { + chunk := unorderedTxToBytes(txHash, uint64(timestamp.Unix()), false) if _, err = w.Write(chunk); err != nil { return fmt.Errorf("failed to write unordered tx to buffer: %w", err) @@ -215,75 +257,94 @@ func (m *Manager) flushToFile() error { } // expiredTxs returns expired tx hashes based on the provided block height. -func (m *Manager) expiredTxs(blockHeight uint64) []TxHash { +func (m *Manager) expiredTxs(blockHeight uint64, blockTime time.Time) []TxHash { m.mu.RLock() defer m.mu.RUnlock() var result []TxHash - for txHash, ttl := range m.txHashes { + for txHash, ttl := range m.txHashesBlockHeight { if blockHeight > ttl { result = append(result, txHash) } } + for txHash, timestamp := range m.txHashesTimestamp { + if blockTime.After(timestamp) { + result = append(result, txHash) + } + } + return result } -func (m *Manager) purge(txHashes []TxHash) { +func (m *Manager) purge(txHashesBlockHeight []TxHash) { m.mu.Lock() defer m.mu.Unlock() - for _, txHash := range txHashes { - delete(m.txHashes, txHash) + for _, txHash := range txHashesBlockHeight { + delete(m.txHashesBlockHeight, txHash) } } // purgeLoop removes expired tx hashes in the background func (m *Manager) purgeLoop() { for { - latestHeight, ok := m.batchReceive() + latestHeight, latestTime, ok := m.batchReceive() if !ok { // channel closed m.doneCh <- struct{}{} return } - hashes := m.expiredTxs(latestHeight) + hashes := m.expiredTxs(latestHeight, latestTime) if len(hashes) > 0 { m.purge(hashes) } } } -func (m *Manager) batchReceive() (uint64, bool) { +func (m *Manager) batchReceive() (uint64, time.Time, bool) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() var latestHeight uint64 + var latestTime time.Time for { select { case <-ctx.Done(): - return latestHeight, true + return latestHeight, latestTime, true - case blockHeight, ok := <-m.blockCh: + case blockInfo, ok := <-m.blockCh: if !ok { // channel is closed - return 0, false + return 0, time.Time{}, false } - if blockHeight > latestHeight { - latestHeight = blockHeight + if blockInfo.blockHeight > latestHeight { + latestHeight = blockInfo.blockHeight + } + + if blockInfo.blockTime.After(latestTime) { + latestTime = blockInfo.blockTime } } } } -func unorderedTxToBytes(txHash TxHash, ttl uint64) []byte { - chunk := make([]byte, chunkSize) +func unorderedTxToBytes(txHash TxHash, ttl uint64, isBlockHeight bool) []byte { + chunk := make([]byte, newChukSize) copy(chunk[:txHashSize], txHash[:]) ttlBz := make([]byte, ttlSize) binary.BigEndian.PutUint64(ttlBz, ttl) - copy(chunk[txHashSize:], ttlBz) + emptyBz := make([]byte, 8) + binary.BigEndian.PutUint64(emptyBz, 0) + if isBlockHeight { + copy(chunk[txHashSize+ttl:], emptyBz) + copy(chunk[txHashSize:txHashSize+ttlSize], ttlBz) + } else { + copy(chunk[txHashSize+ttlSize:], ttlBz) + copy(chunk[txHashSize:txHashSize+ttlSize], emptyBz) + } return chunk } diff --git a/x/auth/ante/unorderedtx/manager_test.go b/x/auth/ante/unorderedtx/manager_test.go index 04138e344657..48e22f4de59d 100644 --- a/x/auth/ante/unorderedtx/manager_test.go +++ b/x/auth/ante/unorderedtx/manager_test.go @@ -119,12 +119,14 @@ func TestUnorderedTxManager_Flow(t *testing.T) { defer ticker.Stop() var ( - height uint64 = 1 - i = 101 + height uint64 = 1 + timestamp time.Time = time.Now() + i = 101 ) - for range ticker.C { - txm.OnNewBlock(height) + for time := range ticker.C { + txm.OnNewBlock(height, timestamp) height++ + timestamp = time if height > 51 { doneBlockCh <- true diff --git a/x/auth/ante/unorderedtx/snapshotter.go b/x/auth/ante/unorderedtx/snapshotter.go index 5941a11a6888..aef275138bf3 100644 --- a/x/auth/ante/unorderedtx/snapshotter.go +++ b/x/auth/ante/unorderedtx/snapshotter.go @@ -9,9 +9,11 @@ import ( ) const ( - txHashSize = 32 - ttlSize = 8 - chunkSize = txHashSize + ttlSize + txHashSize = 32 + ttlSize = 8 + timeoutSize = 8 + chunkSize = txHashSize + ttlSize + newChukSize = txHashSize + ttlSize + timeoutSize ) var _ snapshot.ExtensionSnapshotter = &Snapshotter{} diff --git a/x/auth/tx/builder.go b/x/auth/tx/builder.go index 506412b23f6c..1ad07381c569 100644 --- a/x/auth/tx/builder.go +++ b/x/auth/tx/builder.go @@ -2,9 +2,11 @@ package tx import ( "fmt" + "time" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/timestamppb" basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" multisigv1beta1 "cosmossdk.io/api/cosmos/crypto/multisig/v1beta1" @@ -78,16 +80,17 @@ type builder struct { decoder *decode.Decoder codec codec.BinaryCodec - msgs []sdk.Msg - timeoutHeight uint64 - granter []byte - payer []byte - unordered bool - memo string - gasLimit uint64 - fees sdk.Coins - signerInfos []*tx.SignerInfo - signatures [][]byte + msgs []sdk.Msg + timeoutHeight uint64 + timeoutTimestamp time.Time + granter []byte + payer []byte + unordered bool + memo string + gasLimit uint64 + fees sdk.Coins + signerInfos []*tx.SignerInfo + signatures [][]byte extensionOptions []*codectypes.Any nonCriticalExtensionOptions []*codectypes.Any @@ -114,6 +117,7 @@ func (w *builder) getTx() (*gogoTxWrapper, error) { Messages: anyMsgs, Memo: w.memo, TimeoutHeight: w.timeoutHeight, + TimeoutTimestamp: timestamppb.New(w.timeoutTimestamp), Unordered: w.unordered, ExtensionOptions: intoAnyV2(w.extensionOptions), NonCriticalExtensionOptions: intoAnyV2(w.nonCriticalExtensionOptions), @@ -188,6 +192,8 @@ func (w *builder) SetMsgs(msgs ...sdk.Msg) error { // SetTimeoutHeight sets the transaction's height timeout. func (w *builder) SetTimeoutHeight(height uint64) { w.timeoutHeight = height } +func (w *builder) SetTimeoutTimestamp(timestamp time.Time) { w.timeoutTimestamp = timestamp } + func (w *builder) SetUnordered(v bool) { w.unordered = v } func (w *builder) SetMemo(memo string) { w.memo = memo } From cce6b54a1d7f222f79508b096586c803f35499a5 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Thu, 4 Jul 2024 16:09:51 +0700 Subject: [PATCH 03/39] update snapshotter --- x/auth/ante/unorderedtx/manager.go | 21 ++++++++++++++++++--- x/auth/ante/unorderedtx/snapshotter.go | 17 ++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/x/auth/ante/unorderedtx/manager.go b/x/auth/ante/unorderedtx/manager.go index 1a685c584558..c005593adcd1 100644 --- a/x/auth/ante/unorderedtx/manager.go +++ b/x/auth/ante/unorderedtx/manager.go @@ -175,12 +175,12 @@ func (m *Manager) OnInit() error { timeStamp := binary.BigEndian.Uint64(buf[txHashSize+ttlSize:]) // if not zero value - if blockHeight != 0 { - m.Add(txHash, blockHeight) + if timeStamp != 0 { + m.AddTimestamp(txHash, time.Unix(int64(timeStamp), 0)) continue } - m.AddTimestamp(txHash, time.Unix(int64(timeStamp), 0)) + m.Add(txHash, blockHeight) } return nil @@ -216,6 +216,21 @@ func (m *Manager) exportSnapshot(height uint64, snapshotWriter func([]byte) erro } } + keys = maps.Keys(m.txHashesTimestamp) + sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i][:], keys[j][:]) < 0 }) + + for _, txHash := range keys { + timestamp := m.txHashesTimestamp[txHash] + + // right now we dont have access block time at this flow, so we would just include the expired txs + // and let it be purge during purge loop + chunk := unorderedTxToBytes(txHash, uint64(timestamp.Unix()), false) + + if _, err := w.Write(chunk); err != nil { + return fmt.Errorf("failed to write unordered tx to buffer: %w", err) + } + } + if err := w.Flush(); err != nil { return fmt.Errorf("failed to flush unordered txs buffer: %w", err) } diff --git a/x/auth/ante/unorderedtx/snapshotter.go b/x/auth/ante/unorderedtx/snapshotter.go index aef275138bf3..647f8340fa40 100644 --- a/x/auth/ante/unorderedtx/snapshotter.go +++ b/x/auth/ante/unorderedtx/snapshotter.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "errors" "io" + "time" snapshot "cosmossdk.io/store/snapshots/types" ) @@ -71,7 +72,7 @@ func (s *Snapshotter) restore(height uint64, payloadReader snapshot.ExtensionPay return err } - if len(payload)%chunkSize != 0 { + if len(payload)%newChukSize != 0 { return errors.New("invalid unordered txs payload length") } @@ -80,11 +81,21 @@ func (s *Snapshotter) restore(height uint64, payloadReader snapshot.ExtensionPay var txHash TxHash copy(txHash[:], payload[i:i+txHashSize]) - ttl := binary.BigEndian.Uint64(payload[i+txHashSize : i+chunkSize]) + ttl := binary.BigEndian.Uint64(payload[i+txHashSize : i+txHashSize+timeoutSize]) - if height < ttl { + if ttl != 0 && height < ttl { // only add unordered transactions that are still valid, i.e. unexpired s.m.Add(txHash, ttl) + i += chunkSize + continue + } + + timestamp := binary.BigEndian.Uint64(payload[i+txHashSize+timeoutSize : i+chunkSize]) + // need to come up with a way to fetch blocktime to filter out expired txs + if timestamp != 0 { + // right now we dont have access block time at this flow, so we would just include the expired txs + // and let it be purge during purge loop + s.m.AddTimestamp(txHash, time.Unix(int64(timestamp), 0)) } i += chunkSize From 6a1fe37509a415a8aa0b61f9b3c49df76096ef2b Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Thu, 4 Jul 2024 16:11:54 +0700 Subject: [PATCH 04/39] minor --- x/auth/ante/unorderedtx/manager.go | 16 ++++++++-------- x/auth/ante/unorderedtx/snapshotter.go | 7 +++---- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/x/auth/ante/unorderedtx/manager.go b/x/auth/ante/unorderedtx/manager.go index c005593adcd1..7cb443d6c53f 100644 --- a/x/auth/ante/unorderedtx/manager.go +++ b/x/auth/ante/unorderedtx/manager.go @@ -153,7 +153,7 @@ func (m *Manager) OnInit() error { var ( r = bufio.NewReader(f) - buf = make([]byte, newChukSize) + buf = make([]byte, chunkSize) ) for { n, err := io.ReadFull(r, buf) @@ -171,8 +171,8 @@ func (m *Manager) OnInit() error { var txHash TxHash copy(txHash[:], buf[:txHashSize]) - blockHeight := binary.BigEndian.Uint64(buf[txHashSize : txHashSize+ttlSize]) - timeStamp := binary.BigEndian.Uint64(buf[txHashSize+ttlSize:]) + blockHeight := binary.BigEndian.Uint64(buf[txHashSize : txHashSize+heightSize]) + timeStamp := binary.BigEndian.Uint64(buf[txHashSize+heightSize:]) // if not zero value if timeStamp != 0 { @@ -346,19 +346,19 @@ func (m *Manager) batchReceive() (uint64, time.Time, bool) { } func unorderedTxToBytes(txHash TxHash, ttl uint64, isBlockHeight bool) []byte { - chunk := make([]byte, newChukSize) + chunk := make([]byte, chunkSize) copy(chunk[:txHashSize], txHash[:]) - ttlBz := make([]byte, ttlSize) + ttlBz := make([]byte, heightSize) binary.BigEndian.PutUint64(ttlBz, ttl) emptyBz := make([]byte, 8) binary.BigEndian.PutUint64(emptyBz, 0) if isBlockHeight { copy(chunk[txHashSize+ttl:], emptyBz) - copy(chunk[txHashSize:txHashSize+ttlSize], ttlBz) + copy(chunk[txHashSize:txHashSize+heightSize], ttlBz) } else { - copy(chunk[txHashSize+ttlSize:], ttlBz) - copy(chunk[txHashSize:txHashSize+ttlSize], emptyBz) + copy(chunk[txHashSize+heightSize:], ttlBz) + copy(chunk[txHashSize:txHashSize+heightSize], emptyBz) } return chunk diff --git a/x/auth/ante/unorderedtx/snapshotter.go b/x/auth/ante/unorderedtx/snapshotter.go index 647f8340fa40..8bd440ccfa51 100644 --- a/x/auth/ante/unorderedtx/snapshotter.go +++ b/x/auth/ante/unorderedtx/snapshotter.go @@ -11,10 +11,9 @@ import ( const ( txHashSize = 32 - ttlSize = 8 + heightSize = 8 timeoutSize = 8 - chunkSize = txHashSize + ttlSize - newChukSize = txHashSize + ttlSize + timeoutSize + chunkSize = txHashSize + heightSize + timeoutSize ) var _ snapshot.ExtensionSnapshotter = &Snapshotter{} @@ -72,7 +71,7 @@ func (s *Snapshotter) restore(height uint64, payloadReader snapshot.ExtensionPay return err } - if len(payload)%newChukSize != 0 { + if len(payload)%chunkSize != 0 { return errors.New("invalid unordered txs payload length") } From 6b142ec8f26d85666201f53bf09713ab75cd19e6 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Thu, 4 Jul 2024 16:37:54 +0700 Subject: [PATCH 05/39] minor --- x/auth/ante/basic.go | 2 +- x/auth/ante/unorderedtx/manager.go | 2 +- x/auth/ante/unorderedtx/snapshotter.go | 22 +++++++++++----------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/x/auth/ante/basic.go b/x/auth/ante/basic.go index ba0e3e70e70e..572bda28c6a3 100644 --- a/x/auth/ante/basic.go +++ b/x/auth/ante/basic.go @@ -269,7 +269,7 @@ func (txh TxTimeoutHeightDecorator) ValidateTx(ctx context.Context, tx sdk.Tx) e } timeoutTimestamp := timeoutTx.GetTimeoutTimeStamp() - if timeoutTimestamp.IsZero() && timeoutTimestamp.Before(headerInfo.Time) { + if !timeoutTimestamp.IsZero() && timeoutTimestamp.Before(headerInfo.Time) { return errorsmod.Wrapf( sdkerrors.ErrTxTimeout, "block time: %s, timeout timestamp: %s", headerInfo.Time.String(), timeoutTimestamp.String(), ) diff --git a/x/auth/ante/unorderedtx/manager.go b/x/auth/ante/unorderedtx/manager.go index 7cb443d6c53f..fe6e679f762d 100644 --- a/x/auth/ante/unorderedtx/manager.go +++ b/x/auth/ante/unorderedtx/manager.go @@ -354,7 +354,7 @@ func unorderedTxToBytes(txHash TxHash, ttl uint64, isBlockHeight bool) []byte { emptyBz := make([]byte, 8) binary.BigEndian.PutUint64(emptyBz, 0) if isBlockHeight { - copy(chunk[txHashSize+ttl:], emptyBz) + copy(chunk[txHashSize+heightSize:], emptyBz) copy(chunk[txHashSize:txHashSize+heightSize], ttlBz) } else { copy(chunk[txHashSize+heightSize:], ttlBz) diff --git a/x/auth/ante/unorderedtx/snapshotter.go b/x/auth/ante/unorderedtx/snapshotter.go index 8bd440ccfa51..7cc0dbafacc9 100644 --- a/x/auth/ante/unorderedtx/snapshotter.go +++ b/x/auth/ante/unorderedtx/snapshotter.go @@ -80,21 +80,21 @@ func (s *Snapshotter) restore(height uint64, payloadReader snapshot.ExtensionPay var txHash TxHash copy(txHash[:], payload[i:i+txHashSize]) - ttl := binary.BigEndian.Uint64(payload[i+txHashSize : i+txHashSize+timeoutSize]) + timestamp := binary.BigEndian.Uint64(payload[i+txHashSize+heightSize : i+chunkSize]) + // need to come up with a way to fetch blocktime to filter out expired txs + // + // right now we dont have access block time at this flow, so we would just include the expired txs + // and let it be purge during purge loop + if timestamp != 0 { + s.m.AddTimestamp(txHash, time.Unix(int64(timestamp), 0)) + continue + } - if ttl != 0 && height < ttl { + ttl := binary.BigEndian.Uint64(payload[i+txHashSize : i+txHashSize+heightSize]) + if height < ttl { // only add unordered transactions that are still valid, i.e. unexpired s.m.Add(txHash, ttl) i += chunkSize - continue - } - - timestamp := binary.BigEndian.Uint64(payload[i+txHashSize+timeoutSize : i+chunkSize]) - // need to come up with a way to fetch blocktime to filter out expired txs - if timestamp != 0 { - // right now we dont have access block time at this flow, so we would just include the expired txs - // and let it be purge during purge loop - s.m.AddTimestamp(txHash, time.Unix(int64(timestamp), 0)) } i += chunkSize From 6e2aa2796df7c929ec7f25a1563d0d75902b5f68 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Thu, 4 Jul 2024 16:59:29 +0700 Subject: [PATCH 06/39] fix test --- x/auth/ante/unorderedtx/snapshotter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/auth/ante/unorderedtx/snapshotter.go b/x/auth/ante/unorderedtx/snapshotter.go index 7cc0dbafacc9..4516624c7ed4 100644 --- a/x/auth/ante/unorderedtx/snapshotter.go +++ b/x/auth/ante/unorderedtx/snapshotter.go @@ -87,6 +87,7 @@ func (s *Snapshotter) restore(height uint64, payloadReader snapshot.ExtensionPay // and let it be purge during purge loop if timestamp != 0 { s.m.AddTimestamp(txHash, time.Unix(int64(timestamp), 0)) + i += chunkSize continue } @@ -94,7 +95,6 @@ func (s *Snapshotter) restore(height uint64, payloadReader snapshot.ExtensionPay if height < ttl { // only add unordered transactions that are still valid, i.e. unexpired s.m.Add(txHash, ttl) - i += chunkSize } i += chunkSize From ae1ca05529c89baaef4a9d69a874db486878b038 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Fri, 5 Jul 2024 13:35:22 +0700 Subject: [PATCH 07/39] fix tests --- api/cosmos/tx/v1beta1/tx.pulsar.go | 208 +++++++++--------- client/tx/factory.go | 2 + .../v2/autocli/testdata/help-echo-msg.golden | 1 + client/v2/autocli/testdata/msg-output.golden | 2 +- proto/cosmos/tx/v1beta1/tx.proto | 2 +- types/tx/tx.pb.go | 138 ++++++------ 6 files changed, 178 insertions(+), 175 deletions(-) diff --git a/api/cosmos/tx/v1beta1/tx.pulsar.go b/api/cosmos/tx/v1beta1/tx.pulsar.go index 1043981d63b6..5a8c25c45894 100644 --- a/api/cosmos/tx/v1beta1/tx.pulsar.go +++ b/api/cosmos/tx/v1beta1/tx.pulsar.go @@ -9197,7 +9197,7 @@ var file_cosmos_tx_v1beta1_tx_proto_rawDesc = []byte{ 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x69, 0x70, 0x42, 0x02, 0x18, 0x01, 0x52, 0x03, 0x74, 0x69, 0x70, 0x3a, 0x13, 0xd2, 0xb4, 0x2d, 0x0f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, - 0x6b, 0x20, 0x30, 0x2e, 0x34, 0x36, 0x22, 0x82, 0x03, 0x0a, 0x06, 0x54, 0x78, 0x42, 0x6f, 0x64, + 0x6b, 0x20, 0x30, 0x2e, 0x34, 0x36, 0x22, 0x86, 0x03, 0x0a, 0x06, 0x54, 0x78, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x30, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, @@ -9206,82 +9206,66 @@ var file_cosmos_tx_v1beta1_tx_proto_rawDesc = []byte{ 0x75, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x09, 0x75, 0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x12, 0x4d, 0x0a, 0x11, + 0x08, 0x52, 0x09, 0x75, 0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x12, 0x51, 0x0a, 0x11, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x42, 0x04, 0x90, 0xdf, 0x1f, 0x01, 0x52, 0x10, 0x74, 0x69, 0x6d, 0x65, 0x6f, - 0x75, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x42, 0x0a, 0x11, 0x65, - 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0xff, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x10, 0x65, - 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x5a, 0x0a, 0x1e, 0x6e, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, - 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0xff, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x1b, - 0x6e, 0x6f, 0x6e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, - 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb7, 0x01, 0x0a, 0x08, - 0x41, 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x40, 0x0a, 0x0c, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x73, - 0x69, 0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x12, 0x28, 0x0a, 0x03, 0x66, 0x65, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x46, 0x65, 0x65, 0x52, - 0x03, 0x66, 0x65, 0x65, 0x12, 0x3f, 0x0a, 0x03, 0x74, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x69, 0x70, 0x42, 0x15, 0x18, 0x01, 0xda, 0xb4, 0x2d, - 0x0f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x20, 0x30, 0x2e, 0x34, 0x36, - 0x52, 0x03, 0x74, 0x69, 0x70, 0x22, 0x97, 0x01, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x09, - 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x38, 0x0a, 0x09, 0x6d, 0x6f, 0x64, - 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6d, 0x6f, 0x64, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, - 0xe0, 0x02, 0x0a, 0x08, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3c, 0x0a, 0x06, - 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, - 0x48, 0x00, 0x52, 0x06, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x12, 0x39, 0x0a, 0x05, 0x6d, 0x75, - 0x6c, 0x74, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, - 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x48, 0x00, 0x52, 0x05, - 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x1a, 0x41, 0x0a, 0x06, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x12, - 0x37, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, - 0x67, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x6f, - 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x1a, 0x90, 0x01, 0x0a, 0x05, 0x4d, 0x75, 0x6c, - 0x74, 0x69, 0x12, 0x4b, 0x0a, 0x08, 0x62, 0x69, 0x74, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x69, 0x67, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x69, 0x74, - 0x41, 0x72, 0x72, 0x61, 0x79, 0x52, 0x08, 0x62, 0x69, 0x74, 0x61, 0x72, 0x72, 0x61, 0x79, 0x12, - 0x3a, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x42, 0x05, 0x0a, 0x03, 0x73, - 0x75, 0x6d, 0x22, 0x81, 0x02, 0x0a, 0x03, 0x46, 0x65, 0x65, 0x12, 0x79, 0x0a, 0x06, 0x61, 0x6d, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x46, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x28, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x9a, 0xe7, 0xb0, 0x2a, 0x0c, 0x6c, 0x65, 0x67, 0x61, - 0x63, 0x79, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, - 0x69, 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x70, 0x61, 0x79, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x05, 0x70, 0x61, 0x79, - 0x65, 0x72, 0x12, 0x32, 0x0a, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x67, - 0x72, 0x61, 0x6e, 0x74, 0x65, 0x72, 0x22, 0xc9, 0x01, 0x0a, 0x03, 0x54, 0x69, 0x70, 0x12, 0x79, + 0x61, 0x6d, 0x70, 0x42, 0x08, 0xc8, 0xde, 0x1f, 0x01, 0x90, 0xdf, 0x1f, 0x01, 0x52, 0x10, 0x74, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x42, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xff, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, + 0x79, 0x52, 0x10, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x5a, 0x0a, 0x1e, 0x6e, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x69, 0x74, 0x69, + 0x63, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xff, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, + 0x6e, 0x79, 0x52, 0x1b, 0x6e, 0x6f, 0x6e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x45, + 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0xb7, 0x01, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x40, 0x0a, 0x0c, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x12, 0x28, + 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, + 0x46, 0x65, 0x65, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x3f, 0x0a, 0x03, 0x74, 0x69, 0x70, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, + 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x69, 0x70, 0x42, 0x15, 0x18, + 0x01, 0xda, 0xb4, 0x2d, 0x0f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x20, + 0x30, 0x2e, 0x34, 0x36, 0x52, 0x03, 0x74, 0x69, 0x70, 0x22, 0x97, 0x01, 0x0a, 0x0a, 0x53, 0x69, + 0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, + 0x6e, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x38, 0x0a, + 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6d, + 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x65, 0x22, 0xe0, 0x02, 0x0a, 0x08, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x69, + 0x6e, 0x67, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x06, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x12, 0x39, + 0x0a, 0x05, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, + 0x48, 0x00, 0x52, 0x05, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x1a, 0x41, 0x0a, 0x06, 0x53, 0x69, 0x6e, + 0x67, 0x6c, 0x65, 0x12, 0x37, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, + 0x67, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x1a, 0x90, 0x01, 0x0a, + 0x05, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x12, 0x4b, 0x0a, 0x08, 0x62, 0x69, 0x74, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x69, + 0x67, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, + 0x74, 0x42, 0x69, 0x74, 0x41, 0x72, 0x72, 0x61, 0x79, 0x52, 0x08, 0x62, 0x69, 0x74, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x12, 0x3a, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x42, + 0x05, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x22, 0x81, 0x02, 0x0a, 0x03, 0x46, 0x65, 0x65, 0x12, 0x79, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x46, 0xc8, 0xde, 0x1f, 0x00, 0xaa, @@ -9289,38 +9273,54 @@ var file_cosmos_tx_v1beta1_tx_proto_rawDesc = []byte{ 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x9a, 0xe7, 0xb0, 0x2a, 0x0c, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0xa8, 0xe7, 0xb0, 0x2a, - 0x01, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x06, 0x74, 0x69, 0x70, - 0x70, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x52, 0x06, 0x74, 0x69, 0x70, 0x70, 0x65, 0x72, 0x3a, 0x15, 0x18, 0x01, 0xd2, - 0xb4, 0x2d, 0x0f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x20, 0x30, 0x2e, - 0x34, 0x36, 0x22, 0xe3, 0x01, 0x0a, 0x0d, 0x41, 0x75, 0x78, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, - 0x44, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x01, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, + 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x67, 0x61, + 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x70, 0x61, 0x79, 0x65, 0x72, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, - 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3e, 0x0a, 0x08, 0x73, 0x69, 0x67, 0x6e, - 0x5f, 0x64, 0x6f, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, - 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x41, 0x75, 0x78, 0x52, - 0x07, 0x73, 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x12, 0x37, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x74, 0x78, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, - 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, - 0x73, 0x69, 0x67, 0x3a, 0x13, 0xd2, 0xb4, 0x2d, 0x0f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, - 0x73, 0x64, 0x6b, 0x20, 0x30, 0x2e, 0x34, 0x36, 0x42, 0xb4, 0x01, 0x0a, 0x15, 0x63, 0x6f, 0x6d, + 0x05, 0x70, 0x61, 0x79, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, + 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x72, 0x22, 0xc9, 0x01, 0x0a, 0x03, 0x54, + 0x69, 0x70, 0x12, 0x79, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x46, 0xc8, + 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, + 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x9a, + 0xe7, 0xb0, 0x2a, 0x0c, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x73, + 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, + 0x06, 0x74, 0x69, 0x70, 0x70, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, + 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x06, 0x74, 0x69, 0x70, 0x70, 0x65, 0x72, 0x3a, + 0x15, 0x18, 0x01, 0xd2, 0xb4, 0x2d, 0x0f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, + 0x6b, 0x20, 0x30, 0x2e, 0x34, 0x36, 0x22, 0xe3, 0x01, 0x0a, 0x0d, 0x41, 0x75, 0x78, 0x53, 0x69, + 0x67, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3e, 0x0a, 0x08, + 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x64, 0x6f, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x3b, 0x74, 0x78, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x54, - 0x58, 0xaa, 0x02, 0x11, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x54, 0x78, 0x2e, 0x56, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x11, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x54, - 0x78, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1d, 0x43, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x5c, 0x54, 0x78, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, - 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x3a, 0x3a, 0x54, 0x78, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x41, 0x75, 0x78, 0x52, 0x07, 0x73, 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x12, 0x37, 0x0a, 0x04, + 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x52, + 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x3a, 0x13, 0xd2, 0xb4, 0x2d, 0x0f, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x20, 0x30, 0x2e, 0x34, 0x36, 0x42, 0xb4, 0x01, 0x0a, + 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, + 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x74, 0x78, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, + 0x02, 0x03, 0x43, 0x54, 0x58, 0xaa, 0x02, 0x11, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x54, + 0x78, 0x2e, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x11, 0x43, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x5c, 0x54, 0x78, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1d, + 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x54, 0x78, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, + 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x54, 0x78, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/client/tx/factory.go b/client/tx/factory.go index e0a204c553dc..d2e0146de7bc 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -413,6 +413,8 @@ func (f Factory) PrintUnsignedTx(clientCtx client.Context, msgs ...sdk.Msg) erro return err } + fmt.Println(unsignedTx) + encoder := f.txConfig.TxJSONEncoder() if encoder == nil { return errors.New("cannot print unsigned tx: tx json encoder is nil") diff --git a/client/v2/autocli/testdata/help-echo-msg.golden b/client/v2/autocli/testdata/help-echo-msg.golden index fc981ffd4611..2b631ab0642b 100644 --- a/client/v2/autocli/testdata/help-echo-msg.golden +++ b/client/v2/autocli/testdata/help-echo-msg.golden @@ -28,6 +28,7 @@ Flags: -s, --sequence uint The sequence number of the signing account (offline mode only) --sign-mode string Choose sign mode (direct|amino-json|direct-aux|textual), this is an advanced feature --timeout-height uint Set a block timeout height to prevent the tx from being committed past a certain height + --timeout-timestamp int Set a block timeout timestamp to prevent the tx from being committed past a certain time --tip string Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator --unordered Enable unordered transaction delivery; must be used in conjunction with --timeout-height -y, --yes Skip tx broadcasting prompt confirmation diff --git a/client/v2/autocli/testdata/msg-output.golden b/client/v2/autocli/testdata/msg-output.golden index 924f3eeee5d5..8e075ccb1470 100644 --- a/client/v2/autocli/testdata/msg-output.golden +++ b/client/v2/autocli/testdata/msg-output.golden @@ -1 +1 @@ -{"body":{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk","to_address":"cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk","amount":[{"denom":"foo","amount":"1"}]}]},"auth_info":{"fee":{"gas_limit":"200000"}}} +{"body":{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk","to_address":"cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk","amount":[{"denom":"foo","amount":"1"}]}],"timeout_timestamp":"1970-01-01T00:00:00Z"},"auth_info":{"fee":{"gas_limit":"200000"}}} \ No newline at end of file diff --git a/proto/cosmos/tx/v1beta1/tx.proto b/proto/cosmos/tx/v1beta1/tx.proto index f97d0999e1ec..408573ee439b 100644 --- a/proto/cosmos/tx/v1beta1/tx.proto +++ b/proto/cosmos/tx/v1beta1/tx.proto @@ -134,7 +134,7 @@ message TxBody { // Note, if unordered=true this value MUST be set // and will act as a short-lived TTL in which the transaction is deemed valid // and kept in memory to prevent duplicates. - google.protobuf.Timestamp timeout_timestamp = 5 [(gogoproto.stdtime) = true]; + google.protobuf.Timestamp timeout_timestamp = 5 [(gogoproto.nullable) = true, (gogoproto.stdtime) = true]; // extension_options are arbitrary options that can be added by chains // when the default options are not sufficient. If any of these are present diff --git a/types/tx/tx.pb.go b/types/tx/tx.pb.go index 9ea952ea7f5f..7572f91bfef3 100644 --- a/types/tx/tx.pb.go +++ b/types/tx/tx.pb.go @@ -1054,79 +1054,79 @@ func init() { func init() { proto.RegisterFile("cosmos/tx/v1beta1/tx.proto", fileDescriptor_96d1575ffde80842) } var fileDescriptor_96d1575ffde80842 = []byte{ - // 1143 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xf7, 0x7a, 0x6d, 0xc7, 0x7e, 0x4d, 0xda, 0x64, 0x68, 0x91, 0xe3, 0x52, 0x27, 0xb8, 0x2a, - 0x58, 0x15, 0xd9, 0x6d, 0x53, 0x04, 0xa5, 0x42, 0x14, 0xbb, 0xa5, 0x6a, 0x55, 0x0a, 0xd2, 0x26, - 0xa7, 0x5e, 0x56, 0xe3, 0xdd, 0xc9, 0x7a, 0x54, 0xef, 0xcc, 0xb2, 0x33, 0x0b, 0xde, 0x23, 0x5c, - 0x38, 0x21, 0x55, 0x5c, 0x90, 0xf8, 0x04, 0x88, 0x53, 0x0f, 0x95, 0xf8, 0x0a, 0xe5, 0x56, 0xf5, - 0x84, 0x38, 0xd0, 0xaa, 0x39, 0xf4, 0x63, 0x80, 0x76, 0x76, 0x76, 0x93, 0x26, 0xae, 0x03, 0x02, - 0x89, 0x8b, 0xb5, 0xf3, 0xe6, 0xf7, 0xde, 0xfc, 0xde, 0x7f, 0x43, 0xc7, 0xe3, 0x22, 0xe4, 0xc2, - 0x96, 0x53, 0xfb, 0xcb, 0x8b, 0x23, 0x22, 0xf1, 0x45, 0x5b, 0x4e, 0xad, 0x28, 0xe6, 0x92, 0xa3, - 0x95, 0xfc, 0xce, 0x92, 0x53, 0x4b, 0xdf, 0x75, 0x56, 0x73, 0x91, 0xab, 0x00, 0xb6, 0xbe, 0x57, - 0x87, 0xce, 0x0a, 0x0e, 0x29, 0xe3, 0xb6, 0xfa, 0xd5, 0xa2, 0x93, 0x01, 0x0f, 0x78, 0x0e, 0xcd, - 0xbe, 0xb4, 0x74, 0x43, 0x3f, 0xe9, 0xc5, 0x69, 0x24, 0xb9, 0x1d, 0x26, 0x13, 0x49, 0x05, 0x0d, - 0xca, 0xf7, 0x0b, 0x81, 0x86, 0x77, 0x35, 0x7c, 0x84, 0x05, 0x29, 0x31, 0x1e, 0xa7, 0x4c, 0xdf, - 0xbf, 0xbd, 0xe7, 0x81, 0xa0, 0x01, 0xa3, 0x6c, 0xcf, 0x92, 0x3e, 0x6b, 0xe0, 0x6a, 0xc0, 0x79, - 0x30, 0x21, 0xb6, 0x3a, 0x8d, 0x92, 0x1d, 0x1b, 0xb3, 0x54, 0x5f, 0xad, 0x1d, 0xbc, 0x92, 0x34, - 0x24, 0x42, 0xe2, 0x30, 0xca, 0x01, 0xbd, 0xef, 0x0c, 0xa8, 0x6e, 0x4f, 0xd1, 0x06, 0xd4, 0x46, - 0xdc, 0x4f, 0xdb, 0xc6, 0xba, 0xd1, 0x3f, 0xb6, 0xb9, 0x6a, 0x1d, 0x0a, 0x90, 0xb5, 0x3d, 0x1d, - 0x72, 0x3f, 0x75, 0x14, 0x0c, 0x5d, 0x86, 0x16, 0x4e, 0xe4, 0xd8, 0xa5, 0x6c, 0x87, 0xb7, 0xab, - 0x4a, 0xe7, 0xf4, 0x0c, 0x9d, 0x41, 0x22, 0xc7, 0xb7, 0xd8, 0x0e, 0x77, 0x9a, 0x58, 0x7f, 0xa1, + // 1147 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0x4f, 0x8f, 0xdb, 0x44, + 0x14, 0x8f, 0xe3, 0x24, 0x9b, 0xbc, 0xee, 0xb6, 0xbb, 0x43, 0x8b, 0xb2, 0x29, 0xcd, 0x2e, 0xa9, + 0x0a, 0x51, 0xc5, 0xda, 0xed, 0x16, 0x41, 0xa9, 0x10, 0x25, 0x69, 0xa9, 0x5a, 0x95, 0x82, 0xf0, + 0xee, 0xa9, 0x17, 0x6b, 0x62, 0xcf, 0x3a, 0xa3, 0xc6, 0x33, 0xc6, 0x33, 0x86, 0xf8, 0xc8, 0x05, + 0x4e, 0x48, 0x15, 0x17, 0x24, 0x3e, 0x01, 0xe2, 0xd4, 0x43, 0x25, 0xbe, 0x42, 0xb9, 0x55, 0x3d, + 0x21, 0x0e, 0x6d, 0xd5, 0x3d, 0xf4, 0x63, 0x80, 0x3c, 0x1e, 0x7b, 0xb7, 0xdd, 0x34, 0x0b, 0x02, + 0x89, 0x4b, 0xe4, 0x79, 0xf3, 0x7b, 0x6f, 0x7e, 0xef, 0x7f, 0xa0, 0xe3, 0x71, 0x11, 0x72, 0x61, + 0xcb, 0xa9, 0xfd, 0xd5, 0xf9, 0x11, 0x91, 0xf8, 0xbc, 0x2d, 0xa7, 0x56, 0x14, 0x73, 0xc9, 0xd1, + 0x4a, 0x7e, 0x67, 0xc9, 0xa9, 0xa5, 0xef, 0x3a, 0xab, 0xb9, 0xc8, 0x55, 0x00, 0x5b, 0xdf, 0xab, + 0x43, 0x67, 0x05, 0x87, 0x94, 0x71, 0x5b, 0xfd, 0x6a, 0xd1, 0xf1, 0x80, 0x07, 0x3c, 0x87, 0x66, + 0x5f, 0x5a, 0xba, 0xa1, 0x9f, 0xf4, 0xe2, 0x34, 0x92, 0xdc, 0x0e, 0x93, 0x89, 0xa4, 0x82, 0x06, + 0xe5, 0xfb, 0x85, 0x40, 0xc3, 0xbb, 0x1a, 0x3e, 0xc2, 0x82, 0x94, 0x18, 0x8f, 0x53, 0xa6, 0xef, + 0xdf, 0xde, 0xf3, 0x40, 0xd0, 0x80, 0x51, 0xb6, 0x67, 0x49, 0x9f, 0x35, 0x70, 0x35, 0xe0, 0x3c, + 0x98, 0x10, 0x5b, 0x9d, 0x46, 0xc9, 0x8e, 0x8d, 0x59, 0xaa, 0xaf, 0xd6, 0x5e, 0xbe, 0x92, 0x34, + 0x24, 0x42, 0xe2, 0x30, 0xca, 0x01, 0xbd, 0xef, 0x0d, 0xa8, 0x6e, 0x4f, 0xd1, 0x06, 0xd4, 0x46, + 0xdc, 0x4f, 0xdb, 0xc6, 0xba, 0xd1, 0x3f, 0xb2, 0xb9, 0x6a, 0x1d, 0x08, 0x90, 0xb5, 0x3d, 0x1d, + 0x72, 0x3f, 0x75, 0x14, 0x0c, 0x5d, 0x84, 0x16, 0x4e, 0xe4, 0xd8, 0xa5, 0x6c, 0x87, 0xb7, 0xab, + 0x4a, 0xe7, 0xe4, 0x0c, 0x9d, 0x41, 0x22, 0xc7, 0x37, 0xd8, 0x0e, 0x77, 0x9a, 0x58, 0x7f, 0xa1, 0x2e, 0x40, 0x46, 0x1e, 0xcb, 0x24, 0x26, 0xa2, 0x6d, 0xae, 0x9b, 0xfd, 0x45, 0x67, 0x9f, 0xa4, - 0xc7, 0xa0, 0xbe, 0x3d, 0x75, 0xf0, 0x57, 0xe8, 0x0c, 0x40, 0xf6, 0x94, 0x3b, 0x4a, 0x25, 0x11, - 0x8a, 0xd7, 0xa2, 0xd3, 0xca, 0x24, 0xc3, 0x4c, 0x80, 0xde, 0x82, 0x13, 0x25, 0x03, 0x8d, 0xa9, - 0x2a, 0xcc, 0x52, 0xf1, 0x54, 0x8e, 0x3b, 0xea, 0xbd, 0xef, 0x0d, 0x58, 0xd8, 0xa2, 0x01, 0xbb, - 0xce, 0xbd, 0xff, 0xea, 0xc9, 0x55, 0x68, 0x7a, 0x63, 0x4c, 0x99, 0x4b, 0xfd, 0xb6, 0xb9, 0x6e, - 0xf4, 0x5b, 0xce, 0x82, 0x3a, 0xdf, 0xf2, 0xd1, 0x39, 0x38, 0x8e, 0x3d, 0x8f, 0x27, 0x4c, 0xba, + 0xc7, 0xa0, 0xbe, 0x3d, 0x75, 0xf0, 0xd7, 0xe8, 0x14, 0x40, 0xf6, 0x94, 0x3b, 0x4a, 0x25, 0x11, + 0x8a, 0xd7, 0xa2, 0xd3, 0xca, 0x24, 0xc3, 0x4c, 0x80, 0xde, 0x82, 0x63, 0x25, 0x03, 0x8d, 0xa9, + 0x2a, 0xcc, 0x52, 0xf1, 0x54, 0x8e, 0x3b, 0xec, 0xbd, 0x1f, 0x0c, 0x58, 0xd8, 0xa2, 0x01, 0xbb, + 0xca, 0xbd, 0xff, 0xea, 0xc9, 0x55, 0x68, 0x7a, 0x63, 0x4c, 0x99, 0x4b, 0xfd, 0xb6, 0xb9, 0x6e, + 0xf4, 0x5b, 0xce, 0x82, 0x3a, 0xdf, 0xf0, 0xd1, 0x19, 0x38, 0x8a, 0x3d, 0x8f, 0x27, 0x4c, 0xba, 0x2c, 0x09, 0x47, 0x24, 0x6e, 0xd7, 0xd6, 0x8d, 0x7e, 0xcd, 0x59, 0xd2, 0xd2, 0xcf, 0x94, 0xb0, - 0xf7, 0x6d, 0x15, 0x96, 0x35, 0xa9, 0xeb, 0x34, 0x26, 0x9e, 0x1c, 0x24, 0xd3, 0xa3, 0xd8, 0x5d, - 0x02, 0x88, 0x92, 0xd1, 0x84, 0x7a, 0xee, 0x3d, 0x92, 0xea, 0x9c, 0x9c, 0xb4, 0xf2, 0xf4, 0x5b, - 0x45, 0xfa, 0xad, 0x01, 0x4b, 0x9d, 0x56, 0x8e, 0xbb, 0x4d, 0xd2, 0x7f, 0x4f, 0x15, 0x75, 0xa0, - 0x29, 0xc8, 0x17, 0x09, 0x61, 0x1e, 0x69, 0xd7, 0x15, 0xa0, 0x3c, 0xa3, 0x77, 0xc0, 0x94, 0x34, - 0x6a, 0x37, 0x14, 0x97, 0xd7, 0x67, 0xd5, 0x14, 0x8d, 0x86, 0xd5, 0xb6, 0xe1, 0x64, 0xb0, 0x2b, - 0xaf, 0x3d, 0x79, 0xb8, 0x71, 0x22, 0xc7, 0x6c, 0x08, 0xff, 0xde, 0xfa, 0x05, 0xeb, 0xdd, 0xf7, - 0x7a, 0xdf, 0x98, 0xd0, 0xc8, 0x2b, 0x0f, 0x5d, 0x80, 0x66, 0x48, 0x84, 0xc0, 0x81, 0xf2, 0xde, + 0xf7, 0x5d, 0x15, 0x96, 0x35, 0xa9, 0xab, 0x34, 0x26, 0x9e, 0x1c, 0x24, 0xd3, 0xc3, 0xd8, 0x5d, + 0x00, 0x88, 0x92, 0xd1, 0x84, 0x7a, 0xee, 0x1d, 0x92, 0xea, 0x9c, 0x1c, 0xb7, 0xf2, 0xf4, 0x5b, + 0x45, 0xfa, 0xad, 0x01, 0x4b, 0x9d, 0x56, 0x8e, 0xbb, 0x49, 0xd2, 0x7f, 0x4f, 0x15, 0x75, 0xa0, + 0x29, 0xc8, 0x97, 0x09, 0x61, 0x1e, 0x69, 0xd7, 0x15, 0xa0, 0x3c, 0xa3, 0x77, 0xc0, 0x94, 0x34, + 0x6a, 0x37, 0x14, 0x97, 0xd7, 0x67, 0xd5, 0x14, 0x8d, 0x86, 0xd5, 0xb6, 0xe1, 0x64, 0xb0, 0x4b, + 0xaf, 0x3d, 0xba, 0xbf, 0x71, 0x2c, 0xc7, 0x6c, 0x08, 0xff, 0xce, 0xfa, 0x39, 0xeb, 0xdd, 0xf7, + 0x7a, 0xdf, 0x9a, 0xd0, 0xc8, 0x2b, 0x0f, 0x9d, 0x83, 0x66, 0x48, 0x84, 0xc0, 0x81, 0xf2, 0xde, 0x7c, 0xa5, 0x7b, 0x25, 0x0a, 0x21, 0xa8, 0x85, 0x24, 0xcc, 0x0b, 0xb4, 0xe5, 0xa8, 0xef, 0xcc, 0xad, 0xac, 0x05, 0x78, 0x22, 0xdd, 0x31, 0xa1, 0xc1, 0x58, 0x2a, 0xbf, 0x6b, 0xce, 0x92, 0x96, - 0xde, 0x54, 0x42, 0xf4, 0x06, 0xb4, 0x12, 0xc6, 0x63, 0x9f, 0xc4, 0xc4, 0x57, 0x8e, 0x37, 0x9d, - 0x3d, 0x01, 0xba, 0x03, 0x2b, 0x85, 0x91, 0xb2, 0x9f, 0x94, 0xf7, 0xc7, 0x36, 0x3b, 0x87, 0x38, - 0x6d, 0x17, 0x88, 0x61, 0xed, 0xfe, 0xd3, 0x35, 0xc3, 0x59, 0xd6, 0xaa, 0xa5, 0x1c, 0x0d, 0x61, - 0x85, 0x4c, 0x25, 0x61, 0x82, 0x72, 0xe6, 0xf2, 0x48, 0x52, 0xce, 0x44, 0xfb, 0xcf, 0x85, 0x39, - 0x3e, 0x2e, 0x97, 0xf8, 0xcf, 0x73, 0x38, 0xba, 0x0b, 0x5d, 0xc6, 0x99, 0xeb, 0xc5, 0x54, 0x52, - 0x0f, 0x4f, 0xdc, 0x19, 0x06, 0x4f, 0xcc, 0x31, 0x78, 0x9a, 0x71, 0x76, 0x4d, 0xeb, 0x7e, 0x72, - 0xc0, 0x76, 0xef, 0x17, 0x03, 0x9a, 0x45, 0x2b, 0xa3, 0x8f, 0x61, 0x31, 0x6b, 0x1f, 0x12, 0xab, - 0x3e, 0x28, 0x52, 0x71, 0x66, 0x46, 0x76, 0xb7, 0x14, 0x4c, 0xf5, 0xff, 0x31, 0x51, 0x7e, 0x0b, - 0xd4, 0x07, 0x73, 0x87, 0x10, 0x5d, 0xa2, 0xb3, 0xca, 0xe2, 0x06, 0x21, 0x4e, 0x06, 0x41, 0x57, - 0xf3, 0x02, 0x32, 0xe7, 0x16, 0xd0, 0xa9, 0xdf, 0x0f, 0xd7, 0x8d, 0xae, 0xa9, 0xde, 0x0f, 0x06, - 0xc0, 0x1e, 0x8d, 0x03, 0x3d, 0x62, 0xfc, 0xbd, 0x1e, 0xb9, 0x0c, 0xad, 0x90, 0xfb, 0xe4, 0xa8, - 0x59, 0x77, 0x87, 0xfb, 0x24, 0x9f, 0x75, 0xa1, 0xfe, 0x7a, 0xa9, 0x37, 0xcc, 0x97, 0x7b, 0xa3, - 0xf7, 0xac, 0x0a, 0xcd, 0x42, 0x05, 0x7d, 0x08, 0x0d, 0x41, 0x59, 0x30, 0x21, 0x9a, 0x53, 0x6f, - 0x8e, 0x7d, 0x6b, 0x4b, 0x21, 0x6f, 0x56, 0x1c, 0xad, 0x83, 0x3e, 0x80, 0xba, 0xda, 0x2c, 0x9a, - 0xdc, 0x9b, 0xf3, 0x94, 0xef, 0x64, 0xc0, 0x9b, 0x15, 0x27, 0xd7, 0xe8, 0x0c, 0xa0, 0x91, 0x9b, - 0x43, 0xef, 0x43, 0x2d, 0xe3, 0xad, 0x08, 0x1c, 0xdf, 0x3c, 0xbb, 0xcf, 0x46, 0xb1, 0x6b, 0xf6, - 0xa7, 0x35, 0xb3, 0xe7, 0x28, 0x85, 0xce, 0x7d, 0x03, 0xea, 0xca, 0x2a, 0xba, 0x0d, 0xcd, 0x11, - 0x95, 0x38, 0x8e, 0x71, 0x11, 0x5b, 0xbb, 0x30, 0x93, 0x6f, 0x44, 0xab, 0x5c, 0x80, 0x85, 0xad, - 0x6b, 0x3c, 0x8c, 0xb0, 0x27, 0x87, 0x54, 0x0e, 0x32, 0x35, 0xa7, 0x34, 0x80, 0xae, 0x00, 0x94, - 0x51, 0xcf, 0xe6, 0xac, 0x79, 0x54, 0xd8, 0x5b, 0x45, 0xd8, 0xc5, 0xb0, 0x0e, 0xa6, 0x48, 0xc2, - 0xde, 0xd7, 0x55, 0x30, 0x6f, 0x10, 0x82, 0x52, 0x68, 0xe0, 0x30, 0x1b, 0x59, 0xba, 0x56, 0xcb, - 0xed, 0x96, 0x2d, 0xde, 0x7d, 0x54, 0x28, 0x1b, 0xde, 0x78, 0xf4, 0xc7, 0x5a, 0xe5, 0xe7, 0xa7, - 0x6b, 0xfd, 0x80, 0xca, 0x71, 0x32, 0xb2, 0x3c, 0x1e, 0xda, 0xc5, 0x52, 0x2f, 0x2b, 0xcc, 0x96, - 0x69, 0x44, 0x84, 0x52, 0x10, 0x3f, 0xbe, 0x78, 0x70, 0x7e, 0x71, 0x42, 0x02, 0xec, 0xa5, 0x6e, - 0xb6, 0xba, 0xc5, 0x4f, 0x2f, 0x1e, 0x9c, 0x37, 0x1c, 0xfd, 0x20, 0x3a, 0x0d, 0xad, 0x00, 0x0b, - 0x77, 0x42, 0x43, 0x2a, 0x55, 0x7a, 0x6a, 0x4e, 0x33, 0xc0, 0xe2, 0xd3, 0xec, 0x8c, 0x2c, 0xa8, - 0x47, 0x38, 0x25, 0x71, 0x3e, 0x79, 0x87, 0xed, 0x27, 0x0f, 0x37, 0x4e, 0x6a, 0x66, 0x03, 0xdf, - 0x8f, 0x89, 0x10, 0x5b, 0x32, 0xa6, 0x2c, 0x70, 0x72, 0x18, 0xda, 0x84, 0x85, 0x20, 0xc6, 0x4c, - 0xea, 0x51, 0x3c, 0x4f, 0xa3, 0x00, 0xf6, 0x7e, 0x35, 0xc0, 0xdc, 0xa6, 0xd1, 0xff, 0x19, 0x83, - 0x0b, 0xd0, 0x90, 0x34, 0x8a, 0x48, 0x9c, 0xcf, 0xe1, 0x39, 0xac, 0x35, 0xee, 0xca, 0xa9, 0x27, - 0xb3, 0x3a, 0xba, 0xb7, 0x6b, 0xc0, 0xd2, 0x20, 0x99, 0xe6, 0xfd, 0x7c, 0x1d, 0x4b, 0x9c, 0x45, - 0x04, 0xe7, 0x16, 0x54, 0xc1, 0xcd, 0x8d, 0x88, 0x06, 0xa2, 0x8f, 0xa0, 0x99, 0x55, 0xb4, 0xeb, - 0x73, 0x4f, 0x37, 0xcc, 0xd9, 0x57, 0xcc, 0xae, 0xfd, 0xdb, 0xd7, 0x59, 0x10, 0xfa, 0x4f, 0x42, - 0xd1, 0x28, 0xe6, 0x3f, 0x6c, 0x14, 0xb4, 0x0c, 0xa6, 0xa0, 0x81, 0x4a, 0xdd, 0xa2, 0x93, 0x7d, - 0xce, 0xdc, 0x78, 0xc3, 0xab, 0x8f, 0x9e, 0x77, 0x8d, 0xc7, 0xcf, 0xbb, 0xc6, 0xb3, 0xe7, 0x5d, - 0xe3, 0xfe, 0x6e, 0xb7, 0xf2, 0x78, 0xb7, 0x5b, 0xf9, 0x6d, 0xb7, 0x5b, 0xb9, 0x7b, 0xee, 0xe8, - 0x84, 0xd8, 0x72, 0x3a, 0x6a, 0xa8, 0x41, 0x76, 0xe9, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x52, - 0x04, 0x7c, 0xda, 0x01, 0x0b, 0x00, 0x00, + 0x5e, 0x57, 0x42, 0xf4, 0x06, 0xb4, 0x12, 0xc6, 0x63, 0x9f, 0xc4, 0xc4, 0x57, 0x8e, 0x37, 0x9d, + 0x3d, 0x01, 0xfa, 0x02, 0x56, 0x0a, 0x23, 0x65, 0x3f, 0x29, 0xef, 0x8f, 0x6c, 0x76, 0x0e, 0x70, + 0xda, 0x2e, 0x10, 0xc3, 0xe6, 0x83, 0xc7, 0x6b, 0xc6, 0xdd, 0x27, 0x6b, 0x86, 0xb3, 0xac, 0xd5, + 0xcb, 0x3b, 0x34, 0x84, 0x15, 0x32, 0x95, 0x84, 0x09, 0xca, 0x99, 0xcb, 0x23, 0x49, 0x39, 0x13, + 0xed, 0x3f, 0x17, 0xe6, 0xf8, 0xb9, 0x5c, 0xe2, 0x3f, 0xcf, 0xe1, 0xe8, 0x36, 0x74, 0x19, 0x67, + 0xae, 0x17, 0x53, 0x49, 0x3d, 0x3c, 0x71, 0x67, 0x18, 0x3c, 0x36, 0xc7, 0xe0, 0x49, 0xc6, 0xd9, + 0x15, 0xad, 0xfb, 0xc9, 0x4b, 0xb6, 0x7b, 0xbf, 0x1a, 0xd0, 0x2c, 0xda, 0x19, 0x7d, 0x0c, 0x8b, + 0x59, 0x0b, 0x91, 0x58, 0xf5, 0x42, 0x91, 0x8e, 0x53, 0x33, 0x32, 0xbc, 0xa5, 0x60, 0x6a, 0x06, + 0x1c, 0x11, 0xe5, 0xb7, 0x40, 0x7d, 0x30, 0x77, 0x08, 0xd1, 0x65, 0x3a, 0xab, 0x34, 0xae, 0x11, + 0xe2, 0x64, 0x10, 0x74, 0x39, 0x2f, 0x22, 0x73, 0x6e, 0x11, 0x9d, 0xf8, 0xe3, 0x60, 0xed, 0xe8, + 0xba, 0xea, 0xfd, 0x68, 0x00, 0xec, 0xd1, 0x78, 0xa9, 0x4f, 0x8c, 0xbf, 0xd7, 0x27, 0x17, 0xa1, + 0x15, 0x72, 0x9f, 0x1c, 0x36, 0xef, 0x6e, 0x71, 0x9f, 0xe4, 0xf3, 0x2e, 0xd4, 0x5f, 0x2f, 0xf4, + 0x87, 0xf9, 0x62, 0x7f, 0xf4, 0x9e, 0x56, 0xa1, 0x59, 0xa8, 0xa0, 0x0f, 0xa1, 0x21, 0x28, 0x0b, + 0x26, 0x44, 0x73, 0xea, 0xcd, 0xb1, 0x6f, 0x6d, 0x29, 0xe4, 0xf5, 0x8a, 0xa3, 0x75, 0xd0, 0x07, + 0x50, 0x57, 0xdb, 0x45, 0x93, 0x7b, 0x73, 0x9e, 0xf2, 0xad, 0x0c, 0x78, 0xbd, 0xe2, 0xe4, 0x1a, + 0x9d, 0x01, 0x34, 0x72, 0x73, 0xe8, 0x7d, 0xa8, 0x65, 0xbc, 0x15, 0x81, 0xa3, 0x9b, 0xa7, 0xf7, + 0xd9, 0x28, 0xf6, 0xcd, 0xfe, 0xb4, 0x66, 0xf6, 0x1c, 0xa5, 0xd0, 0xb9, 0x6b, 0x40, 0x5d, 0x59, + 0x45, 0x37, 0xa1, 0x39, 0xa2, 0x12, 0xc7, 0x31, 0x2e, 0x62, 0x6b, 0x17, 0x66, 0xf2, 0xad, 0x68, + 0x95, 0x4b, 0xb0, 0xb0, 0x75, 0x85, 0x87, 0x11, 0xf6, 0xe4, 0x90, 0xca, 0x41, 0xa6, 0xe6, 0x94, + 0x06, 0xd0, 0x25, 0x80, 0x32, 0xea, 0xd9, 0xac, 0x35, 0x0f, 0x0b, 0x7b, 0xab, 0x08, 0xbb, 0x18, + 0xd6, 0xc1, 0x14, 0x49, 0xd8, 0xfb, 0xa6, 0x0a, 0xe6, 0x35, 0x42, 0x50, 0x0a, 0x0d, 0x1c, 0x66, + 0x63, 0x4b, 0xd7, 0x6a, 0xb9, 0xe1, 0xb2, 0xe5, 0xbb, 0x8f, 0x0a, 0x65, 0xc3, 0x6b, 0x0f, 0x1e, + 0xaf, 0x55, 0x7e, 0x79, 0xb2, 0xd6, 0x0f, 0xa8, 0x1c, 0x27, 0x23, 0xcb, 0xe3, 0xa1, 0x5d, 0x2c, + 0xf6, 0xb2, 0xc2, 0x6c, 0x99, 0x46, 0x44, 0x28, 0x05, 0xf1, 0xd3, 0xf3, 0x7b, 0x67, 0x17, 0x27, + 0x24, 0xc0, 0x5e, 0xea, 0x66, 0xeb, 0x5b, 0xfc, 0xfc, 0xfc, 0xde, 0x59, 0xc3, 0xd1, 0x0f, 0xa2, + 0x93, 0xd0, 0x0a, 0xb0, 0x70, 0x27, 0x34, 0xa4, 0x52, 0xa5, 0xa7, 0xe6, 0x34, 0x03, 0x2c, 0x3e, + 0xcd, 0xce, 0xc8, 0x82, 0x7a, 0x84, 0x53, 0x12, 0xe7, 0xd3, 0x77, 0xd8, 0x7e, 0x74, 0x7f, 0xe3, + 0xb8, 0x66, 0x36, 0xf0, 0xfd, 0x98, 0x08, 0xb1, 0x25, 0x63, 0xca, 0x02, 0x27, 0x87, 0xa1, 0x4d, + 0x58, 0x08, 0x62, 0xcc, 0xa4, 0x1e, 0xc7, 0xf3, 0x34, 0x0a, 0x60, 0xef, 0x37, 0x03, 0xcc, 0x6d, + 0x1a, 0xfd, 0x9f, 0x31, 0x38, 0x07, 0x0d, 0x49, 0xa3, 0x88, 0xc4, 0xf9, 0x2c, 0x9e, 0xc3, 0x5a, + 0xe3, 0x2e, 0x9d, 0x78, 0x34, 0xab, 0xa3, 0x7b, 0xbb, 0x06, 0x2c, 0x0d, 0x92, 0x69, 0xde, 0xcf, + 0x57, 0xb1, 0xc4, 0x59, 0x44, 0x70, 0x6e, 0x41, 0x15, 0xdc, 0xdc, 0x88, 0x68, 0x20, 0xfa, 0x08, + 0x9a, 0x59, 0x45, 0xbb, 0x3e, 0xf7, 0x74, 0xc3, 0x9c, 0x7e, 0xc5, 0xec, 0xda, 0xbf, 0x81, 0x9d, + 0x05, 0xa1, 0xff, 0x28, 0x14, 0x8d, 0x62, 0xfe, 0xc3, 0x46, 0x41, 0xcb, 0x60, 0x0a, 0x1a, 0xa8, + 0xd4, 0x2d, 0x3a, 0xd9, 0xe7, 0xcc, 0xad, 0x37, 0xbc, 0xfc, 0xe0, 0x59, 0xd7, 0x78, 0xf8, 0xac, + 0x6b, 0x3c, 0x7d, 0xd6, 0x35, 0xee, 0xee, 0x76, 0x2b, 0x0f, 0x77, 0xbb, 0x95, 0xdf, 0x77, 0xbb, + 0x95, 0xdb, 0x67, 0x0e, 0x4f, 0x88, 0x2d, 0xa7, 0xa3, 0x86, 0x1a, 0x64, 0x17, 0xfe, 0x0a, 0x00, + 0x00, 0xff, 0xff, 0x72, 0x63, 0x4f, 0x0e, 0x05, 0x0b, 0x00, 0x00, } func (m *Tx) Marshal() (dAtA []byte, err error) { From 59248f5514b9397b180e1dae64a79163e3f42ca6 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Fri, 5 Jul 2024 14:04:13 +0700 Subject: [PATCH 08/39] lint --- x/auth/ante/unorderedtx/manager_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/auth/ante/unorderedtx/manager_test.go b/x/auth/ante/unorderedtx/manager_test.go index 48e22f4de59d..7c2374ba44b3 100644 --- a/x/auth/ante/unorderedtx/manager_test.go +++ b/x/auth/ante/unorderedtx/manager_test.go @@ -120,7 +120,7 @@ func TestUnorderedTxManager_Flow(t *testing.T) { var ( height uint64 = 1 - timestamp time.Time = time.Now() + timestamp time.Time = time.Now() //nolint:stylecheck // false positive i = 101 ) for time := range ticker.C { From ce2c7d2afa7441691e7aa4e76bc36116f0700450 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Fri, 5 Jul 2024 18:02:14 +0700 Subject: [PATCH 09/39] fix tests --- baseapp/abci_test.go | 14 ++++++++++++-- baseapp/abci_utils_test.go | 10 +++++----- tests/e2e/baseapp/block_gas_test.go | 2 +- x/auth/ante/basic.go | 2 +- x/auth/ante/unordered.go | 6 +++--- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 7e08aabfba05..c14f588eb554 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -1597,19 +1597,29 @@ func TestABCI_PrepareProposal_ReachedMaxBytes(t *testing.T) { }) require.NoError(t, err) + expectedTxs := 8 + var expectedTxBytes int64 + for i := 0; i < 100; i++ { tx2 := newTxCounter(t, suite.txConfig, int64(i), int64(i)) err := pool.Insert(sdk.Context{}, tx2) require.NoError(t, err) + + txBz, err := suite.txConfig.TxEncoder()(tx2) + require.NoError(t, err) + txDataSize := int(cmttypes.ComputeProtoSizeForTxs([]cmttypes.Tx{txBz})) + if i < expectedTxs { + expectedTxBytes += int64(txDataSize) + } } reqPrepareProposal := abci.PrepareProposalRequest{ - MaxTxBytes: 1500, + MaxTxBytes: expectedTxBytes, Height: 1, } resPrepareProposal, err := suite.baseApp.PrepareProposal(&reqPrepareProposal) require.NoError(t, err) - require.Equal(t, 8, len(resPrepareProposal.Txs)) + require.Equal(t, expectedTxs, len(resPrepareProposal.Txs)) } func TestABCI_PrepareProposal_BadEncoding(t *testing.T) { diff --git a/baseapp/abci_utils_test.go b/baseapp/abci_utils_test.go index 25d4c4073c89..ace1001b4717 100644 --- a/baseapp/abci_utils_test.go +++ b/baseapp/abci_utils_test.go @@ -496,10 +496,10 @@ func (s *ABCIUtilsTestSuite) TestDefaultProposalHandler_NoOpMempoolTxSelection() tx := builder.GetTx() txBz, err := txConfig.TxEncoder()(tx) s.Require().NoError(err) - s.Require().Len(txBz, 152) + s.Require().Len(txBz, 165) txDataSize := int(cmttypes.ComputeProtoSizeForTxs([]cmttypes.Tx{txBz})) - s.Require().Equal(txDataSize, 155) + s.Require().Equal(txDataSize, 168) testCases := map[string]struct { ctx sdk.Context @@ -532,15 +532,15 @@ func (s *ABCIUtilsTestSuite) TestDefaultProposalHandler_NoOpMempoolTxSelection() Txs: [][]byte{txBz, txBz, txBz, txBz, txBz}, MaxTxBytes: 465, }, - expectedTxs: 3, + expectedTxs: 2, }, "large max tx bytes len calculation": { ctx: s.ctx, req: &abci.PrepareProposalRequest{ Txs: [][]byte{txBz, txBz, txBz, txBz, txBz}, - MaxTxBytes: 456, + MaxTxBytes: 504, }, - expectedTxs: 2, + expectedTxs: 3, }, "max gas and tx bytes": { ctx: s.ctx.WithConsensusParams(cmtproto.ConsensusParams{ diff --git a/tests/e2e/baseapp/block_gas_test.go b/tests/e2e/baseapp/block_gas_test.go index 431e9463c066..5bc9349c6881 100644 --- a/tests/e2e/baseapp/block_gas_test.go +++ b/tests/e2e/baseapp/block_gas_test.go @@ -175,7 +175,7 @@ func TestBaseApp_BlockGas(t *testing.T) { require.Equal(t, []byte("ok"), okValue) } // check block gas is always consumed - baseGas := uint64(38012) // baseGas is the gas consumed before tx msg + baseGas := uint64(38142) // baseGas is the gas consumed before tx msg expGasConsumed := addUint64Saturating(tc.gasToConsume, baseGas) if expGasConsumed > uint64(simtestutil.DefaultConsensusParams.Block.MaxGas) { // capped by gasLimit diff --git a/x/auth/ante/basic.go b/x/auth/ante/basic.go index 572bda28c6a3..642230a6de3e 100644 --- a/x/auth/ante/basic.go +++ b/x/auth/ante/basic.go @@ -269,7 +269,7 @@ func (txh TxTimeoutHeightDecorator) ValidateTx(ctx context.Context, tx sdk.Tx) e } timeoutTimestamp := timeoutTx.GetTimeoutTimeStamp() - if !timeoutTimestamp.IsZero() && timeoutTimestamp.Before(headerInfo.Time) { + if !timeoutTimestamp.IsZero() && timeoutTimestamp.Unix() != 0 && timeoutTimestamp.Before(headerInfo.Time) { return errorsmod.Wrapf( sdkerrors.ErrTxTimeout, "block time: %s, timeout timestamp: %s", headerInfo.Time.String(), timeoutTimestamp.String(), ) diff --git a/x/auth/ante/unordered.go b/x/auth/ante/unordered.go index 1e495328fecd..85894048cfad 100644 --- a/x/auth/ante/unordered.go +++ b/x/auth/ante/unordered.go @@ -59,10 +59,9 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne } timeoutTimestamp := unorderedTx.GetTimeoutTimeStamp() - // TTL is defined as a specific block height at which this tx is no longer valid - if !timeoutTimestamp.IsZero() { + if !timeoutTimestamp.IsZero() && timeoutTimestamp.Unix() != 0 { if timeoutTimestamp.Before(ctx.BlockTime()) { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_height that has already passed") + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_timestamp that has already passed") } if timeoutTimestamp.After(ctx.BlockTime().Add(d.maxTimeoutDuration)) { return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) @@ -76,6 +75,7 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne return next(ctx, tx, false) } + // TTL is defined as a specific block height at which this tx is no longer valid ttl := unorderedTx.GetTimeoutHeight() if ttl == 0 && timeoutTimestamp.IsZero() { return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_height or timeout_timestamp set") From 559e0be4f12e9da6f74271fa04180714b4e1d0fc Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Fri, 5 Jul 2024 19:59:45 +0700 Subject: [PATCH 10/39] fix more test --- baseapp/abci_utils_test.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/baseapp/abci_utils_test.go b/baseapp/abci_utils_test.go index ace1001b4717..7e1c566faf94 100644 --- a/baseapp/abci_utils_test.go +++ b/baseapp/abci_utils_test.go @@ -619,15 +619,15 @@ func (s *ABCIUtilsTestSuite) TestDefaultProposalHandler_PriorityNonceMempoolTxSe testTxs[i].size = int(cmttypes.ComputeProtoSizeForTxs([]cmttypes.Tx{bz})) } - s.Require().Equal(180, testTxs[0].size) - s.Require().Equal(190, testTxs[1].size) - s.Require().Equal(181, testTxs[2].size) - s.Require().Equal(181, testTxs[3].size) - s.Require().Equal(263, testTxs[4].size) - s.Require().Equal(273, testTxs[5].size) - s.Require().Equal(264, testTxs[6].size) - s.Require().Equal(264, testTxs[7].size) - s.Require().Equal(264, testTxs[8].size) + s.Require().Equal(193, testTxs[0].size) + s.Require().Equal(203, testTxs[1].size) + s.Require().Equal(194, testTxs[2].size) + s.Require().Equal(194, testTxs[3].size) + s.Require().Equal(276, testTxs[4].size) + s.Require().Equal(286, testTxs[5].size) + s.Require().Equal(277, testTxs[6].size) + s.Require().Equal(277, testTxs[7].size) + s.Require().Equal(277, testTxs[8].size) testCases := map[string]struct { ctx sdk.Context @@ -640,7 +640,7 @@ func (s *ABCIUtilsTestSuite) TestDefaultProposalHandler_PriorityNonceMempoolTxSe ctx: s.ctx, txInputs: []testTx{testTxs[0], testTxs[1], testTxs[2], testTxs[3]}, req: &abci.PrepareProposalRequest{ - MaxTxBytes: 180 + 181, + MaxTxBytes: 193 + 194, }, expectedTxs: []int{0, 3}, }, @@ -648,7 +648,7 @@ func (s *ABCIUtilsTestSuite) TestDefaultProposalHandler_PriorityNonceMempoolTxSe ctx: s.ctx, txInputs: []testTx{testTxs[4], testTxs[5], testTxs[6], testTxs[7], testTxs[8]}, req: &abci.PrepareProposalRequest{ - MaxTxBytes: 263 + 264, + MaxTxBytes: 276 + 277, }, expectedTxs: []int{4, 8}, }, @@ -657,7 +657,7 @@ func (s *ABCIUtilsTestSuite) TestDefaultProposalHandler_PriorityNonceMempoolTxSe ctx: s.ctx, txInputs: []testTx{testTxs[9], testTxs[10], testTxs[11]}, req: &abci.PrepareProposalRequest{ - MaxTxBytes: 263 + 264, + MaxTxBytes: 276 + 277, }, expectedTxs: []int{9}, }, From a178e9ab1e8737bbd4e4b7a4e311ee1e96fb79f9 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Mon, 8 Jul 2024 20:41:44 +0700 Subject: [PATCH 11/39] add tests --- UPGRADING.md | 2 +- simapp/ante.go | 2 +- types/context.go | 7 ++++ x/auth/ante/basic_test.go | 30 +++++++++++----- x/auth/ante/unordered.go | 20 ++++++----- x/auth/ante/unordered_test.go | 57 ++++++++++++++++++++++-------- x/auth/ante/unorderedtx/manager.go | 43 +++++++++++----------- 7 files changed, 107 insertions(+), 54 deletions(-) diff --git a/UPGRADING.md b/UPGRADING.md index 64f8b56780d9..83a9b7029031 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -103,7 +103,7 @@ transactions in your application: anteDecorators := []sdk.AnteDecorator{ ante.NewSetUpContextDecorator(), // ... - ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, app.UnorderedTxManager), + ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, unorderedtx.DefaultmaxTimeoutDuration, app.UnorderedTxManager), // ... } diff --git a/simapp/ante.go b/simapp/ante.go index fb54d1baed71..0557de4582aa 100644 --- a/simapp/ante.go +++ b/simapp/ante.go @@ -39,7 +39,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), ante.NewValidateBasicDecorator(options.Environment), ante.NewTxTimeoutHeightDecorator(options.Environment), - ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, options.TxManager, options.Environment), + ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, options.TxManager, options.Environment), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), diff --git a/types/context.go b/types/context.go index 72a944847432..9cd92f352d3e 100644 --- a/types/context.go +++ b/types/context.go @@ -189,6 +189,13 @@ func (c Context) WithBlockHeight(height int64) Context { return c.WithBlockHeader(newHeader) } +// WithBlockTime returns a Context with an updated block time. +func (c Context) WithBlockTime(time time.Time) Context { + newHeader := c.BlockHeader() + newHeader.Time = time + return c.WithBlockHeader(newHeader) +} + // WithChainID returns a Context with an updated chain identifier. func (c Context) WithChainID(chainID string) Context { c.chainID = chainID diff --git a/x/auth/ante/basic_test.go b/x/auth/ante/basic_test.go index 836fd63e1fb6..b3e7683896cf 100644 --- a/x/auth/ante/basic_test.go +++ b/x/auth/ante/basic_test.go @@ -4,6 +4,7 @@ import ( "context" "strings" "testing" + "time" "github.com/stretchr/testify/require" @@ -199,15 +200,22 @@ func TestTxHeightTimeoutDecorator(t *testing.T) { gasLimit := testdata.NewTestGasLimit() testCases := []struct { - name string - timeout uint64 - height int64 - expectedErr error + name string + timeout uint64 + height int64 + timeoutTimestamp time.Time + timestamp time.Time + expectedErr error }{ - {"default value", 0, 10, nil}, - {"no timeout (greater height)", 15, 10, nil}, - {"no timeout (same height)", 10, 10, nil}, - {"timeout (smaller height)", 9, 10, sdkerrors.ErrTxTimeoutHeight}, + {"default value", 0, 10, time.Time{}, time.Time{}, nil}, + {"no timeout (greater height)", 15, 10, time.Time{}, time.Time{}, nil}, + {"no timeout (same height)", 10, 10, time.Time{}, time.Time{}, nil}, + {"timeout (smaller height)", 9, 10, time.Time{}, time.Time{}, sdkerrors.ErrTxTimeoutHeight}, + {"no timeout (timeout after timestamp)", 0, 20, time.Now().Add(time.Minute), time.Now(), nil}, + {"no timeout (current time)", 0, 20, time.Now(), time.Now(), nil}, + {"timeout before timestamp", 0, 20, time.Now(), time.Now().Add(time.Minute), sdkerrors.ErrTxTimeout}, + {"tx contain both timeouts, timeout (timeout before timestamp)", 15, 10, time.Now(), time.Now().Add(time.Minute), sdkerrors.ErrTxTimeout}, + {"tx contain both timeout, no timeout", 15, 10, time.Now().Add(time.Minute), time.Now(), nil}, } for _, tc := range testCases { @@ -222,12 +230,14 @@ func TestTxHeightTimeoutDecorator(t *testing.T) { suite.txBuilder.SetGasLimit(gasLimit) suite.txBuilder.SetMemo(strings.Repeat("01234567890", 10)) suite.txBuilder.SetTimeoutHeight(tc.timeout) + suite.txBuilder.SetTimeoutTimestamp(tc.timeoutTimestamp) privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} tx, err := suite.CreateTestTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT) require.NoError(t, err) mockHeaderService.WithBlockHeight(tc.height) + mockHeaderService.WithBlockTime(tc.timestamp) _, err = antehandler(suite.ctx, tx, true) require.ErrorIs(t, err, tc.expectedErr) }) @@ -247,3 +257,7 @@ func (m *mockHeaderService) HeaderInfo(_ context.Context) header.Info { func (m *mockHeaderService) WithBlockHeight(height int64) { m.exp.Height = height } + +func (m *mockHeaderService) WithBlockTime(blocktime time.Time) { + m.exp.Time = blocktime +} diff --git a/x/auth/ante/unordered.go b/x/auth/ante/unordered.go index 85894048cfad..31937d3c8c6b 100644 --- a/x/auth/ante/unordered.go +++ b/x/auth/ante/unordered.go @@ -2,6 +2,7 @@ package ante import ( "crypto/sha256" + "fmt" "time" "cosmossdk.io/core/appmodule/v2" @@ -35,11 +36,12 @@ type UnorderedTxDecorator struct { env appmodule.Environment } -func NewUnorderedTxDecorator(maxTTL uint64, m *unorderedtx.Manager, env appmodule.Environment) *UnorderedTxDecorator { +func NewUnorderedTxDecorator(maxTTL uint64, maxDuration time.Duration, m *unorderedtx.Manager, env appmodule.Environment) *UnorderedTxDecorator { return &UnorderedTxDecorator{ - maxUnOrderedTTL: maxTTL, - txManager: m, - env: env, + maxUnOrderedTTL: maxTTL, + maxTimeoutDuration: maxDuration, + txManager: m, + env: env, } } @@ -58,12 +60,14 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "tx %X is duplicated") } + headerInfo := d.env.HeaderService.HeaderInfo(ctx) timeoutTimestamp := unorderedTx.GetTimeoutTimeStamp() if !timeoutTimestamp.IsZero() && timeoutTimestamp.Unix() != 0 { - if timeoutTimestamp.Before(ctx.BlockTime()) { + if timeoutTimestamp.Before(headerInfo.Time) { return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_timestamp that has already passed") } - if timeoutTimestamp.After(ctx.BlockTime().Add(d.maxTimeoutDuration)) { + if timeoutTimestamp.After(headerInfo.Time.Add(d.maxTimeoutDuration)) { + fmt.Println(timeoutTimestamp.String(), headerInfo.Time.String()) return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) } @@ -80,10 +84,10 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne if ttl == 0 && timeoutTimestamp.IsZero() { return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_height or timeout_timestamp set") } - if ttl < uint64(ctx.BlockHeight()) { + if ttl < uint64(headerInfo.Height) { return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_height that has already passed") } - if ttl > uint64(ctx.BlockHeight())+d.maxUnOrderedTTL { + if ttl > uint64(headerInfo.Height)+d.maxUnOrderedTTL { return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) } diff --git a/x/auth/ante/unordered_test.go b/x/auth/ante/unordered_test.go index c64a267f4afa..c0b757c83ffa 100644 --- a/x/auth/ante/unordered_test.go +++ b/x/auth/ante/unordered_test.go @@ -3,9 +3,11 @@ package ante_test import ( "crypto/sha256" "testing" + "time" "github.com/stretchr/testify/require" + "cosmossdk.io/core/header" "cosmossdk.io/x/auth/ante" "cosmossdk.io/x/auth/ante/unorderedtx" @@ -25,9 +27,9 @@ func TestUnorderedTxDecorator_OrderedTx(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, false, 0) + tx, txBz := genUnorderedTx(t, false, 0, time.Time{}) ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100) _, err := chain(ctx, tx, false) @@ -44,9 +46,9 @@ func TestUnorderedTxDecorator_UnorderedTx_NoTTL(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, true, 0) + tx, txBz := genUnorderedTx(t, true, 0, time.Time{}) ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100) _, err := chain(ctx, tx, false) @@ -63,13 +65,19 @@ func TestUnorderedTxDecorator_UnorderedTx_InvalidTTL(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, true, 100+unorderedtx.DefaultMaxUnOrderedTTL+1) + tx, txBz := genUnorderedTx(t, true, 100+unorderedtx.DefaultMaxUnOrderedHeight+1, time.Time{}) ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100) _, err := chain(ctx, tx, false) require.Error(t, err) + + tx, txBz = genUnorderedTx(t, true, 0, time.Now().Add(unorderedtx.DefaultmaxTimeoutDuration+time.Second)) + ctx = sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}) + _, err = chain(ctx, tx, false) + require.Error(t, err) + } func TestUnorderedTxDecorator_UnorderedTx_AlreadyExists(t *testing.T) { @@ -82,16 +90,25 @@ func TestUnorderedTxDecorator_UnorderedTx_AlreadyExists(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, true, 150) - ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100) + tx, txBz := genUnorderedTx(t, true, 150, time.Time{}) + ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithHeaderInfo(header.Info{Time: time.Now()}) txHash := sha256.Sum256(txBz) txm.Add(txHash, 150) _, err := chain(ctx, tx, false) require.Error(t, err) + + tx, txBz = genUnorderedTx(t, true, 150, time.Now().Add(time.Minute)) + ctx = sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}) + + txHash = sha256.Sum256(txBz) + txm.AddTimestamp(txHash, time.Now().Add(time.Minute)) + + _, err = chain(ctx, tx, false) + require.Error(t, err) } func TestUnorderedTxDecorator_UnorderedTx_ValidCheckTx(t *testing.T) { @@ -104,9 +121,9 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidCheckTx(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, true, 150) + tx, txBz := genUnorderedTx(t, true, 150, time.Now().Add(time.Minute)) ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithExecMode(sdk.ExecModeCheck) _, err := chain(ctx, tx, false) @@ -123,9 +140,9 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidDeliverTx(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, true, 150) + tx, txBz := genUnorderedTx(t, true, 150, time.Time{}) ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithExecMode(sdk.ExecModeFinalize) _, err := chain(ctx, tx, false) @@ -133,9 +150,18 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidDeliverTx(t *testing.T) { txHash := sha256.Sum256(txBz) require.True(t, txm.Contains(txHash)) + + tx, txBz = genUnorderedTx(t, true, 0, time.Now().Add(time.Minute)) + ctx = sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeFinalize) + + _, err = chain(ctx, tx, false) + require.NoError(t, err) + + txHash = sha256.Sum256(txBz) + require.True(t, txm.Contains(txHash)) } -func genUnorderedTx(t *testing.T, unordered bool, ttl uint64) (sdk.Tx, []byte) { +func genUnorderedTx(t *testing.T, unordered bool, height uint64, timestamp time.Time) (sdk.Tx, []byte) { t.Helper() s := SetupTestSuite(t, true) @@ -153,7 +179,8 @@ func genUnorderedTx(t *testing.T, unordered bool, ttl uint64) (sdk.Tx, []byte) { s.txBuilder.SetFeeAmount(feeAmount) s.txBuilder.SetGasLimit(gasLimit) s.txBuilder.SetUnordered(unordered) - s.txBuilder.SetTimeoutHeight(ttl) + s.txBuilder.SetTimeoutHeight(height) + s.txBuilder.SetTimeoutTimestamp(timestamp) privKeys, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} tx, err := s.CreateTestTx(s.ctx, privKeys, accNums, accSeqs, s.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT) diff --git a/x/auth/ante/unorderedtx/manager.go b/x/auth/ante/unorderedtx/manager.go index fe6e679f762d..d1b9c1e38271 100644 --- a/x/auth/ante/unorderedtx/manager.go +++ b/x/auth/ante/unorderedtx/manager.go @@ -18,9 +18,9 @@ import ( ) const ( - // DefaultMaxUnOrderedTTL defines the default maximum TTL an un-ordered transaction + // DefaultMaxUnOrderedHeight defines the default maximum height an un-ordered transaction // can set. - DefaultMaxUnOrderedTTL = 1024 + DefaultMaxUnOrderedHeight = 1024 // DefaultmaxTimeoutDuration defines the default maximum duration an un-ordered transaction // can set. // TODO: need to decide a default value @@ -62,10 +62,10 @@ type Manager struct { // expired. txHashesBlockHeight map[TxHash]uint64 - // txHashesTimestamp defines a map from tx hash -> TTL value defined as block time, which is used for duplicate + // txHashesBlockTime defines a map from tx hash -> TTL value defined as block time, which is used for duplicate // checking and replay protection, as well as purging the map when the TTL is // expired. - txHashesTimestamp map[TxHash]time.Time + txHashesBlockTime map[TxHash]time.Time } func NewManager(dataDir string) *Manager { @@ -79,7 +79,7 @@ func NewManager(dataDir string) *Manager { blockCh: make(chan blockInfo, 16), doneCh: make(chan struct{}), txHashesBlockHeight: make(map[TxHash]uint64), - txHashesTimestamp: make(map[TxHash]time.Time), + txHashesBlockTime: make(map[TxHash]time.Time), } return m @@ -111,7 +111,7 @@ func (m *Manager) Contains(hash TxHash) bool { if ok { return ok } - _, ok = m.txHashesTimestamp[hash] + _, ok = m.txHashesBlockTime[hash] return ok } @@ -119,21 +119,21 @@ func (m *Manager) Size() int { m.mu.RLock() defer m.mu.RUnlock() - return len(m.txHashesBlockHeight) + len(m.txHashesTimestamp) + return len(m.txHashesBlockHeight) + len(m.txHashesBlockTime) } -func (m *Manager) Add(txHash TxHash, ttl uint64) { +func (m *Manager) Add(txHash TxHash, height uint64) { m.mu.Lock() defer m.mu.Unlock() - m.txHashesBlockHeight[txHash] = ttl + m.txHashesBlockHeight[txHash] = height } func (m *Manager) AddTimestamp(txHash TxHash, timestamp time.Time) { m.mu.Lock() defer m.mu.Unlock() - m.txHashesTimestamp[txHash] = timestamp + m.txHashesBlockTime[txHash] = timestamp } // OnInit must be called when a node starts up. Typically, this should be called @@ -203,24 +203,24 @@ func (m *Manager) exportSnapshot(height uint64, snapshotWriter func([]byte) erro sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i][:], keys[j][:]) < 0 }) for _, txHash := range keys { - ttl := m.txHashesBlockHeight[txHash] - if height > ttl { + blockHeight := m.txHashesBlockHeight[txHash] + if height > blockHeight { // skip expired txs that have yet to be purged continue } - chunk := unorderedTxToBytes(txHash, ttl, true) + chunk := unorderedTxToBytes(txHash, blockHeight, true) if _, err := w.Write(chunk); err != nil { return fmt.Errorf("failed to write unordered tx to buffer: %w", err) } } - keys = maps.Keys(m.txHashesTimestamp) + keys = maps.Keys(m.txHashesBlockTime) sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i][:], keys[j][:]) < 0 }) for _, txHash := range keys { - timestamp := m.txHashesTimestamp[txHash] + timestamp := m.txHashesBlockTime[txHash] // right now we dont have access block time at this flow, so we would just include the expired txs // and let it be purge during purge loop @@ -248,15 +248,15 @@ func (m *Manager) flushToFile() error { defer f.Close() w := bufio.NewWriter(f) - for txHash, ttl := range m.txHashesBlockHeight { - chunk := unorderedTxToBytes(txHash, ttl, true) + for txHash, height := range m.txHashesBlockHeight { + chunk := unorderedTxToBytes(txHash, height, true) if _, err = w.Write(chunk); err != nil { return fmt.Errorf("failed to write unordered tx to buffer: %w", err) } } - for txHash, timestamp := range m.txHashesTimestamp { + for txHash, timestamp := range m.txHashesBlockTime { chunk := unorderedTxToBytes(txHash, uint64(timestamp.Unix()), false) if _, err = w.Write(chunk); err != nil { @@ -277,13 +277,13 @@ func (m *Manager) expiredTxs(blockHeight uint64, blockTime time.Time) []TxHash { defer m.mu.RUnlock() var result []TxHash - for txHash, ttl := range m.txHashesBlockHeight { - if blockHeight > ttl { + for txHash, height := range m.txHashesBlockHeight { + if blockHeight > height { result = append(result, txHash) } } - for txHash, timestamp := range m.txHashesTimestamp { + for txHash, timestamp := range m.txHashesBlockTime { if blockTime.After(timestamp) { result = append(result, txHash) } @@ -298,6 +298,7 @@ func (m *Manager) purge(txHashesBlockHeight []TxHash) { for _, txHash := range txHashesBlockHeight { delete(m.txHashesBlockHeight, txHash) + delete(m.txHashesBlockTime, txHash) } } From 02d63dcf749ba7b66d91ab591e5250aaba1d5367 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Mon, 8 Jul 2024 20:49:05 +0700 Subject: [PATCH 12/39] remove unnecessary code --- types/context.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/types/context.go b/types/context.go index 9cd92f352d3e..72a944847432 100644 --- a/types/context.go +++ b/types/context.go @@ -189,13 +189,6 @@ func (c Context) WithBlockHeight(height int64) Context { return c.WithBlockHeader(newHeader) } -// WithBlockTime returns a Context with an updated block time. -func (c Context) WithBlockTime(time time.Time) Context { - newHeader := c.BlockHeader() - newHeader.Time = time - return c.WithBlockHeader(newHeader) -} - // WithChainID returns a Context with an updated chain identifier. func (c Context) WithChainID(chainID string) Context { c.chainID = chainID From efcb0b95323f4371705ae1128c74833ea46ad505 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Mon, 8 Jul 2024 21:06:57 +0700 Subject: [PATCH 13/39] fix tests --- x/auth/ante/unordered.go | 2 -- x/auth/ante/unordered_test.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/x/auth/ante/unordered.go b/x/auth/ante/unordered.go index 31937d3c8c6b..7316ae3f1ab0 100644 --- a/x/auth/ante/unordered.go +++ b/x/auth/ante/unordered.go @@ -2,7 +2,6 @@ package ante import ( "crypto/sha256" - "fmt" "time" "cosmossdk.io/core/appmodule/v2" @@ -67,7 +66,6 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_timestamp that has already passed") } if timeoutTimestamp.After(headerInfo.Time.Add(d.maxTimeoutDuration)) { - fmt.Println(timeoutTimestamp.String(), headerInfo.Time.String()) return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) } diff --git a/x/auth/ante/unordered_test.go b/x/auth/ante/unordered_test.go index c0b757c83ffa..928dd81da093 100644 --- a/x/auth/ante/unordered_test.go +++ b/x/auth/ante/unordered_test.go @@ -124,7 +124,7 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidCheckTx(t *testing.T) { chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) tx, txBz := genUnorderedTx(t, true, 150, time.Now().Add(time.Minute)) - ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithExecMode(sdk.ExecModeCheck) + ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeCheck) _, err := chain(ctx, tx, false) require.NoError(t, err) From ca0b587fcbd92d7c274442e71ea6934e603c8b5f Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Mon, 8 Jul 2024 21:28:35 +0700 Subject: [PATCH 14/39] lint --- x/auth/ante/basic_test.go | 12 +++++++----- x/auth/ante/unordered_test.go | 1 - 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/x/auth/ante/basic_test.go b/x/auth/ante/basic_test.go index b3e7683896cf..599fc653913c 100644 --- a/x/auth/ante/basic_test.go +++ b/x/auth/ante/basic_test.go @@ -194,6 +194,8 @@ func TestTxHeightTimeoutDecorator(t *testing.T) { // keys and addresses priv1, _, addr1 := testdata.KeyTestPubAddr() + currentTime := time.Now() + // msg and signatures msg := testdata.NewTestMsg(addr1) feeAmount := testdata.NewTestFeeAmount() @@ -211,11 +213,11 @@ func TestTxHeightTimeoutDecorator(t *testing.T) { {"no timeout (greater height)", 15, 10, time.Time{}, time.Time{}, nil}, {"no timeout (same height)", 10, 10, time.Time{}, time.Time{}, nil}, {"timeout (smaller height)", 9, 10, time.Time{}, time.Time{}, sdkerrors.ErrTxTimeoutHeight}, - {"no timeout (timeout after timestamp)", 0, 20, time.Now().Add(time.Minute), time.Now(), nil}, - {"no timeout (current time)", 0, 20, time.Now(), time.Now(), nil}, - {"timeout before timestamp", 0, 20, time.Now(), time.Now().Add(time.Minute), sdkerrors.ErrTxTimeout}, - {"tx contain both timeouts, timeout (timeout before timestamp)", 15, 10, time.Now(), time.Now().Add(time.Minute), sdkerrors.ErrTxTimeout}, - {"tx contain both timeout, no timeout", 15, 10, time.Now().Add(time.Minute), time.Now(), nil}, + {"no timeout (timeout after timestamp)", 0, 20, currentTime.Add(time.Minute), currentTime, nil}, + {"no timeout (current time)", 0, 20, currentTime, currentTime, nil}, + {"timeout before timestamp", 0, 20, currentTime, currentTime.Add(time.Minute), sdkerrors.ErrTxTimeout}, + {"tx contain both timeouts, timeout (timeout before timestamp)", 15, 10, currentTime, currentTime.Add(time.Minute), sdkerrors.ErrTxTimeout}, + {"tx contain both timeout, no timeout", 15, 10, currentTime.Add(time.Minute), currentTime, nil}, } for _, tc := range testCases { diff --git a/x/auth/ante/unordered_test.go b/x/auth/ante/unordered_test.go index 928dd81da093..ec2502f6190b 100644 --- a/x/auth/ante/unordered_test.go +++ b/x/auth/ante/unordered_test.go @@ -77,7 +77,6 @@ func TestUnorderedTxDecorator_UnorderedTx_InvalidTTL(t *testing.T) { ctx = sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}) _, err = chain(ctx, tx, false) require.Error(t, err) - } func TestUnorderedTxDecorator_UnorderedTx_AlreadyExists(t *testing.T) { From 4810fd19dca7e03a9de954e9a9b48623af68d84c Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 9 Jul 2024 11:59:41 +0700 Subject: [PATCH 15/39] add more test --- x/auth/ante/unorderedtx/manager_test.go | 29 ++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/x/auth/ante/unorderedtx/manager_test.go b/x/auth/ante/unorderedtx/manager_test.go index 7c2374ba44b3..c6515e73a31b 100644 --- a/x/auth/ante/unorderedtx/manager_test.go +++ b/x/auth/ante/unorderedtx/manager_test.go @@ -112,6 +112,20 @@ func TestUnorderedTxManager_Flow(t *testing.T) { } } + currentTime := time.Now() + + // Seed the manager with a txs, some of which should eventually be purged and + // the others will remain. Txs with TTL less than or equal to 50 should be purged. + for i := 1; i <= 100; i++ { + txHash := [32]byte{byte(i + 100)} + + if i <= 50 { + txm.AddTimestamp(txHash, currentTime.Add(time.Millisecond*500*time.Duration(i))) + } else { + txm.AddTimestamp(txHash, currentTime.Add(time.Hour)) + } + } + // start a goroutine that mimics new blocks being made every 500ms doneBlockCh := make(chan bool) go func() { @@ -119,20 +133,15 @@ func TestUnorderedTxManager_Flow(t *testing.T) { defer ticker.Stop() var ( - height uint64 = 1 - timestamp time.Time = time.Now() //nolint:stylecheck // false positive - i = 101 + height uint64 = 1 ) - for time := range ticker.C { - txm.OnNewBlock(height, timestamp) + for t := range ticker.C { + txm.OnNewBlock(height, t) height++ - timestamp = time - if height > 51 { + if height > 51 && t.After(currentTime.Add(time.Millisecond*500*time.Duration(50))) { doneBlockCh <- true return - } else { - txm.Add([32]byte{byte(i)}, 50) } } }() @@ -142,7 +151,7 @@ func TestUnorderedTxManager_Flow(t *testing.T) { require.Eventually( t, func() bool { - return txm.Size() == 50 + return txm.Size() == 100 }, 2*time.Minute, 5*time.Second, From e17ddc8f2ca4ba781e563bafb8e3cd688af20b08 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 9 Jul 2024 12:23:12 +0700 Subject: [PATCH 16/39] lint --- x/auth/ante/unorderedtx/manager_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x/auth/ante/unorderedtx/manager_test.go b/x/auth/ante/unorderedtx/manager_test.go index c6515e73a31b..a6b107bf5f6a 100644 --- a/x/auth/ante/unorderedtx/manager_test.go +++ b/x/auth/ante/unorderedtx/manager_test.go @@ -132,9 +132,7 @@ func TestUnorderedTxManager_Flow(t *testing.T) { ticker := time.NewTicker(time.Millisecond * 500) defer ticker.Stop() - var ( - height uint64 = 1 - ) + var height uint64 = 1 for t := range ticker.C { txm.OnNewBlock(height, t) height++ From 2f69f6f9a7586c224fcbd01f2cb32dca6b962af0 Mon Sep 17 00:00:00 2001 From: son trinh Date: Tue, 9 Jul 2024 17:36:32 +0700 Subject: [PATCH 17/39] remove testing print Co-authored-by: Marko --- client/tx/factory.go | 1 - 1 file changed, 1 deletion(-) diff --git a/client/tx/factory.go b/client/tx/factory.go index d2e0146de7bc..0972fe5f5d77 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -413,7 +413,6 @@ func (f Factory) PrintUnsignedTx(clientCtx client.Context, msgs ...sdk.Msg) erro return err } - fmt.Println(unsignedTx) encoder := f.txConfig.TxJSONEncoder() if encoder == nil { From f97802705c7cfed98ceef3160242a18cf3e64117 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 9 Jul 2024 19:35:45 +0700 Subject: [PATCH 18/39] unordered tx use time based timeout --- types/tx_msg.go | 1 - x/auth/ante/unordered.go | 48 ++----- x/auth/ante/unordered_test.go | 65 +++------ x/auth/ante/unorderedtx/manager.go | 151 +++++--------------- x/auth/ante/unorderedtx/manager_test.go | 36 ++--- x/auth/ante/unorderedtx/snapshotter.go | 17 +-- x/auth/ante/unorderedtx/snapshotter_test.go | 13 +- 7 files changed, 96 insertions(+), 235 deletions(-) diff --git a/types/tx_msg.go b/types/tx_msg.go index 37ff1264d9a0..c4fabe98d40f 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -99,7 +99,6 @@ type ( // TxWithUnordered extends the Tx interface by allowing a transaction to set // the unordered field, which implicitly relies on TxWithTimeoutHeight. TxWithUnordered interface { - TxWithTimeoutHeight TxWithTimeoutTimeStamp GetUnordered() bool diff --git a/x/auth/ante/unordered.go b/x/auth/ante/unordered.go index 7316ae3f1ab0..fb30dc7e1d43 100644 --- a/x/auth/ante/unordered.go +++ b/x/auth/ante/unordered.go @@ -29,15 +29,13 @@ var _ sdk.AnteDecorator = (*UnorderedTxDecorator)(nil) // chain to ensure that during DeliverTx, the transaction is added to the UnorderedTxManager. type UnorderedTxDecorator struct { // maxUnOrderedTTL defines the maximum TTL a transaction can define. - maxUnOrderedTTL uint64 maxTimeoutDuration time.Duration txManager *unorderedtx.Manager env appmodule.Environment } -func NewUnorderedTxDecorator(maxTTL uint64, maxDuration time.Duration, m *unorderedtx.Manager, env appmodule.Environment) *UnorderedTxDecorator { +func NewUnorderedTxDecorator(maxDuration time.Duration, m *unorderedtx.Manager, env appmodule.Environment) *UnorderedTxDecorator { return &UnorderedTxDecorator{ - maxUnOrderedTTL: maxTTL, maxTimeoutDuration: maxDuration, txManager: m, env: env, @@ -52,46 +50,28 @@ func (d *UnorderedTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, ne return next(ctx, tx, false) } - txHash := sha256.Sum256(ctx.TxBytes()) - - // check for duplicates - if d.txManager.Contains(txHash) { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "tx %X is duplicated") - } - headerInfo := d.env.HeaderService.HeaderInfo(ctx) timeoutTimestamp := unorderedTx.GetTimeoutTimeStamp() - if !timeoutTimestamp.IsZero() && timeoutTimestamp.Unix() != 0 { - if timeoutTimestamp.Before(headerInfo.Time) { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_timestamp that has already passed") - } - if timeoutTimestamp.After(headerInfo.Time.Add(d.maxTimeoutDuration)) { - return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) - } - - if d.env.TransactionService.ExecMode(ctx) == transaction.ExecModeFinalize { - // a new tx included in the block, add the hash to the unordered tx manager - d.txManager.AddTimestamp(txHash, timeoutTimestamp) - } - - return next(ctx, tx, false) + if timeoutTimestamp.IsZero() || timeoutTimestamp.Unix() == 0 { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_timestamp set") } - - // TTL is defined as a specific block height at which this tx is no longer valid - ttl := unorderedTx.GetTimeoutHeight() - if ttl == 0 && timeoutTimestamp.IsZero() { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_height or timeout_timestamp set") + if timeoutTimestamp.Before(headerInfo.Time) { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_timestamp that has already passed") } - if ttl < uint64(headerInfo.Height) { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_height that has already passed") + if timeoutTimestamp.After(headerInfo.Time.Add(d.maxTimeoutDuration)) { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %s", d.maxTimeoutDuration.String()) } - if ttl > uint64(headerInfo.Height)+d.maxUnOrderedTTL { - return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) + + txHash := sha256.Sum256(ctx.TxBytes()) + + // check for duplicates + if d.txManager.Contains(txHash) { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "tx %X is duplicated") } if d.env.TransactionService.ExecMode(ctx) == transaction.ExecModeFinalize { // a new tx included in the block, add the hash to the unordered tx manager - d.txManager.Add(txHash, ttl) + d.txManager.Add(txHash, timeoutTimestamp) } return next(ctx, tx, false) diff --git a/x/auth/ante/unordered_test.go b/x/auth/ante/unordered_test.go index ec2502f6190b..e5ad979dfb95 100644 --- a/x/auth/ante/unordered_test.go +++ b/x/auth/ante/unordered_test.go @@ -27,10 +27,10 @@ func TestUnorderedTxDecorator_OrderedTx(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, false, 0, time.Time{}) - ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100) + tx, txBz := genUnorderedTx(t, false, time.Time{}) + ctx := sdk.Context{}.WithTxBytes(txBz) _, err := chain(ctx, tx, false) require.NoError(t, err) @@ -46,10 +46,10 @@ func TestUnorderedTxDecorator_UnorderedTx_NoTTL(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, true, 0, time.Time{}) - ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100) + tx, txBz := genUnorderedTx(t, true, time.Time{}) + ctx := sdk.Context{}.WithTxBytes(txBz) _, err := chain(ctx, tx, false) require.Error(t, err) @@ -65,18 +65,12 @@ func TestUnorderedTxDecorator_UnorderedTx_InvalidTTL(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - - tx, txBz := genUnorderedTx(t, true, 100+unorderedtx.DefaultMaxUnOrderedHeight+1, time.Time{}) - ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + tx, txBz := genUnorderedTx(t, true, time.Now().Add(unorderedtx.DefaultmaxTimeoutDuration+time.Second)) + ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}) _, err := chain(ctx, tx, false) require.Error(t, err) - - tx, txBz = genUnorderedTx(t, true, 0, time.Now().Add(unorderedtx.DefaultmaxTimeoutDuration+time.Second)) - ctx = sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}) - _, err = chain(ctx, tx, false) - require.Error(t, err) } func TestUnorderedTxDecorator_UnorderedTx_AlreadyExists(t *testing.T) { @@ -89,25 +83,16 @@ func TestUnorderedTxDecorator_UnorderedTx_AlreadyExists(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, true, 150, time.Time{}) - ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithHeaderInfo(header.Info{Time: time.Now()}) + tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute)) + ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}) txHash := sha256.Sum256(txBz) - txm.Add(txHash, 150) + txm.Add(txHash, time.Now().Add(time.Minute)) _, err := chain(ctx, tx, false) require.Error(t, err) - - tx, txBz = genUnorderedTx(t, true, 150, time.Now().Add(time.Minute)) - ctx = sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}) - - txHash = sha256.Sum256(txBz) - txm.AddTimestamp(txHash, time.Now().Add(time.Minute)) - - _, err = chain(ctx, tx, false) - require.Error(t, err) } func TestUnorderedTxDecorator_UnorderedTx_ValidCheckTx(t *testing.T) { @@ -120,10 +105,10 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidCheckTx(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, true, 150, time.Now().Add(time.Minute)) - ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeCheck) + tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute)) + ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeCheck) _, err := chain(ctx, tx, false) require.NoError(t, err) @@ -139,28 +124,19 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidDeliverTx(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, true, 150, time.Time{}) - ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockHeight(100).WithExecMode(sdk.ExecModeFinalize) + tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute)) + ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeFinalize) _, err := chain(ctx, tx, false) require.NoError(t, err) txHash := sha256.Sum256(txBz) require.True(t, txm.Contains(txHash)) - - tx, txBz = genUnorderedTx(t, true, 0, time.Now().Add(time.Minute)) - ctx = sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeFinalize) - - _, err = chain(ctx, tx, false) - require.NoError(t, err) - - txHash = sha256.Sum256(txBz) - require.True(t, txm.Contains(txHash)) } -func genUnorderedTx(t *testing.T, unordered bool, height uint64, timestamp time.Time) (sdk.Tx, []byte) { +func genUnorderedTx(t *testing.T, unordered bool, timestamp time.Time) (sdk.Tx, []byte) { t.Helper() s := SetupTestSuite(t, true) @@ -178,7 +154,6 @@ func genUnorderedTx(t *testing.T, unordered bool, height uint64, timestamp time. s.txBuilder.SetFeeAmount(feeAmount) s.txBuilder.SetGasLimit(gasLimit) s.txBuilder.SetUnordered(unordered) - s.txBuilder.SetTimeoutHeight(height) s.txBuilder.SetTimeoutTimestamp(timestamp) privKeys, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} diff --git a/x/auth/ante/unorderedtx/manager.go b/x/auth/ante/unorderedtx/manager.go index d1b9c1e38271..4adcd21dfe89 100644 --- a/x/auth/ante/unorderedtx/manager.go +++ b/x/auth/ante/unorderedtx/manager.go @@ -33,16 +33,11 @@ const ( // TxHash defines a transaction hash type alias, which is a fixed array of 32 bytes. type TxHash [32]byte -type blockInfo struct { - blockHeight uint64 - blockTime time.Time -} - // Manager contains the tx hash dictionary for duplicates checking, and expire // them when block production progresses. type Manager struct { // blockCh defines a channel to receive newly committed block heights - blockCh chan blockInfo + blockCh chan time.Time // doneCh allows us to ensure the purgeLoop has gracefully terminated prior to closing doneCh chan struct{} @@ -57,15 +52,11 @@ type Manager struct { dataDir string mu sync.RWMutex - // txHashesBlockHeight defines a map from tx hash -> TTL value defined as block height, which is used for duplicate - // checking and replay protection, as well as purging the map when the TTL is - // expired. - txHashesBlockHeight map[TxHash]uint64 - // txHashesBlockTime defines a map from tx hash -> TTL value defined as block time, which is used for duplicate + // txHashes defines a map from tx hash -> TTL value defined as block time, which is used for duplicate // checking and replay protection, as well as purging the map when the TTL is // expired. - txHashesBlockTime map[TxHash]time.Time + txHashes map[TxHash]time.Time } func NewManager(dataDir string) *Manager { @@ -75,11 +66,10 @@ func NewManager(dataDir string) *Manager { } m := &Manager{ - dataDir: dataDir, - blockCh: make(chan blockInfo, 16), - doneCh: make(chan struct{}), - txHashesBlockHeight: make(map[TxHash]uint64), - txHashesBlockTime: make(map[TxHash]time.Time), + dataDir: dataDir, + blockCh: make(chan time.Time, 16), + doneCh: make(chan struct{}), + txHashes: make(map[TxHash]time.Time), } return m @@ -106,12 +96,7 @@ func (m *Manager) Close() error { func (m *Manager) Contains(hash TxHash) bool { m.mu.RLock() defer m.mu.RUnlock() - - _, ok := m.txHashesBlockHeight[hash] - if ok { - return ok - } - _, ok = m.txHashesBlockTime[hash] + _, ok := m.txHashes[hash] return ok } @@ -119,21 +104,14 @@ func (m *Manager) Size() int { m.mu.RLock() defer m.mu.RUnlock() - return len(m.txHashesBlockHeight) + len(m.txHashesBlockTime) -} - -func (m *Manager) Add(txHash TxHash, height uint64) { - m.mu.Lock() - defer m.mu.Unlock() - - m.txHashesBlockHeight[txHash] = height + return len(m.txHashes) } -func (m *Manager) AddTimestamp(txHash TxHash, timestamp time.Time) { +func (m *Manager) Add(txHash TxHash, timestamp time.Time) { m.mu.Lock() defer m.mu.Unlock() - m.txHashesBlockTime[txHash] = timestamp + m.txHashes[txHash] = timestamp } // OnInit must be called when a node starts up. Typically, this should be called @@ -164,23 +142,15 @@ func (m *Manager) OnInit() error { return fmt.Errorf("failed to read unconfirmed txs file: %w", err) } } - if n != 32+8+8 { + if n != 32+8 { return fmt.Errorf("read unexpected number of bytes from unconfirmed txs file: %d", n) } var txHash TxHash copy(txHash[:], buf[:txHashSize]) - blockHeight := binary.BigEndian.Uint64(buf[txHashSize : txHashSize+heightSize]) - timeStamp := binary.BigEndian.Uint64(buf[txHashSize+heightSize:]) - - // if not zero value - if timeStamp != 0 { - m.AddTimestamp(txHash, time.Unix(int64(timeStamp), 0)) - continue - } - - m.Add(txHash, blockHeight) + timeStamp := binary.BigEndian.Uint64(buf[txHashSize:]) + m.Add(txHash, time.Unix(int64(timeStamp), 0)) } return nil @@ -188,43 +158,27 @@ func (m *Manager) OnInit() error { // OnNewBlock sends the latest block number to the background purge loop, which // should be called in ABCI Commit event. -func (m *Manager) OnNewBlock(blockHeight uint64, blockTime time.Time) { - m.blockCh <- blockInfo{ - blockHeight: blockHeight, - blockTime: blockTime, - } +func (m *Manager) OnNewBlock(blockTime time.Time) { + m.blockCh <- blockTime } func (m *Manager) exportSnapshot(height uint64, snapshotWriter func([]byte) error) error { var buf bytes.Buffer w := bufio.NewWriter(&buf) - keys := maps.Keys(m.txHashesBlockHeight) + keys := maps.Keys(m.txHashes) sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i][:], keys[j][:]) < 0 }) for _, txHash := range keys { - blockHeight := m.txHashesBlockHeight[txHash] - if height > blockHeight { + timeoutTime := m.txHashes[txHash] + timestamp := time.Unix(int64(height), 0) + if timestamp.After(timeoutTime) { // skip expired txs that have yet to be purged continue } - - chunk := unorderedTxToBytes(txHash, blockHeight, true) - - if _, err := w.Write(chunk); err != nil { - return fmt.Errorf("failed to write unordered tx to buffer: %w", err) - } - } - - keys = maps.Keys(m.txHashesBlockTime) - sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i][:], keys[j][:]) < 0 }) - - for _, txHash := range keys { - timestamp := m.txHashesBlockTime[txHash] - // right now we dont have access block time at this flow, so we would just include the expired txs // and let it be purge during purge loop - chunk := unorderedTxToBytes(txHash, uint64(timestamp.Unix()), false) + chunk := unorderedTxToBytes(txHash, uint64(timeoutTime.Unix())) if _, err := w.Write(chunk); err != nil { return fmt.Errorf("failed to write unordered tx to buffer: %w", err) @@ -248,16 +202,8 @@ func (m *Manager) flushToFile() error { defer f.Close() w := bufio.NewWriter(f) - for txHash, height := range m.txHashesBlockHeight { - chunk := unorderedTxToBytes(txHash, height, true) - - if _, err = w.Write(chunk); err != nil { - return fmt.Errorf("failed to write unordered tx to buffer: %w", err) - } - } - - for txHash, timestamp := range m.txHashesBlockTime { - chunk := unorderedTxToBytes(txHash, uint64(timestamp.Unix()), false) + for txHash, timestamp := range m.txHashes { + chunk := unorderedTxToBytes(txHash, uint64(timestamp.Unix())) if _, err = w.Write(chunk); err != nil { return fmt.Errorf("failed to write unordered tx to buffer: %w", err) @@ -272,18 +218,12 @@ func (m *Manager) flushToFile() error { } // expiredTxs returns expired tx hashes based on the provided block height. -func (m *Manager) expiredTxs(blockHeight uint64, blockTime time.Time) []TxHash { +func (m *Manager) expiredTxs(blockTime time.Time) []TxHash { m.mu.RLock() defer m.mu.RUnlock() var result []TxHash - for txHash, height := range m.txHashesBlockHeight { - if blockHeight > height { - result = append(result, txHash) - } - } - - for txHash, timestamp := range m.txHashesBlockTime { + for txHash, timestamp := range m.txHashes { if blockTime.After(timestamp) { result = append(result, txHash) } @@ -292,75 +232,62 @@ func (m *Manager) expiredTxs(blockHeight uint64, blockTime time.Time) []TxHash { return result } -func (m *Manager) purge(txHashesBlockHeight []TxHash) { +func (m *Manager) purge(txHashes []TxHash) { m.mu.Lock() defer m.mu.Unlock() - for _, txHash := range txHashesBlockHeight { - delete(m.txHashesBlockHeight, txHash) - delete(m.txHashesBlockTime, txHash) + for _, txHash := range txHashes { + delete(m.txHashes, txHash) } } // purgeLoop removes expired tx hashes in the background func (m *Manager) purgeLoop() { for { - latestHeight, latestTime, ok := m.batchReceive() + latestTime, ok := m.batchReceive() if !ok { // channel closed m.doneCh <- struct{}{} return } - hashes := m.expiredTxs(latestHeight, latestTime) + hashes := m.expiredTxs(latestTime) if len(hashes) > 0 { m.purge(hashes) } } } -func (m *Manager) batchReceive() (uint64, time.Time, bool) { +func (m *Manager) batchReceive() (time.Time, bool) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - var latestHeight uint64 var latestTime time.Time for { select { case <-ctx.Done(): - return latestHeight, latestTime, true + return latestTime, true - case blockInfo, ok := <-m.blockCh: + case blockTime, ok := <-m.blockCh: if !ok { // channel is closed - return 0, time.Time{}, false - } - if blockInfo.blockHeight > latestHeight { - latestHeight = blockInfo.blockHeight + return time.Time{}, false } - if blockInfo.blockTime.After(latestTime) { - latestTime = blockInfo.blockTime + if blockTime.After(latestTime) { + latestTime = blockTime } } } } -func unorderedTxToBytes(txHash TxHash, ttl uint64, isBlockHeight bool) []byte { +func unorderedTxToBytes(txHash TxHash, ttl uint64) []byte { chunk := make([]byte, chunkSize) copy(chunk[:txHashSize], txHash[:]) - ttlBz := make([]byte, heightSize) + ttlBz := make([]byte, timeoutSize) binary.BigEndian.PutUint64(ttlBz, ttl) - emptyBz := make([]byte, 8) - binary.BigEndian.PutUint64(emptyBz, 0) - if isBlockHeight { - copy(chunk[txHashSize+heightSize:], emptyBz) - copy(chunk[txHashSize:txHashSize+heightSize], ttlBz) - } else { - copy(chunk[txHashSize+heightSize:], ttlBz) - copy(chunk[txHashSize:txHashSize+heightSize], emptyBz) - } + copy(chunk[txHashSize:], ttlBz) return chunk } diff --git a/x/auth/ante/unorderedtx/manager_test.go b/x/auth/ante/unorderedtx/manager_test.go index a6b107bf5f6a..40e48c72be27 100644 --- a/x/auth/ante/unorderedtx/manager_test.go +++ b/x/auth/ante/unorderedtx/manager_test.go @@ -25,9 +25,9 @@ func TestUnorderedTxManager_SimpleSize(t *testing.T) { txm.Start() - txm.Add([32]byte{0xFF}, 100) - txm.Add([32]byte{0xAA}, 100) - txm.Add([32]byte{0xCC}, 100) + txm.Add([32]byte{0xFF}, time.Now()) + txm.Add([32]byte{0xAA}, time.Now()) + txm.Add([32]byte{0xCC}, time.Now()) require.Equal(t, 3, txm.Size()) } @@ -42,7 +42,7 @@ func TestUnorderedTxManager_SimpleContains(t *testing.T) { for i := 0; i < 10; i++ { txHash := [32]byte{byte(i)} - txm.Add(txHash, 100) + txm.Add(txHash, time.Now()) require.True(t, txm.Contains(txHash)) } @@ -70,7 +70,7 @@ func TestUnorderedTxManager_CloseInit(t *testing.T) { // add a handful of unordered txs for i := 0; i < 100; i++ { - txm.Add([32]byte{byte(i)}, 100) + txm.Add([32]byte{byte(i)}, time.Now()) } // close the manager, which should flush all unexpired txs to file @@ -100,29 +100,17 @@ func TestUnorderedTxManager_Flow(t *testing.T) { txm.Start() - // Seed the manager with a txs, some of which should eventually be purged and - // the others will remain. Txs with TTL less than or equal to 50 should be purged. - for i := 1; i <= 100; i++ { - txHash := [32]byte{byte(i)} - - if i <= 50 { - txm.Add(txHash, uint64(i)) - } else { - txm.Add(txHash, 100) - } - } - currentTime := time.Now() // Seed the manager with a txs, some of which should eventually be purged and // the others will remain. Txs with TTL less than or equal to 50 should be purged. for i := 1; i <= 100; i++ { - txHash := [32]byte{byte(i + 100)} + txHash := [32]byte{byte(i)} if i <= 50 { - txm.AddTimestamp(txHash, currentTime.Add(time.Millisecond*500*time.Duration(i))) + txm.Add(txHash, currentTime.Add(time.Millisecond*500*time.Duration(i))) } else { - txm.AddTimestamp(txHash, currentTime.Add(time.Hour)) + txm.Add(txHash, currentTime.Add(time.Hour)) } } @@ -132,12 +120,10 @@ func TestUnorderedTxManager_Flow(t *testing.T) { ticker := time.NewTicker(time.Millisecond * 500) defer ticker.Stop() - var height uint64 = 1 for t := range ticker.C { - txm.OnNewBlock(height, t) - height++ + txm.OnNewBlock(t) - if height > 51 && t.After(currentTime.Add(time.Millisecond*500*time.Duration(50))) { + if t.After(currentTime.Add(time.Millisecond * 500 * time.Duration(50))) { doneBlockCh <- true return } @@ -149,7 +135,7 @@ func TestUnorderedTxManager_Flow(t *testing.T) { require.Eventually( t, func() bool { - return txm.Size() == 100 + return txm.Size() == 50 }, 2*time.Minute, 5*time.Second, diff --git a/x/auth/ante/unorderedtx/snapshotter.go b/x/auth/ante/unorderedtx/snapshotter.go index 4516624c7ed4..690c45445493 100644 --- a/x/auth/ante/unorderedtx/snapshotter.go +++ b/x/auth/ante/unorderedtx/snapshotter.go @@ -11,9 +11,8 @@ import ( const ( txHashSize = 32 - heightSize = 8 timeoutSize = 8 - chunkSize = txHashSize + heightSize + timeoutSize + chunkSize = txHashSize + timeoutSize ) var _ snapshot.ExtensionSnapshotter = &Snapshotter{} @@ -80,21 +79,13 @@ func (s *Snapshotter) restore(height uint64, payloadReader snapshot.ExtensionPay var txHash TxHash copy(txHash[:], payload[i:i+txHashSize]) - timestamp := binary.BigEndian.Uint64(payload[i+txHashSize+heightSize : i+chunkSize]) + timestamp := binary.BigEndian.Uint64(payload[i+txHashSize : i+chunkSize]) // need to come up with a way to fetch blocktime to filter out expired txs // // right now we dont have access block time at this flow, so we would just include the expired txs // and let it be purge during purge loop - if timestamp != 0 { - s.m.AddTimestamp(txHash, time.Unix(int64(timestamp), 0)) - i += chunkSize - continue - } - - ttl := binary.BigEndian.Uint64(payload[i+txHashSize : i+txHashSize+heightSize]) - if height < ttl { - // only add unordered transactions that are still valid, i.e. unexpired - s.m.Add(txHash, ttl) + if timestamp != 0 && timestamp > height { + s.m.Add(txHash, time.Unix(int64(timestamp), 0)) } i += chunkSize diff --git a/x/auth/ante/unorderedtx/snapshotter_test.go b/x/auth/ante/unorderedtx/snapshotter_test.go index c073cf73f054..4b3101f5b068 100644 --- a/x/auth/ante/unorderedtx/snapshotter_test.go +++ b/x/auth/ante/unorderedtx/snapshotter_test.go @@ -2,6 +2,7 @@ package unorderedtx_test import ( "testing" + "time" "github.com/stretchr/testify/require" @@ -12,9 +13,11 @@ func TestSnapshotter(t *testing.T) { dataDir := t.TempDir() txm := unorderedtx.NewManager(dataDir) + currentTime := time.Now() + // add a handful of unordered txs for i := 0; i < 100; i++ { - txm.Add([32]byte{byte(i)}, 100) + txm.Add([32]byte{byte(i)}, currentTime.Add(time.Second*100)) } var unorderedTxBz []byte @@ -36,17 +39,17 @@ func TestSnapshotter(t *testing.T) { err = s.RestoreExtension(50, 2, pr) require.Error(t, err) - // restore with height > ttl which should result in no unordered txs synced + // restore with timestamp > timeout time which should result in no unordered txs synced txm2 := unorderedtx.NewManager(dataDir) s2 := unorderedtx.NewSnapshotter(txm2) - err = s2.RestoreExtension(200, unorderedtx.SnapshotFormat, pr) + err = s2.RestoreExtension(uint64(currentTime.Add(time.Second*200).Unix()), unorderedtx.SnapshotFormat, pr) require.NoError(t, err) require.Empty(t, txm2.Size()) - // restore with height < ttl which should result in all unordered txs synced + // restore with timestamp < timeout time which should result in all unordered txs synced txm3 := unorderedtx.NewManager(dataDir) s3 := unorderedtx.NewSnapshotter(txm3) - err = s3.RestoreExtension(50, unorderedtx.SnapshotFormat, pr) + err = s3.RestoreExtension(uint64(currentTime.Add(time.Second*99).Unix()), unorderedtx.SnapshotFormat, pr) require.NoError(t, err) require.Equal(t, 100, txm3.Size()) From 1013006e18d04c7ed8e79c71c83f7289b57cc173 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 9 Jul 2024 19:49:10 +0700 Subject: [PATCH 19/39] minor --- x/auth/ante/unorderedtx/snapshotter_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/auth/ante/unorderedtx/snapshotter_test.go b/x/auth/ante/unorderedtx/snapshotter_test.go index 4b3101f5b068..dcf7c05a0cd5 100644 --- a/x/auth/ante/unorderedtx/snapshotter_test.go +++ b/x/auth/ante/unorderedtx/snapshotter_test.go @@ -49,7 +49,7 @@ func TestSnapshotter(t *testing.T) { // restore with timestamp < timeout time which should result in all unordered txs synced txm3 := unorderedtx.NewManager(dataDir) s3 := unorderedtx.NewSnapshotter(txm3) - err = s3.RestoreExtension(uint64(currentTime.Add(time.Second*99).Unix()), unorderedtx.SnapshotFormat, pr) + err = s3.RestoreExtension(uint64(currentTime.Add(time.Second*50).Unix()), unorderedtx.SnapshotFormat, pr) require.NoError(t, err) require.Equal(t, 100, txm3.Size()) From 680082e3f490a046946dcdcdf01ce1ec26704e7a Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 9 Jul 2024 19:56:25 +0700 Subject: [PATCH 20/39] fix tests --- simapp/ante.go | 2 +- x/auth/ante/unorderedtx/manager.go | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/simapp/ante.go b/simapp/ante.go index 0557de4582aa..39ccda27ce6f 100644 --- a/simapp/ante.go +++ b/simapp/ante.go @@ -39,7 +39,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), ante.NewValidateBasicDecorator(options.Environment), ante.NewTxTimeoutHeightDecorator(options.Environment), - ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedHeight, unorderedtx.DefaultmaxTimeoutDuration, options.TxManager, options.Environment), + ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, options.TxManager, options.Environment), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), diff --git a/x/auth/ante/unorderedtx/manager.go b/x/auth/ante/unorderedtx/manager.go index 4adcd21dfe89..f9b2dd410eaa 100644 --- a/x/auth/ante/unorderedtx/manager.go +++ b/x/auth/ante/unorderedtx/manager.go @@ -18,9 +18,6 @@ import ( ) const ( - // DefaultMaxUnOrderedHeight defines the default maximum height an un-ordered transaction - // can set. - DefaultMaxUnOrderedHeight = 1024 // DefaultmaxTimeoutDuration defines the default maximum duration an un-ordered transaction // can set. // TODO: need to decide a default value From 4c00978d5742a44673fc67949205cac1ae486b4b Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 9 Jul 2024 20:58:40 +0700 Subject: [PATCH 21/39] lint --- client/tx/factory.go | 1 - 1 file changed, 1 deletion(-) diff --git a/client/tx/factory.go b/client/tx/factory.go index 0972fe5f5d77..e0a204c553dc 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -413,7 +413,6 @@ func (f Factory) PrintUnsignedTx(clientCtx client.Context, msgs ...sdk.Msg) erro return err } - encoder := f.txConfig.TxJSONEncoder() if encoder == nil { return errors.New("cannot print unsigned tx: tx json encoder is nil") From 96507c58818cc421d042c5bdc5ad8141e51a116d Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Wed, 10 Jul 2024 00:24:19 +0700 Subject: [PATCH 22/39] add changelog --- CHANGELOG.md | 2 ++ api/cosmos/tx/v1beta1/tx.pulsar.go | 8 ++------ proto/cosmos/tx/v1beta1/tx.proto | 8 ++------ types/tx/tx.pb.go | 8 ++------ 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0915fbb45ff..5f907d90121c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -197,11 +197,13 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i ### Client Breaking Changes * (runtime) [#19040](https://github.com/cosmos/cosmos-sdk/pull/19040) Simplify app config implementation and deprecate `/cosmos/app/v1alpha1/config` query. +* (client) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Increased gas cost for processing newly added timeout timestamp field in tx body. ### CLI Breaking Changes * (perf)[#20490](https://github.com/cosmos/cosmos-sdk/pull/20490) Sims: Replace runsim command with Go stdlib testing. CLI: `Commit` default true, `Lean`, `SimulateEveryOperation`, `PrintAllInvariants`, `DBBackend` params removed * (server) [#18303](https://github.com/cosmos/cosmos-sdk/pull/18303) `appd export` has moved with other genesis commands, use `appd genesis export` instead. +* (client) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Add `-timeout-timestamp` flag for tx time based timout. ### Deprecated diff --git a/api/cosmos/tx/v1beta1/tx.pulsar.go b/api/cosmos/tx/v1beta1/tx.pulsar.go index 5a8c25c45894..b2feef2fb80f 100644 --- a/api/cosmos/tx/v1beta1/tx.pulsar.go +++ b/api/cosmos/tx/v1beta1/tx.pulsar.go @@ -8551,10 +8551,6 @@ type TxBody struct { Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` // timeout_height is the block height after which this transaction will not // be processed by the chain. - // - // Note, if unordered=true this value MUST be set - // and will act as a short-lived TTL in which the transaction is deemed valid - // and kept in memory to prevent duplicates. TimeoutHeight uint64 `protobuf:"varint,3,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty"` // unordered, when set to true, indicates that the transaction signer(s) // intend for the transaction to be evaluated and executed in an un-ordered @@ -8562,8 +8558,8 @@ type TxBody struct { // incremented, which allows for fire-and-forget as well as concurrent // transaction execution. // - // Note, when set to true, the existing 'timeout_height' or 'timeout_timestamp' value must - // be set and will be used to correspond to a height/time_stamp in which the transaction is deemed + // Note, when set to true, the existing 'timeout_height' value must + // be set and will be used to correspond to a time_stamp in which the transaction is deemed // valid. Unordered bool `protobuf:"varint,4,opt,name=unordered,proto3" json:"unordered,omitempty"` // timeout_timestamp is the block time after which this transaction will not diff --git a/proto/cosmos/tx/v1beta1/tx.proto b/proto/cosmos/tx/v1beta1/tx.proto index 408573ee439b..7b78cd6d07e4 100644 --- a/proto/cosmos/tx/v1beta1/tx.proto +++ b/proto/cosmos/tx/v1beta1/tx.proto @@ -111,10 +111,6 @@ message TxBody { // timeout_height is the block height after which this transaction will not // be processed by the chain. - // - // Note, if unordered=true this value MUST be set - // and will act as a short-lived TTL in which the transaction is deemed valid - // and kept in memory to prevent duplicates. uint64 timeout_height = 3; // unordered, when set to true, indicates that the transaction signer(s) @@ -123,8 +119,8 @@ message TxBody { // incremented, which allows for fire-and-forget as well as concurrent // transaction execution. // - // Note, when set to true, the existing 'timeout_height' or 'timeout_timestamp' value must - // be set and will be used to correspond to a height/time_stamp in which the transaction is deemed + // Note, when set to true, the existing 'timeout_height' value must + // be set and will be used to correspond to a time_stamp in which the transaction is deemed // valid. bool unordered = 4; diff --git a/types/tx/tx.pb.go b/types/tx/tx.pb.go index 7572f91bfef3..5037f2c605d6 100644 --- a/types/tx/tx.pb.go +++ b/types/tx/tx.pb.go @@ -363,10 +363,6 @@ type TxBody struct { Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` // timeout_height is the block height after which this transaction will not // be processed by the chain. - // - // Note, if unordered=true this value MUST be set - // and will act as a short-lived TTL in which the transaction is deemed valid - // and kept in memory to prevent duplicates. TimeoutHeight uint64 `protobuf:"varint,3,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty"` // unordered, when set to true, indicates that the transaction signer(s) // intend for the transaction to be evaluated and executed in an un-ordered @@ -374,8 +370,8 @@ type TxBody struct { // incremented, which allows for fire-and-forget as well as concurrent // transaction execution. // - // Note, when set to true, the existing 'timeout_height' or 'timeout_timestamp' value must - // be set and will be used to correspond to a height/time_stamp in which the transaction is deemed + // Note, when set to true, the existing 'timeout_height' value must + // be set and will be used to correspond to a time_stamp in which the transaction is deemed // valid. Unordered bool `protobuf:"varint,4,opt,name=unordered,proto3" json:"unordered,omitempty"` // timeout_timestamp is the block time after which this transaction will not From b439a8a36e98900ff87362c6e256270a097b020a Mon Sep 17 00:00:00 2001 From: son trinh Date: Wed, 10 Jul 2024 15:26:46 +0700 Subject: [PATCH 23/39] Update x/auth/tx/gogotx.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- x/auth/tx/gogotx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/auth/tx/gogotx.go b/x/auth/tx/gogotx.go index c56a3a9760eb..36d124206b03 100644 --- a/x/auth/tx/gogotx.go +++ b/x/auth/tx/gogotx.go @@ -178,7 +178,7 @@ func (w *gogoTxWrapper) GetMemo() string { return w.Tx.Body.Memo } // GetTimeoutHeight returns the transaction's timeout height (if set). func (w *gogoTxWrapper) GetTimeoutHeight() uint64 { return w.Tx.Body.TimeoutHeight } -// GetTimeoutHeight returns the transaction's timeout height (if set). +// GetTimeoutTimeStamp returns the transaction's timeout timestamp (if set). func (w *gogoTxWrapper) GetTimeoutTimeStamp() time.Time { return w.Tx.Body.TimeoutTimestamp.AsTime() } From 424724b3c23920185d2e44f94568ce5ba56e8831 Mon Sep 17 00:00:00 2001 From: son trinh Date: Mon, 15 Jul 2024 15:43:49 +0700 Subject: [PATCH 24/39] Update UPGRADING.md Co-authored-by: Marko --- UPGRADING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADING.md b/UPGRADING.md index 086404547732..ef6194b989fc 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -103,7 +103,7 @@ transactions in your application: anteDecorators := []sdk.AnteDecorator{ ante.NewSetUpContextDecorator(), // ... - ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, unorderedtx.DefaultmaxTimeoutDuration, app.UnorderedTxManager), + ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, app.UnorderedTxManager), // ... } From 70f772d710377565da00e07128d1f6ccce9860e2 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 16 Jul 2024 10:47:17 +0700 Subject: [PATCH 25/39] address comments --- UPGRADING.md | 2 +- simapp/ante.go | 2 +- x/auth/ante/unordered_test.go | 14 +++++++------- x/auth/ante/unorderedtx/manager.go | 5 ++--- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/UPGRADING.md b/UPGRADING.md index 086404547732..138493f04ca9 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -103,7 +103,7 @@ transactions in your application: anteDecorators := []sdk.AnteDecorator{ ante.NewSetUpContextDecorator(), // ... - ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxUnOrderedTTL, unorderedtx.DefaultmaxTimeoutDuration, app.UnorderedTxManager), + ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, options.TxManager, options.Environment), // ... } diff --git a/simapp/ante.go b/simapp/ante.go index 39ccda27ce6f..61695d1dada3 100644 --- a/simapp/ante.go +++ b/simapp/ante.go @@ -39,7 +39,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), ante.NewValidateBasicDecorator(options.Environment), ante.NewTxTimeoutHeightDecorator(options.Environment), - ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, options.TxManager, options.Environment), + ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, options.TxManager, options.Environment), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), diff --git a/x/auth/ante/unordered_test.go b/x/auth/ante/unordered_test.go index e5ad979dfb95..bddc36b9662e 100644 --- a/x/auth/ante/unordered_test.go +++ b/x/auth/ante/unordered_test.go @@ -27,7 +27,7 @@ func TestUnorderedTxDecorator_OrderedTx(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) tx, txBz := genUnorderedTx(t, false, time.Time{}) ctx := sdk.Context{}.WithTxBytes(txBz) @@ -46,7 +46,7 @@ func TestUnorderedTxDecorator_UnorderedTx_NoTTL(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) tx, txBz := genUnorderedTx(t, true, time.Time{}) ctx := sdk.Context{}.WithTxBytes(txBz) @@ -65,9 +65,9 @@ func TestUnorderedTxDecorator_UnorderedTx_InvalidTTL(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) - tx, txBz := genUnorderedTx(t, true, time.Now().Add(unorderedtx.DefaultmaxTimeoutDuration+time.Second)) + tx, txBz := genUnorderedTx(t, true, time.Now().Add(unorderedtx.DefaultMaxTimeoutDuration+time.Second)) ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}) _, err := chain(ctx, tx, false) require.Error(t, err) @@ -83,7 +83,7 @@ func TestUnorderedTxDecorator_UnorderedTx_AlreadyExists(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute)) ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}) @@ -105,7 +105,7 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidCheckTx(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute)) ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeCheck) @@ -124,7 +124,7 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidDeliverTx(t *testing.T) { suite := SetupTestSuite(t, false) - chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultmaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) + chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment())) tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute)) ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeFinalize) diff --git a/x/auth/ante/unorderedtx/manager.go b/x/auth/ante/unorderedtx/manager.go index f9b2dd410eaa..00e6ae624d5c 100644 --- a/x/auth/ante/unorderedtx/manager.go +++ b/x/auth/ante/unorderedtx/manager.go @@ -20,8 +20,7 @@ import ( const ( // DefaultmaxTimeoutDuration defines the default maximum duration an un-ordered transaction // can set. - // TODO: need to decide a default value - DefaultmaxTimeoutDuration = time.Minute * 40 + DefaultMaxTimeoutDuration = time.Minute * 40 dirName = "unordered_txs" fileName = "data" @@ -166,9 +165,9 @@ func (m *Manager) exportSnapshot(height uint64, snapshotWriter func([]byte) erro keys := maps.Keys(m.txHashes) sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i][:], keys[j][:]) < 0 }) + timestamp := time.Unix(int64(height), 0) for _, txHash := range keys { timeoutTime := m.txHashes[txHash] - timestamp := time.Unix(int64(height), 0) if timestamp.After(timeoutTime) { // skip expired txs that have yet to be purged continue From 0fe0792a171259cf00a2863567be71786cf64ada Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 16 Jul 2024 11:21:20 +0700 Subject: [PATCH 26/39] fix test --- x/auth/ante/unordered_test.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/x/auth/ante/unordered_test.go b/x/auth/ante/unordered_test.go index 2be180566e35..b02fcc28c471 100644 --- a/x/auth/ante/unordered_test.go +++ b/x/auth/ante/unordered_test.go @@ -1,13 +1,13 @@ package ante_test import ( - "crypto/sha256" "testing" "time" "github.com/stretchr/testify/require" "cosmossdk.io/core/header" + storetypes "cosmossdk.io/store/types" "cosmossdk.io/x/auth/ante" "cosmossdk.io/x/auth/ante/unorderedtx" @@ -88,10 +88,11 @@ func TestUnorderedTxDecorator_UnorderedTx_AlreadyExists(t *testing.T) { chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment(), ante.DefaultSha256Cost)) tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute)) - ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}) + ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithGasMeter(storetypes.NewGasMeter(gasConsumed)) - txHash := sha256.Sum256(txBz) - txm.Add(txHash, time.Now().Add(time.Minute)) + bz := [32]byte{} + copy(bz[:], txBz[:32]) + txm.Add(bz, time.Now().Add(time.Minute)) _, err := chain(ctx, tx, false) require.Error(t, err) @@ -110,7 +111,7 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidCheckTx(t *testing.T) { chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment(), ante.DefaultSha256Cost)) tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute)) - ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeCheck) + ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeCheck).WithGasMeter(storetypes.NewGasMeter(gasConsumed)) _, err := chain(ctx, tx, false) require.NoError(t, err) @@ -129,7 +130,7 @@ func TestUnorderedTxDecorator_UnorderedTx_ValidDeliverTx(t *testing.T) { chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, suite.accountKeeper.GetEnvironment(), ante.DefaultSha256Cost)) tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute)) - ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeFinalize) + ctx := sdk.Context{}.WithTxBytes(txBz).WithHeaderInfo(header.Info{Time: time.Now()}).WithExecMode(sdk.ExecModeFinalize).WithGasMeter(storetypes.NewGasMeter(gasConsumed)) _, err := chain(ctx, tx, false) require.NoError(t, err) From c74e08fe1d19d1b5a76f4c4d8b9d4e13679b1360 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 16 Jul 2024 12:06:25 +0700 Subject: [PATCH 27/39] fix tests --- tests/systemtests/unordered_tx_test.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/systemtests/unordered_tx_test.go b/tests/systemtests/unordered_tx_test.go index 4d74cbec2ece..7427e2fd7646 100644 --- a/tests/systemtests/unordered_tx_test.go +++ b/tests/systemtests/unordered_tx_test.go @@ -3,8 +3,9 @@ package systemtests import ( - "strconv" + "fmt" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -27,11 +28,9 @@ func TestUnorderedTXDuplicate(t *testing.T) { sut.StartChain(t) - height := sut.CurrentHeight() - timeoutHeight := height + 15 - timeoutHeightStr := strconv.Itoa(int(timeoutHeight)) + timeoutTimestamp := time.Now().Add(time.Minute * 2) // send tokens - rsp1 := cli.Run("tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from="+account1Addr, "--fees=1stake", "--timeout-height="+timeoutHeightStr, "--unordered", "--sequence=1", "--note=1") + rsp1 := cli.Run("tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from="+account1Addr, "--fees=1stake", fmt.Sprintf("--timeout-timestamp=%v", timeoutTimestamp.Unix()), "--unordered", "--sequence=1", "--note=1") RequireTxSuccess(t, rsp1) assertDuplicateErr := func(xt assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { @@ -39,13 +38,13 @@ func TestUnorderedTXDuplicate(t *testing.T) { assert.Contains(t, gotOutputs[0], "is duplicated: invalid request") return false // always abort } - rsp2 := cli.WithRunErrorMatcher(assertDuplicateErr).Run("tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from="+account1Addr, "--fees=1stake", "--timeout-height="+timeoutHeightStr, "--unordered", "--sequence=1") + rsp2 := cli.WithRunErrorMatcher(assertDuplicateErr).Run("tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from="+account1Addr, "--fees=1stake", fmt.Sprintf("--timeout-timestamp=%v", timeoutTimestamp.Unix()), "--unordered", "--sequence=1") RequireTxFailure(t, rsp2) // assert TX executed before timeout for cli.QueryBalance(account2Addr, "stake") != 5000 { t.Log("query balance") - if current := sut.AwaitNextBlock(t); current > timeoutHeight { + if time.Now().After(timeoutTimestamp) { t.Fatal("TX was not executed before timeout") } } From 6edb58e09e176ef498ca14bc8694fa65c7dcd8d1 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 16 Jul 2024 16:57:53 +0700 Subject: [PATCH 28/39] use eventually --- tests/systemtests/unordered_tx_test.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/systemtests/unordered_tx_test.go b/tests/systemtests/unordered_tx_test.go index 7427e2fd7646..4b22df92b0a5 100644 --- a/tests/systemtests/unordered_tx_test.go +++ b/tests/systemtests/unordered_tx_test.go @@ -28,7 +28,7 @@ func TestUnorderedTXDuplicate(t *testing.T) { sut.StartChain(t) - timeoutTimestamp := time.Now().Add(time.Minute * 2) + timeoutTimestamp := time.Now().Add(time.Minute) // send tokens rsp1 := cli.Run("tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from="+account1Addr, "--fees=1stake", fmt.Sprintf("--timeout-timestamp=%v", timeoutTimestamp.Unix()), "--unordered", "--sequence=1", "--note=1") RequireTxSuccess(t, rsp1) @@ -41,11 +41,7 @@ func TestUnorderedTXDuplicate(t *testing.T) { rsp2 := cli.WithRunErrorMatcher(assertDuplicateErr).Run("tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from="+account1Addr, "--fees=1stake", fmt.Sprintf("--timeout-timestamp=%v", timeoutTimestamp.Unix()), "--unordered", "--sequence=1") RequireTxFailure(t, rsp2) - // assert TX executed before timeout - for cli.QueryBalance(account2Addr, "stake") != 5000 { - t.Log("query balance") - if time.Now().After(timeoutTimestamp) { - t.Fatal("TX was not executed before timeout") - } - } + require.Eventually(t, func() bool { + return cli.QueryBalance(account2Addr, "stake") == 5000 + }, time.Minute, time.Microsecond*500, "TX was not executed before timeout") } From 7b2d554daea60b023cdcc29c76d76e43fc02c221 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Tue, 16 Jul 2024 19:29:53 +0700 Subject: [PATCH 29/39] update ADR --- .../adr-070-unordered-transactions.md | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/docs/architecture/adr-070-unordered-transactions.md b/docs/architecture/adr-070-unordered-transactions.md index b3547b1075ec..abcf63e76dd6 100644 --- a/docs/architecture/adr-070-unordered-transactions.md +++ b/docs/architecture/adr-070-unordered-transactions.md @@ -35,13 +35,13 @@ this proposal, they'll follow the nonce rules the same as before. When an un-ordered transaction is included into a block, the transaction hash is recorded in a dictionary. New transactions are checked against this dictionary for duplicates, and to prevent the dictionary grow indefinitely, the transaction must -specify `timeout_height` for expiration, so it's safe to removed it from the +specify `timeout_timestamp` for expiration, so it's safe to removed it from the dictionary after it's expired. The dictionary can be simply implemented as an in-memory golang map, a preliminary analysis shows that the memory consumption won't be too big, for example `32M = 32 * 1024 * 1024` can support 1024 blocks where each block contains 1024 unordered transactions. For -safety, we should limit the range of `timeout_height` to prevent very long expiration, +safety, we should limit the range of `timeout_timestamp` to prevent very long expiration, and limit the size of the dictionary. ### Transaction Format @@ -58,12 +58,12 @@ message TxBody { In order to provide replay protection, a user should ensure that the transaction's TTL value is relatively short-lived but long enough to provide enough time to be -included in a block, e.g. ~H+50. +included in a block, e.g. ~10 minutes. We facilitate this by storing the transaction's hash in a durable map, `UnorderedTxManager`, to prevent duplicates, i.e. replay attacks. Upon transaction ingress during `CheckTx`, we check if the transaction's hash exists in this map or if the TTL value is stale, -i.e. before the current block. If so, we reject it. Upon inclusion in a block +i.e. before the current block time. If so, we reject it. Upon inclusion in a block during `DeliverTx`, the transaction's hash is set in the map along with it's TTL value. @@ -93,20 +93,20 @@ const PurgeLoopSleepMS = 500 // UnorderedTxManager contains the tx hash dictionary for duplicates checking, // and expire them when block production progresses. type UnorderedTxManager struct { - // blockCh defines a channel to receive newly committed block heights - blockCh chan uint64 + // blockCh defines a channel to receive newly committed block time + blockCh chan time.Time mu sync.RWMutex // txHashes defines a map from tx hash -> TTL value, which is used for duplicate // checking and replay protection, as well as purging the map when the TTL is // expired. - txHashes map[TxHash]uint64 + txHashes map[TxHash]time.Time } func NewUnorderedTxManager() *UnorderedTxManager { m := &UnorderedTxManager{ - blockCh: make(chan uint64, 16), - txHashes: make(map[TxHash]uint64), + blockCh: make(chan time.Time, 16), + txHashes: make(map[TxHash]time.Time), } return m @@ -137,27 +137,27 @@ func (m *UnorderedTxManager) Size() int { return len(m.txHashes) } -func (m *UnorderedTxManager) Add(hash TxHash, expire uint64) { +func (m *UnorderedTxManager) Add(hash TxHash, expire time.Time) { m.mu.Lock() defer m.mu.Unlock() m.txHashes[hash] = expire } -// OnNewBlock send the latest block number to the background purge loop, which +// OnNewBlock send the latest block time to the background purge loop, which // should be called in ABCI Commit event. -func (m *UnorderedTxManager) OnNewBlock(blockHeight uint64) { - m.blockCh <- blockHeight +func (m *UnorderedTxManager) OnNewBlock(blockTime time.Time) { + m.blockCh <- blockTime } -// expiredTxs returns expired tx hashes based on the provided block height. -func (m *UnorderedTxManager) expiredTxs(blockHeight uint64) []TxHash { +// expiredTxs returns expired tx hashes based on the provided block time. +func (m *UnorderedTxManager) expiredTxs(blockTime time.Time) []TxHash { m.mu.RLock() defer m.mu.RUnlock() var result []TxHash for txHash, expire := range m.txHashes { - if blockHeight > expire { + if blockTime.After(expire) { result = append(result, txHash) } } @@ -178,21 +178,17 @@ func (m *UnorderedTxManager) purge(txHashes []TxHash) { // purgeLoop removes expired tx hashes in the background func (m *UnorderedTxManager) purgeLoop() error { for { - blocks := channelBatchRecv(m.blockCh) - if len(blocks) == 0 { - // channel closed - break - } - - latest := *blocks[len(blocks)-1] - hashes := m.expired(latest) - if len(hashes) > 0 { - m.purge(hashes) - } + latestTime, ok := m.batchReceive() + if !ok { + // channel closed + return + } - // avoid burning cpu in catching up phase - time.Sleep(PurgeLoopSleepMS * time.Millisecond) - } + hashes := m.expiredTxs(latestTime) + if len(hashes) > 0 { + m.purge(hashes) + } + } } @@ -237,14 +233,14 @@ verification and map lookup. ```golang const ( - // DefaultMaxUnOrderedTTL defines the default maximum TTL an un-ordered transaction + // DefaultMaxTimeoutDuration defines the default maximum duration an un-ordered transaction // can set. - DefaultMaxUnOrderedTTL = 1024 + DefaultMaxTimeoutDuration = time.Minute * 40 ) type DedupTxDecorator struct { m *UnorderedTxManager - maxUnOrderedTTL uint64 + maxTimeoutDuration time.Time } func (d *DedupTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { @@ -253,13 +249,17 @@ func (d *DedupTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, return next(ctx, tx, simulate) } - if tx.TimeoutHeight() == 0 { - return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "unordered tx must set timeout-height") - } - - if tx.TimeoutHeight() > ctx.BlockHeight() + d.maxUnOrderedTTL { - return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "unordered tx ttl exceeds %d", d.maxUnOrderedTTL) - } + headerInfo := d.env.HeaderService.HeaderInfo(ctx) + timeoutTimestamp := unorderedTx.GetTimeoutTimeStamp() + if timeoutTimestamp.IsZero() || timeoutTimestamp.Unix() == 0 { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_timestamp set") + } + if timeoutTimestamp.Before(headerInfo.Time) { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_timestamp that has already passed") + } + if timeoutTimestamp.After(headerInfo.Time.Add(d.maxTimeoutDuration)) { + return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %s", d.maxTimeoutDuration.String()) + } // in order to create a deterministic hash based on the tx, we need to hash the contents of the tx with signature // Get a Buffer from the pool @@ -302,7 +302,7 @@ encoding is not malleable. If a given transaction, which is otherwise valid, can be encoded to produce different hashes, which reflect the same valid transaction, then a duplicate unordered transaction can be submitted and included in a block. -In order to prevent this, the decoded transaction contents is taken. Starting with the content of the transaction we marshal the transaction in order to prevent a client reordering the transaction. Next we include the gas and timeout height as part of the identifier. All these fields are signed over in the transaction payload. If one of them changes the signature will not match the transaction. +In order to prevent this, the decoded transaction contents is taken. Starting with the content of the transaction we marshal the transaction in order to prevent a client reordering the transaction. Next we include the gas and timeout timestamp as part of the identifier. All these fields are signed over in the transaction payload. If one of them changes the signature will not match the transaction. ### State Management From db37bfaed4e204a40c5df6ff70901b49e2bdecbe Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Mon, 22 Jul 2024 19:03:06 +0700 Subject: [PATCH 30/39] address comment --- client/flags/flags.go | 1 + types/tx_msg.go | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/client/flags/flags.go b/client/flags/flags.go index a4d6ae6b101d..32873c64c241 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -123,6 +123,7 @@ func AddTxFlagsToCmd(cmd *cobra.Command) { if cmd.Flag(FlagFrom) == nil { // avoid flag redefinition when it's already been added by AutoCLI f.String(FlagFrom, "", "Name or address of private key with which to sign") } + cmd.MarkFlagsMutuallyExclusive(FlagTimeoutHeight, FlagTimeoutTimestamp) f.Uint64P(FlagAccountNumber, "a", 0, "The account number of the signing account (offline mode only)") f.Uint64P(FlagSequence, "s", 0, "The sequence number of the signing account (offline mode only)") f.String(FlagNote, "", "Note to add a description to the transaction (previously --memo)") diff --git a/types/tx_msg.go b/types/tx_msg.go index c4fabe98d40f..22e785e898e1 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -80,8 +80,8 @@ type ( GetMemo() string } - // TxWithTimeoutHeight extends the Tx interface by allowing a transaction to - // set a height timeout. + // TxWithTimeoutTimeStamp extends the Tx interface by allowing a transaction to + // set a timeout timestamp. TxWithTimeoutTimeStamp interface { Tx @@ -97,7 +97,7 @@ type ( } // TxWithUnordered extends the Tx interface by allowing a transaction to set - // the unordered field, which implicitly relies on TxWithTimeoutHeight. + // the unordered field, which implicitly relies on TxWithTimeoutTimeStamp. TxWithUnordered interface { TxWithTimeoutTimeStamp From 165702757a5033c3d6e3e4337db96d48cd84e52f Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Mon, 22 Jul 2024 19:54:25 +0700 Subject: [PATCH 31/39] address comments --- CHANGELOG.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cf6e01509bc..6c0117c295f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i * (client) [#19870](https://github.com/cosmos/cosmos-sdk/pull/19870) Add new query command `wait-tx`. Alias `event-query-tx-for` to `wait-tx` for backward compatibility. * (crypto/keyring) [#20212](https://github.com/cosmos/cosmos-sdk/pull/20212) Expose the db keyring used in the keystore. * (genutil) [#19971](https://github.com/cosmos/cosmos-sdk/pull/19971) Allow manually setting the consensus key type in genesis +* (client/tx) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Add `timeout-timestamp` field for tx body defines time based timeout.Add `WithTimeoutTimestamp` to tx factory. ### Improvements @@ -191,16 +192,18 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i * (client) [#20616](https://github.com/cosmos/cosmos-sdk/pull/20616) gentx subcommand output goes to `cmd.ErrOrStderr()` instead of being hardcoded to `os.Stderr` * (types/errors) [#20756](https://github.com/cosmos/cosmos-sdk/pull/20756) Remove `ResponseCheckTxWithEvents`, `ResponseExecTxResultWithEvents` & `QueryResult` from types/errors pkg. They have been moved to `baseapp/errors.go` and made private +### Client Changes + +* (client) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Increased gas cost for processing newly added timeout timestamp field in tx body. + ### Client Breaking Changes -* (runtime) [#19040](https://github.com/cosmos/cosmos-sdk/pull/19040) Simplify app config implementation and deprecate `/cosmos/app/v1alpha1/config` query. -* (client) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Increased gas cost for processing newly added timeout timestamp field in tx body. +* (runtime) [#19040](https://github.com/cosmos/cosmos-sdk/pull/19040) Simplify app config implementation and deprecate `/cosmos/app/v1alpha1/config` query. ### CLI Breaking Changes * (perf)[#20490](https://github.com/cosmos/cosmos-sdk/pull/20490) Sims: Replace runsim command with Go stdlib testing. CLI: `Commit` default true, `Lean`, `SimulateEveryOperation`, `PrintAllInvariants`, `DBBackend` params removed * (server) [#18303](https://github.com/cosmos/cosmos-sdk/pull/18303) `appd export` has moved with other genesis commands, use `appd genesis export` instead. -* (client) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Add `-timeout-timestamp` flag for tx time based timout. ### Deprecated From 9ac9527e8b903c85288c73dceeb237426895e7f8 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Mon, 22 Jul 2024 19:59:08 +0700 Subject: [PATCH 32/39] minor --- CHANGELOG.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01bd9e03f358..013ceef50d5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,7 +61,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i * (client) [#19870](https://github.com/cosmos/cosmos-sdk/pull/19870) Add new query command `wait-tx`. Alias `event-query-tx-for` to `wait-tx` for backward compatibility. * (crypto/keyring) [#20212](https://github.com/cosmos/cosmos-sdk/pull/20212) Expose the db keyring used in the keystore. * (genutil) [#19971](https://github.com/cosmos/cosmos-sdk/pull/19971) Allow manually setting the consensus key type in genesis -* (client/tx) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Add `timeout-timestamp` field for tx body defines time based timeout.Add `WithTimeoutTimestamp` to tx factory. +* (client/tx) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Add `timeout-timestamp` field for tx body defines time based timeout.Add `WithTimeoutTimestamp` to tx factory. Increased gas cost for processing newly added timeout timestamp field in tx body. ### Improvements @@ -198,10 +198,6 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i * (client) [#20616](https://github.com/cosmos/cosmos-sdk/pull/20616) gentx subcommand output goes to `cmd.ErrOrStderr()` instead of being hardcoded to `os.Stderr` * (types/errors) [#20756](https://github.com/cosmos/cosmos-sdk/pull/20756) Remove `ResponseCheckTxWithEvents`, `ResponseExecTxResultWithEvents` & `QueryResult` from types/errors pkg. They have been moved to `baseapp/errors.go` and made private -### Client Changes - -* (client) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Increased gas cost for processing newly added timeout timestamp field in tx body. - ### Client Breaking Changes * (runtime) [#19040](https://github.com/cosmos/cosmos-sdk/pull/19040) Simplify app config implementation and deprecate `/cosmos/app/v1alpha1/config` query. From e5b2a8ec6859d711079010a3e84213aca40d28e0 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Wed, 24 Jul 2024 06:09:12 +0700 Subject: [PATCH 33/39] remove timeout_height flag in CLI --- client/v2/autocli/testdata/help-echo-msg.golden | 1 - 1 file changed, 1 deletion(-) diff --git a/client/v2/autocli/testdata/help-echo-msg.golden b/client/v2/autocli/testdata/help-echo-msg.golden index 2b631ab0642b..e10aaac0ca1a 100644 --- a/client/v2/autocli/testdata/help-echo-msg.golden +++ b/client/v2/autocli/testdata/help-echo-msg.golden @@ -27,7 +27,6 @@ Flags: -o, --output string Output format (text|json) (default "json") -s, --sequence uint The sequence number of the signing account (offline mode only) --sign-mode string Choose sign mode (direct|amino-json|direct-aux|textual), this is an advanced feature - --timeout-height uint Set a block timeout height to prevent the tx from being committed past a certain height --timeout-timestamp int Set a block timeout timestamp to prevent the tx from being committed past a certain time --tip string Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator --unordered Enable unordered transaction delivery; must be used in conjunction with --timeout-height From 43234835efefb10e6bf87bcc4b63f33b7c72bf75 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Wed, 24 Jul 2024 06:12:15 +0700 Subject: [PATCH 34/39] fix tests --- client/flags/flags.go | 3 --- client/tx/factory.go | 2 -- 2 files changed, 5 deletions(-) diff --git a/client/flags/flags.go b/client/flags/flags.go index 32873c64c241..14d0456c4dfd 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -73,7 +73,6 @@ const ( FlagPageKey = "page-key" FlagOffset = "offset" FlagCountTotal = "count-total" - FlagTimeoutHeight = "timeout-height" FlagTimeoutTimestamp = "timeout-timestamp" FlagUnordered = "unordered" FlagKeyAlgorithm = "algo" @@ -123,7 +122,6 @@ func AddTxFlagsToCmd(cmd *cobra.Command) { if cmd.Flag(FlagFrom) == nil { // avoid flag redefinition when it's already been added by AutoCLI f.String(FlagFrom, "", "Name or address of private key with which to sign") } - cmd.MarkFlagsMutuallyExclusive(FlagTimeoutHeight, FlagTimeoutTimestamp) f.Uint64P(FlagAccountNumber, "a", 0, "The account number of the signing account (offline mode only)") f.Uint64P(FlagSequence, "s", 0, "The sequence number of the signing account (offline mode only)") f.String(FlagNote, "", "Note to add a description to the transaction (previously --memo)") @@ -138,7 +136,6 @@ func AddTxFlagsToCmd(cmd *cobra.Command) { f.Bool(FlagOffline, false, "Offline mode (does not allow any online functionality)") f.BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation") f.String(FlagSignMode, "", "Choose sign mode (direct|amino-json|direct-aux|textual), this is an advanced feature") - f.Uint64(FlagTimeoutHeight, 0, "Set a block timeout height to prevent the tx from being committed past a certain height") f.Int64(FlagTimeoutTimestamp, 0, "Set a block timeout timestamp to prevent the tx from being committed past a certain time") f.Bool(FlagUnordered, false, "Enable unordered transaction delivery; must be used in conjunction with --timeout-height") f.String(FlagFeePayer, "", "Fee payer pays fees for the transaction instead of deducting from the signer") diff --git a/client/tx/factory.go b/client/tx/factory.go index b890a80c8463..471aaa7dab1c 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -88,7 +88,6 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e gasAdj := clientCtx.Viper.GetFloat64(flags.FlagGasAdjustment) memo := clientCtx.Viper.GetString(flags.FlagNote) - timeoutHeight := clientCtx.Viper.GetUint64(flags.FlagTimeoutHeight) timestampUnix := clientCtx.Viper.GetInt64(flags.FlagTimeoutTimestamp) timeoutTimestamp := time.Unix(timestampUnix, 0) unordered := clientCtx.Viper.GetBool(flags.FlagUnordered) @@ -108,7 +107,6 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e simulateAndExecute: gasSetting.Simulate, accountNumber: accNum, sequence: accSeq, - timeoutHeight: timeoutHeight, timeoutTimestamp: timeoutTimestamp, unordered: unordered, gasAdjustment: gasAdj, From 02726737c82bfae29e91da54d00723df1c278c64 Mon Sep 17 00:00:00 2001 From: son trinh Date: Wed, 24 Jul 2024 06:26:46 +0700 Subject: [PATCH 35/39] Update client/flags/flags.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- client/flags/flags.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/flags/flags.go b/client/flags/flags.go index 14d0456c4dfd..b3460eb0699a 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -137,6 +137,7 @@ func AddTxFlagsToCmd(cmd *cobra.Command) { f.BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation") f.String(FlagSignMode, "", "Choose sign mode (direct|amino-json|direct-aux|textual), this is an advanced feature") f.Int64(FlagTimeoutTimestamp, 0, "Set a block timeout timestamp to prevent the tx from being committed past a certain time") + f.Bool(FlagUnordered, false, "Enable unordered transaction delivery; must be used in conjunction with --timeout-timestamp") f.Bool(FlagUnordered, false, "Enable unordered transaction delivery; must be used in conjunction with --timeout-height") f.String(FlagFeePayer, "", "Fee payer pays fees for the transaction instead of deducting from the signer") f.String(FlagFeeGranter, "", "Fee granter grants fees for the transaction") From a85d969aa0bb315c890aa085c4c1aaba7626024b Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Wed, 24 Jul 2024 13:08:40 +0700 Subject: [PATCH 36/39] fix tests --- client/flags/flags.go | 1 - 1 file changed, 1 deletion(-) diff --git a/client/flags/flags.go b/client/flags/flags.go index b3460eb0699a..d44ed316792d 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -138,7 +138,6 @@ func AddTxFlagsToCmd(cmd *cobra.Command) { f.String(FlagSignMode, "", "Choose sign mode (direct|amino-json|direct-aux|textual), this is an advanced feature") f.Int64(FlagTimeoutTimestamp, 0, "Set a block timeout timestamp to prevent the tx from being committed past a certain time") f.Bool(FlagUnordered, false, "Enable unordered transaction delivery; must be used in conjunction with --timeout-timestamp") - f.Bool(FlagUnordered, false, "Enable unordered transaction delivery; must be used in conjunction with --timeout-height") f.String(FlagFeePayer, "", "Fee payer pays fees for the transaction instead of deducting from the signer") f.String(FlagFeeGranter, "", "Fee granter grants fees for the transaction") f.String(FlagTip, "", "Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator") From f6c0df56bdc2bfdbe95be4c356beae51551b69b5 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Wed, 24 Jul 2024 13:16:31 +0700 Subject: [PATCH 37/39] fix test --- client/v2/autocli/testdata/help-echo-msg.golden | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/v2/autocli/testdata/help-echo-msg.golden b/client/v2/autocli/testdata/help-echo-msg.golden index e10aaac0ca1a..91c5e678c43e 100644 --- a/client/v2/autocli/testdata/help-echo-msg.golden +++ b/client/v2/autocli/testdata/help-echo-msg.golden @@ -29,5 +29,5 @@ Flags: --sign-mode string Choose sign mode (direct|amino-json|direct-aux|textual), this is an advanced feature --timeout-timestamp int Set a block timeout timestamp to prevent the tx from being committed past a certain time --tip string Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator - --unordered Enable unordered transaction delivery; must be used in conjunction with --timeout-height + --unordered Enable unordered transaction delivery; must be used in conjunction with --timeout-timestamp -y, --yes Skip tx broadcasting prompt confirmation From 2074128146a25de6edef8367df450727c37ae470 Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Mon, 29 Jul 2024 17:33:12 +0700 Subject: [PATCH 38/39] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c3af0638368..be7112183a05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -206,6 +206,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i * (perf)[#20490](https://github.com/cosmos/cosmos-sdk/pull/20490) Sims: Replace runsim command with Go stdlib testing. CLI: `Commit` default true, `Lean`, `SimulateEveryOperation`, `PrintAllInvariants`, `DBBackend` params removed * (server) [#18303](https://github.com/cosmos/cosmos-sdk/pull/18303) `appd export` has moved with other genesis commands, use `appd genesis export` instead. +* (client/tx) [#20870](https://github.com/cosmos/cosmos-sdk/pull/20870) Removed `timeout-height` flag replace with `timeout-timestamp` flag for a time based timeout. ### Deprecated From 4c6c03f73cc94c8be738201b0b7eac835edf630a Mon Sep 17 00:00:00 2001 From: sontrinh16 Date: Mon, 29 Jul 2024 17:51:30 +0700 Subject: [PATCH 39/39] lint --- docs/learn/advanced/00-baseapp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/learn/advanced/00-baseapp.md b/docs/learn/advanced/00-baseapp.md index 8a4fa12b3a15..61e71f28d779 100644 --- a/docs/learn/advanced/00-baseapp.md +++ b/docs/learn/advanced/00-baseapp.md @@ -480,7 +480,7 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/baseapp/abci.go#L623 When the underlying consensus engine receives a block proposal, each transaction in the block needs to be processed by the application. To that end, the underlying consensus engine sends the transactions in FinalizeBlock message to the application for each transaction in a sequential order. -Since `FinalizeBlock` is an ABCI call, `Tx` is received in the encoded `[]byte` form. Nodes first unmarshal the transaction, using the [`TxConfig`](./00-app-anatomy.md#register-codec) defined in the app, then call `runTx` in `execModeFinalize`, which is very similar to `CheckTx` but also executes and writes state changes. +Since `FinalizeBlock` is an ABCI call, `Tx` is received in the encoded `[]byte` form. Nodes first unmarshal the transaction, using the [`TxConfig`](../beginner/00-app-anatomy.md#register-codec) defined in the app, then call `runTx` in `execModeFinalize`, which is very similar to `CheckTx` but also executes and writes state changes. ![blockprocessing](./blockprocessing-1.png)