From e2886f39fc28923584a9e408eb0d355f1f1b9f22 Mon Sep 17 00:00:00 2001 From: Romain Ruetschi <106849+romac@users.noreply.github.com> Date: Wed, 13 Sep 2023 14:28:32 +0200 Subject: [PATCH] Update ICS protos to include misbehaviour messages --- scripts/sync-protobuf.sh | 4 +- src/COSMOS_ICS_COMMIT | 2 +- src/prost/google.protobuf.rs | 626 +++++++++++++++++- .../interchain_security.ccv.consumer.v1.rs | 17 +- .../interchain_security.ccv.provider.v1.rs | 404 +++++++++-- src/prost/interchain_security.ccv.v1.rs | 436 ------------ src/prost/proto_descriptor.bin | Bin 632684 -> 650425 bytes 7 files changed, 988 insertions(+), 501 deletions(-) diff --git a/scripts/sync-protobuf.sh b/scripts/sync-protobuf.sh index f58f23f8..dc7f053d 100755 --- a/scripts/sync-protobuf.sh +++ b/scripts/sync-protobuf.sh @@ -181,13 +181,13 @@ mkdir -p src/prost cd tools/proto-compiler -cargo build --locked +cargo build # Run the proto-compiler twice, # once for std version with --build-tonic set to true # and once for no-std version with --build-tonic set to false -cargo run --locked -- compile \ +cargo run -- compile \ --ics "$COSMOS_ICS_DIR/proto-include" \ --sdk "$COSMOS_SDK_DIR/proto-include" \ --ibc "$IBC_GO_DIR/proto-include" \ diff --git a/src/COSMOS_ICS_COMMIT b/src/COSMOS_ICS_COMMIT index 032e9892..f2c4e503 100644 --- a/src/COSMOS_ICS_COMMIT +++ b/src/COSMOS_ICS_COMMIT @@ -1 +1 @@ -1afe31f573c8dcde08a572572565d43a35eab642 +c881a1aad37f2f8041c913468602edaf69fef9bf diff --git a/src/prost/google.protobuf.rs b/src/prost/google.protobuf.rs index 27ae62a0..d20767eb 100644 --- a/src/prost/google.protobuf.rs +++ b/src/prost/google.protobuf.rs @@ -44,9 +44,14 @@ pub struct FileDescriptorProto { #[prost(message, optional, tag = "9")] pub source_code_info: ::core::option::Option, /// The syntax of the proto file. - /// The supported values are "proto2" and "proto3". + /// The supported values are "proto2", "proto3", and "editions". + /// + /// If `edition` is present, this value must be "editions". #[prost(string, optional, tag = "12")] pub syntax: ::core::option::Option<::prost::alloc::string::String>, + /// The edition of the proto file, which is an opaque string. + #[prost(string, optional, tag = "13")] + pub edition: ::core::option::Option<::prost::alloc::string::String>, } /// Describes a message type. #[allow(clippy::derive_partial_eq_without_eq)] @@ -109,6 +114,90 @@ pub struct ExtensionRangeOptions { /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, + /// For external users: DO NOT USE. We are in the process of open sourcing + /// extension declaration and executing internal cleanups before it can be + /// used externally. + #[prost(message, repeated, tag = "2")] + pub declaration: ::prost::alloc::vec::Vec, + /// Any features defined in the specific edition. + #[prost(message, optional, tag = "50")] + pub features: ::core::option::Option, + /// The verification state of the range. + /// TODO(b/278783756): flip the default to DECLARATION once all empty ranges + /// are marked as UNVERIFIED. + #[prost( + enumeration = "extension_range_options::VerificationState", + optional, + tag = "3", + default = "Unverified" + )] + pub verification: ::core::option::Option, +} +/// Nested message and enum types in `ExtensionRangeOptions`. +pub mod extension_range_options { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct Declaration { + /// The extension number declared within the extension range. + #[prost(int32, optional, tag = "1")] + pub number: ::core::option::Option, + /// The fully-qualified name of the extension field. There must be a leading + /// dot in front of the full name. + #[prost(string, optional, tag = "2")] + pub full_name: ::core::option::Option<::prost::alloc::string::String>, + /// The fully-qualified type name of the extension field. Unlike + /// Metadata.type, Declaration.type must have a leading dot for messages + /// and enums. + #[prost(string, optional, tag = "3")] + pub r#type: ::core::option::Option<::prost::alloc::string::String>, + /// If true, indicates that the number is reserved in the extension range, + /// and any extension field with the number will fail to compile. Set this + /// when a declared extension field is deleted. + #[prost(bool, optional, tag = "5")] + pub reserved: ::core::option::Option, + /// If true, indicates that the extension must be defined as repeated. + /// Otherwise the extension must be defined as optional. + #[prost(bool, optional, tag = "6")] + pub repeated: ::core::option::Option, + } + /// The verification state of the extension range. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum VerificationState { + /// All the extensions of the range must be declared. + Declaration = 0, + Unverified = 1, + } + impl VerificationState { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + VerificationState::Declaration => "DECLARATION", + VerificationState::Unverified => "UNVERIFIED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "DECLARATION" => Some(Self::Declaration), + "UNVERIFIED" => Some(Self::Unverified), + _ => None, + } + } + } } /// Describes a field within a message. #[allow(clippy::derive_partial_eq_without_eq)] @@ -521,6 +610,9 @@ pub struct FileOptions { /// determining the ruby package. #[prost(string, optional, tag = "45")] pub ruby_package: ::core::option::Option<::prost::alloc::string::String>, + /// Any features defined in the specific edition. + #[prost(message, optional, tag = "50")] + pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. /// See the documentation for the "Options" section above. #[prost(message, repeated, tag = "999")] @@ -608,6 +700,10 @@ pub struct MessageOptions { /// this is a formalization for deprecating messages. #[prost(bool, optional, tag = "3", default = "false")] pub deprecated: ::core::option::Option, + /// NOTE: Do not set the option in .proto files. Always use the maps syntax + /// instead. The option should only be implicitly set by the proto compiler + /// parser. + /// /// Whether the message is an automatically generated map entry type for the /// maps field. /// @@ -625,12 +721,24 @@ pub struct MessageOptions { /// use a native map in the target language to hold the keys and values. /// The reflection APIs in such implementations still need to work as /// if the field is a repeated message field. - /// - /// NOTE: Do not set the option in .proto files. Always use the maps syntax - /// instead. The option should only be implicitly set by the proto compiler - /// parser. #[prost(bool, optional, tag = "7")] pub map_entry: ::core::option::Option, + /// Enable the legacy handling of JSON field name conflicts. This lowercases + /// and strips underscored from the fields before comparison in proto3 only. + /// The new behavior takes `json_name` into account and applies to proto2 as + /// well. + /// + /// This should only be used as a temporary measure against broken builds due + /// to the change in behavior for JSON field name conflicts. + /// + /// TODO(b/261750190) This is legacy behavior we plan to remove once downstream + /// teams have had time to migrate. + #[deprecated] + #[prost(bool, optional, tag = "11")] + pub deprecated_legacy_json_field_conflicts: ::core::option::Option, + /// Any features defined in the specific edition. + #[prost(message, optional, tag = "12")] + pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, @@ -640,8 +748,10 @@ pub struct MessageOptions { pub struct FieldOptions { /// The ctype option instructs the C++ code generator to use a different /// representation of the field than it normally would. See the specific - /// options below. This option is not yet implemented in the open source - /// release -- sorry, we'll try to include it in a future version! + /// options below. This option is only implemented to support use of + /// \[ctype=CORD\] and \[ctype=STRING\] (the default) on non-repeated fields of + /// type "bytes" in the open source release -- sorry, we'll try to include + /// other types in a future version! #[prost( enumeration = "field_options::CType", optional, @@ -691,7 +801,6 @@ pub struct FieldOptions { /// call from multiple threads concurrently, while non-const methods continue /// to require exclusive access. /// - /// /// Note that implementations may choose not to check required fields within /// a lazy sub-message. That is, calling IsInitialized() on the outer message /// may return true even if the inner message has missing required fields. @@ -703,11 +812,8 @@ pub struct FieldOptions { /// check its required fields, regardless of whether or not the message has /// been parsed. /// - /// As of 2021, lazy does no correctness checks on the byte stream during - /// parsing. This may lead to crashes if and when an invalid byte stream is - /// finally parsed upon access. - /// - /// TODO(b/211906113): Enable validation on lazy fields. + /// As of May 2022, lazy verifies the contents of the byte stream during + /// parsing. An invalid byte stream will cause the overall parsing to fail. #[prost(bool, optional, tag = "5", default = "false")] pub lazy: ::core::option::Option, /// unverified_lazy does no correctness checks on the byte stream. This should @@ -724,12 +830,39 @@ pub struct FieldOptions { /// For Google-internal migration only. Do not use. #[prost(bool, optional, tag = "10", default = "false")] pub weak: ::core::option::Option, + /// Indicate that the field value should not be printed out when using debug + /// formats, e.g. when the field contains sensitive credentials. + #[prost(bool, optional, tag = "16", default = "false")] + pub debug_redact: ::core::option::Option, + #[prost(enumeration = "field_options::OptionRetention", optional, tag = "17")] + pub retention: ::core::option::Option, + #[prost( + enumeration = "field_options::OptionTargetType", + repeated, + packed = "false", + tag = "19" + )] + pub targets: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "20")] + pub edition_defaults: ::prost::alloc::vec::Vec, + /// Any features defined in the specific edition. + #[prost(message, optional, tag = "21")] + pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, } /// Nested message and enum types in `FieldOptions`. pub mod field_options { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Message)] + pub struct EditionDefault { + #[prost(string, optional, tag = "1")] + pub edition: ::core::option::Option<::prost::alloc::string::String>, + /// Textproto value. + #[prost(string, optional, tag = "2")] + pub value: ::core::option::Option<::prost::alloc::string::String>, + } #[derive( Clone, Copy, @@ -745,6 +878,12 @@ pub mod field_options { pub enum CType { /// Default mode. String = 0, + /// The option \[ctype=CORD\] may be applied to a non-repeated field of type + /// "bytes". It indicates that in C++, the data should be stored in a Cord + /// instead of a string. For very large strings, this may reduce memory + /// fragmentation. It may also allow better performance when parsing from a + /// Cord, or when parsing with aliasing enabled, as the parsed Cord may then + /// alias the original buffer. Cord = 1, StringPiece = 2, } @@ -812,10 +951,121 @@ pub mod field_options { } } } + /// If set to RETENTION_SOURCE, the option will be omitted from the binary. + /// Note: as of January 2023, support for this is in progress and does not yet + /// have an effect (b/264593489). + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum OptionRetention { + RetentionUnknown = 0, + RetentionRuntime = 1, + RetentionSource = 2, + } + impl OptionRetention { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + OptionRetention::RetentionUnknown => "RETENTION_UNKNOWN", + OptionRetention::RetentionRuntime => "RETENTION_RUNTIME", + OptionRetention::RetentionSource => "RETENTION_SOURCE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "RETENTION_UNKNOWN" => Some(Self::RetentionUnknown), + "RETENTION_RUNTIME" => Some(Self::RetentionRuntime), + "RETENTION_SOURCE" => Some(Self::RetentionSource), + _ => None, + } + } + } + /// This indicates the types of entities that the field may apply to when used + /// as an option. If it is unset, then the field may be freely used as an + /// option on any kind of entity. Note: as of January 2023, support for this is + /// in progress and does not yet have an effect (b/264593489). + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum OptionTargetType { + TargetTypeUnknown = 0, + TargetTypeFile = 1, + TargetTypeExtensionRange = 2, + TargetTypeMessage = 3, + TargetTypeField = 4, + TargetTypeOneof = 5, + TargetTypeEnum = 6, + TargetTypeEnumEntry = 7, + TargetTypeService = 8, + TargetTypeMethod = 9, + } + impl OptionTargetType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + OptionTargetType::TargetTypeUnknown => "TARGET_TYPE_UNKNOWN", + OptionTargetType::TargetTypeFile => "TARGET_TYPE_FILE", + OptionTargetType::TargetTypeExtensionRange => { + "TARGET_TYPE_EXTENSION_RANGE" + } + OptionTargetType::TargetTypeMessage => "TARGET_TYPE_MESSAGE", + OptionTargetType::TargetTypeField => "TARGET_TYPE_FIELD", + OptionTargetType::TargetTypeOneof => "TARGET_TYPE_ONEOF", + OptionTargetType::TargetTypeEnum => "TARGET_TYPE_ENUM", + OptionTargetType::TargetTypeEnumEntry => "TARGET_TYPE_ENUM_ENTRY", + OptionTargetType::TargetTypeService => "TARGET_TYPE_SERVICE", + OptionTargetType::TargetTypeMethod => "TARGET_TYPE_METHOD", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "TARGET_TYPE_UNKNOWN" => Some(Self::TargetTypeUnknown), + "TARGET_TYPE_FILE" => Some(Self::TargetTypeFile), + "TARGET_TYPE_EXTENSION_RANGE" => Some(Self::TargetTypeExtensionRange), + "TARGET_TYPE_MESSAGE" => Some(Self::TargetTypeMessage), + "TARGET_TYPE_FIELD" => Some(Self::TargetTypeField), + "TARGET_TYPE_ONEOF" => Some(Self::TargetTypeOneof), + "TARGET_TYPE_ENUM" => Some(Self::TargetTypeEnum), + "TARGET_TYPE_ENUM_ENTRY" => Some(Self::TargetTypeEnumEntry), + "TARGET_TYPE_SERVICE" => Some(Self::TargetTypeService), + "TARGET_TYPE_METHOD" => Some(Self::TargetTypeMethod), + _ => None, + } + } + } } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OneofOptions { + /// Any features defined in the specific edition. + #[prost(message, optional, tag = "1")] + pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, @@ -833,6 +1083,18 @@ pub struct EnumOptions { /// is a formalization for deprecating enums. #[prost(bool, optional, tag = "3", default = "false")] pub deprecated: ::core::option::Option, + /// Enable the legacy handling of JSON field name conflicts. This lowercases + /// and strips underscored from the fields before comparison in proto3 only. + /// The new behavior takes `json_name` into account and applies to proto2 as + /// well. + /// TODO(b/261750190) Remove this legacy behavior once downstream teams have + /// had time to migrate. + #[deprecated] + #[prost(bool, optional, tag = "6")] + pub deprecated_legacy_json_field_conflicts: ::core::option::Option, + /// Any features defined in the specific edition. + #[prost(message, optional, tag = "7")] + pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, @@ -846,6 +1108,14 @@ pub struct EnumValueOptions { /// this is a formalization for deprecating enum values. #[prost(bool, optional, tag = "1", default = "false")] pub deprecated: ::core::option::Option, + /// Any features defined in the specific edition. + #[prost(message, optional, tag = "2")] + pub features: ::core::option::Option, + /// Indicate that fields annotated with this enum value should not be printed + /// out when using debug formats, e.g. when the field contains sensitive + /// credentials. + #[prost(bool, optional, tag = "3", default = "false")] + pub debug_redact: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, @@ -853,6 +1123,9 @@ pub struct EnumValueOptions { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ServiceOptions { + /// Any features defined in the specific edition. + #[prost(message, optional, tag = "34")] + pub features: ::core::option::Option, /// Is this service deprecated? /// Depending on the target platform, this can emit Deprecated annotations /// for the service, or it will be completely ignored; in the very least, @@ -879,6 +1152,9 @@ pub struct MethodOptions { default = "IdempotencyUnknown" )] pub idempotency_level: ::core::option::Option, + /// Any features defined in the specific edition. + #[prost(message, optional, tag = "35")] + pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, @@ -972,6 +1248,273 @@ pub mod uninterpreted_option { pub is_extension: bool, } } +/// TODO(b/274655146) Enums in C++ gencode (and potentially other languages) are +/// not well scoped. This means that each of the feature enums below can clash +/// with each other. The short names we've chosen maximize call-site +/// readability, but leave us very open to this scenario. A future feature will +/// be designed and implemented to handle this, hopefully before we ever hit a +/// conflict here. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FeatureSet { + #[prost(enumeration = "feature_set::FieldPresence", optional, tag = "1")] + pub field_presence: ::core::option::Option, + #[prost(enumeration = "feature_set::EnumType", optional, tag = "2")] + pub enum_type: ::core::option::Option, + #[prost(enumeration = "feature_set::RepeatedFieldEncoding", optional, tag = "3")] + pub repeated_field_encoding: ::core::option::Option, + #[prost(enumeration = "feature_set::StringFieldValidation", optional, tag = "4")] + pub string_field_validation: ::core::option::Option, + #[prost(enumeration = "feature_set::MessageEncoding", optional, tag = "5")] + pub message_encoding: ::core::option::Option, + #[prost(enumeration = "feature_set::JsonFormat", optional, tag = "6")] + pub json_format: ::core::option::Option, + #[prost(message, optional, boxed, tag = "999")] + pub raw_features: ::core::option::Option<::prost::alloc::boxed::Box>, +} +/// Nested message and enum types in `FeatureSet`. +pub mod feature_set { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum FieldPresence { + Unknown = 0, + Explicit = 1, + Implicit = 2, + LegacyRequired = 3, + } + impl FieldPresence { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + FieldPresence::Unknown => "FIELD_PRESENCE_UNKNOWN", + FieldPresence::Explicit => "EXPLICIT", + FieldPresence::Implicit => "IMPLICIT", + FieldPresence::LegacyRequired => "LEGACY_REQUIRED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "FIELD_PRESENCE_UNKNOWN" => Some(Self::Unknown), + "EXPLICIT" => Some(Self::Explicit), + "IMPLICIT" => Some(Self::Implicit), + "LEGACY_REQUIRED" => Some(Self::LegacyRequired), + _ => None, + } + } + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum EnumType { + Unknown = 0, + Open = 1, + Closed = 2, + } + impl EnumType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + EnumType::Unknown => "ENUM_TYPE_UNKNOWN", + EnumType::Open => "OPEN", + EnumType::Closed => "CLOSED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "ENUM_TYPE_UNKNOWN" => Some(Self::Unknown), + "OPEN" => Some(Self::Open), + "CLOSED" => Some(Self::Closed), + _ => None, + } + } + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum RepeatedFieldEncoding { + Unknown = 0, + Packed = 1, + Expanded = 2, + } + impl RepeatedFieldEncoding { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + RepeatedFieldEncoding::Unknown => "REPEATED_FIELD_ENCODING_UNKNOWN", + RepeatedFieldEncoding::Packed => "PACKED", + RepeatedFieldEncoding::Expanded => "EXPANDED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "REPEATED_FIELD_ENCODING_UNKNOWN" => Some(Self::Unknown), + "PACKED" => Some(Self::Packed), + "EXPANDED" => Some(Self::Expanded), + _ => None, + } + } + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum StringFieldValidation { + Unknown = 0, + Mandatory = 1, + Hint = 2, + None = 3, + } + impl StringFieldValidation { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + StringFieldValidation::Unknown => "STRING_FIELD_VALIDATION_UNKNOWN", + StringFieldValidation::Mandatory => "MANDATORY", + StringFieldValidation::Hint => "HINT", + StringFieldValidation::None => "NONE", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "STRING_FIELD_VALIDATION_UNKNOWN" => Some(Self::Unknown), + "MANDATORY" => Some(Self::Mandatory), + "HINT" => Some(Self::Hint), + "NONE" => Some(Self::None), + _ => None, + } + } + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum MessageEncoding { + Unknown = 0, + LengthPrefixed = 1, + Delimited = 2, + } + impl MessageEncoding { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + MessageEncoding::Unknown => "MESSAGE_ENCODING_UNKNOWN", + MessageEncoding::LengthPrefixed => "LENGTH_PREFIXED", + MessageEncoding::Delimited => "DELIMITED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "MESSAGE_ENCODING_UNKNOWN" => Some(Self::Unknown), + "LENGTH_PREFIXED" => Some(Self::LengthPrefixed), + "DELIMITED" => Some(Self::Delimited), + _ => None, + } + } + } + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum JsonFormat { + Unknown = 0, + Allow = 1, + LegacyBestEffort = 2, + } + impl JsonFormat { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + JsonFormat::Unknown => "JSON_FORMAT_UNKNOWN", + JsonFormat::Allow => "ALLOW", + JsonFormat::LegacyBestEffort => "LEGACY_BEST_EFFORT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "JSON_FORMAT_UNKNOWN" => Some(Self::Unknown), + "ALLOW" => Some(Self::Allow), + "LEGACY_BEST_EFFORT" => Some(Self::LegacyBestEffort), + _ => None, + } + } + } +} /// Encapsulates information about the original source file from which a /// FileDescriptorProto was generated. #[allow(clippy::derive_partial_eq_without_eq)] @@ -1145,10 +1688,59 @@ pub mod generated_code_info { #[prost(int32, optional, tag = "3")] pub begin: ::core::option::Option, /// Identifies the ending offset in bytes in the generated code that - /// relates to the identified offset. The end offset should be one past + /// relates to the identified object. The end offset should be one past /// the last relevant byte (so the length of the text = end - begin). #[prost(int32, optional, tag = "4")] pub end: ::core::option::Option, + #[prost(enumeration = "annotation::Semantic", optional, tag = "5")] + pub semantic: ::core::option::Option, + } + /// Nested message and enum types in `Annotation`. + pub mod annotation { + /// Represents the identified object's effect on the element in the original + /// .proto file. + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Semantic { + /// There is no effect or the effect is indescribable. + None = 0, + /// The element is set or otherwise mutated. + Set = 1, + /// An alias to the element is returned. + Alias = 2, + } + impl Semantic { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Semantic::None => "NONE", + Semantic::Set => "SET", + Semantic::Alias => "ALIAS", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "NONE" => Some(Self::None), + "SET" => Some(Self::Set), + "ALIAS" => Some(Self::Alias), + _ => None, + } + } + } } } /// `Any` contains an arbitrary serialized protocol buffer message along with a @@ -1320,7 +1912,6 @@ pub struct Any { /// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) /// .setNanos((int) ((millis % 1000) * 1000000)).build(); /// -/// /// Example 5: Compute Timestamp from Java `Instant.now()`. /// /// Instant now = Instant.now(); @@ -1329,7 +1920,6 @@ pub struct Any { /// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) /// .setNanos(now.getNano()).build(); /// -/// /// Example 6: Compute Timestamp from current time in Python. /// /// timestamp = Timestamp() @@ -1359,10 +1949,9 @@ pub struct Any { /// \[`strftime`\]() with /// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use /// the Joda Time's \[`ISODateTimeFormat.dateTime()`\]( -/// +/// ) /// ) to obtain a formatter capable of generating timestamps in this format. /// -/// #[cfg_attr(feature = "std", derive(::serde::Serialize, ::serde::Deserialize))] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1438,7 +2027,6 @@ pub struct Timestamp { /// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 /// microsecond should be expressed in JSON format as "3.000001s". /// -/// #[cfg_attr(feature = "std", derive(::serde::Serialize, ::serde::Deserialize))] #[derive(Eq)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/src/prost/interchain_security.ccv.consumer.v1.rs b/src/prost/interchain_security.ccv.consumer.v1.rs index 1712e414..2030193f 100644 --- a/src/prost/interchain_security.ccv.consumer.v1.rs +++ b/src/prost/interchain_security.ccv.consumer.v1.rs @@ -2,7 +2,7 @@ #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Params { - /// TODO: Remove enabled flag and find a better way to setup e2e tests + /// TODO: Remove enabled flag and find a better way to setup integration tests /// See: #[prost(bool, tag = "1")] pub enabled: bool, @@ -47,6 +47,18 @@ pub struct Params { pub unbonding_period: ::core::option::Option< super::super::super::super::google::protobuf::Duration, >, + /// The threshold for the percentage of validators at the bottom of the set who + /// can opt out of running the consumer chain without being punished. For example, a + /// value of 0.05 means that the validators in the bottom 5% of the set can opt out + #[prost(string, tag = "10")] + pub soft_opt_out_threshold: ::prost::alloc::string::String, + /// Reward denoms. These are the denominations which are allowed to be sent to the provider as rewards. + #[prost(string, repeated, tag = "11")] + pub reward_denoms: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + /// Provider-originated reward denoms. These are denoms coming from the provider + /// which are allowed to be used as rewards. e.g. "uatom" + #[prost(string, repeated, tag = "12")] + pub provider_reward_denoms: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } /// LastTransmissionBlockHeight is the last time validator holding /// pools were transmitted to the provider chain @@ -130,6 +142,9 @@ pub struct GenesisState { pub last_transmission_block_height: ::core::option::Option< LastTransmissionBlockHeight, >, + /// flag indicating whether the consumer CCV module starts in pre-CCV state + #[prost(bool, tag = "13")] + pub pre_ccv: bool, } /// HeightValsetUpdateID defines the genesis information for the mapping /// of each block height to a valset update id diff --git a/src/prost/interchain_security.ccv.provider.v1.rs b/src/prost/interchain_security.ccv.provider.v1.rs index a63d0017..3dd032c5 100644 --- a/src/prost/interchain_security.ccv.provider.v1.rs +++ b/src/prost/interchain_security.ccv.provider.v1.rs @@ -7,17 +7,33 @@ pub struct MsgAssignConsumerKey { /// The validator address on the provider #[prost(string, tag = "2")] pub provider_addr: ::prost::alloc::string::String, - /// The consensus public key to use on the consumer - #[prost(message, optional, tag = "3")] - pub consumer_key: ::core::option::Option< - super::super::super::super::google::protobuf::Any, - >, + /// The consensus public key to use on the consumer. + /// in json string format corresponding to proto-any, ex: + /// `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}` + #[prost(string, tag = "3")] + pub consumer_key: ::prost::alloc::string::String, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgAssignConsumerKeyResponse {} +/// MsgRegisterConsumerRewardDenom allows an account to register +/// a consumer reward denom, i.e., add it to the list of denoms +/// accepted by the provider as rewards. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgRegisterConsumerRewardDenom { + #[prost(string, tag = "1")] + pub denom: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub depositor: ::prost::alloc::string::String, +} +/// MsgRegisterConsumerRewardDenomResponse defines the Msg/RegisterConsumerRewardDenom response type. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgRegisterConsumerRewardDenomResponse {} /// MsgSubmitConsumerMisbehaviour defines a message that reports a misbehaviour /// observed on a consumer chain +/// Note that the misbheaviour' headers must contain the same trusted states #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgSubmitConsumerMisbehaviour { @@ -33,6 +49,28 @@ pub struct MsgSubmitConsumerMisbehaviour { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct MsgSubmitConsumerMisbehaviourResponse {} +/// MsgSubmitConsumerDoubleVoting defines a message that reports an equivocation +/// observed on a consumer chain +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSubmitConsumerDoubleVoting { + #[prost(string, tag = "1")] + pub submitter: ::prost::alloc::string::String, + /// The equivocation of the consumer chain wrapping + /// an evidence of a validator that signed two conflicting votes + #[prost(message, optional, tag = "2")] + pub duplicate_vote_evidence: ::core::option::Option< + ::tendermint_proto::types::DuplicateVoteEvidence, + >, + /// The light client header of the infraction block + #[prost(message, optional, tag = "3")] + pub infraction_block_header: ::core::option::Option< + super::super::super::super::ibc::lightclients::tendermint::v1::Header, + >, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MsgSubmitConsumerDoubleVotingResponse {} /// Generated client implementations. #[cfg(feature = "client")] pub mod msg_client { @@ -150,6 +188,36 @@ pub mod msg_client { ); self.inner.unary(req, path, codec).await } + pub async fn register_consumer_reward_denom( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/interchain_security.ccv.provider.v1.Msg/RegisterConsumerRewardDenom", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "interchain_security.ccv.provider.v1.Msg", + "RegisterConsumerRewardDenom", + ), + ); + self.inner.unary(req, path, codec).await + } pub async fn submit_consumer_misbehaviour( &mut self, request: impl tonic::IntoRequest, @@ -180,6 +248,36 @@ pub mod msg_client { ); self.inner.unary(req, path, codec).await } + pub async fn submit_consumer_double_voting( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/interchain_security.ccv.provider.v1.Msg/SubmitConsumerDoubleVoting", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "interchain_security.ccv.provider.v1.Msg", + "SubmitConsumerDoubleVoting", + ), + ); + self.inner.unary(req, path, codec).await + } } } /// Generated server implementations. @@ -197,6 +295,13 @@ pub mod msg_server { tonic::Response, tonic::Status, >; + async fn register_consumer_reward_denom( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn submit_consumer_misbehaviour( &self, request: tonic::Request, @@ -204,6 +309,13 @@ pub mod msg_server { tonic::Response, tonic::Status, >; + async fn submit_consumer_double_voting( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } /// Msg defines the Msg service. #[derive(Debug)] @@ -329,6 +441,54 @@ pub mod msg_server { }; Box::pin(fut) } + "/interchain_security.ccv.provider.v1.Msg/RegisterConsumerRewardDenom" => { + #[allow(non_camel_case_types)] + struct RegisterConsumerRewardDenomSvc(pub Arc); + impl< + T: Msg, + > tonic::server::UnaryService + for RegisterConsumerRewardDenomSvc { + type Response = super::MsgRegisterConsumerRewardDenomResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::MsgRegisterConsumerRewardDenom, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).register_consumer_reward_denom(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = RegisterConsumerRewardDenomSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/interchain_security.ccv.provider.v1.Msg/SubmitConsumerMisbehaviour" => { #[allow(non_camel_case_types)] struct SubmitConsumerMisbehaviourSvc(pub Arc); @@ -375,6 +535,52 @@ pub mod msg_server { }; Box::pin(fut) } + "/interchain_security.ccv.provider.v1.Msg/SubmitConsumerDoubleVoting" => { + #[allow(non_camel_case_types)] + struct SubmitConsumerDoubleVotingSvc(pub Arc); + impl< + T: Msg, + > tonic::server::UnaryService + for SubmitConsumerDoubleVotingSvc { + type Response = super::MsgSubmitConsumerDoubleVotingResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).submit_consumer_double_voting(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = SubmitConsumerDoubleVotingSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( @@ -482,6 +688,14 @@ pub struct ConsumerAdditionProposal { /// a ccv enabled consumer chain, the ccv module acts as the staking module. #[prost(int64, tag = "13")] pub historical_entries: i64, + /// The ID of a token transfer channel used for the Reward Distribution + /// sub-protocol. If DistributionTransmissionChannel == "", a new transfer + /// channel is created on top of the same connection as the CCV channel. + /// Note that transfer_channel_id is the ID of the channel end on the consumer chain. + /// it is most relevant for chains performing a sovereign to consumer changeover + /// in order to maintan the existing ibc transfer channel + #[prost(string, tag = "14")] + pub distribution_transmission_channel: ::prost::alloc::string::String, } /// ConsumerRemovalProposal is a governance proposal on the provider chain to remove (and stop) a consumer chain. /// If it passes, all the consumer chain's state is removed from the provider chain. The outstanding unbonding @@ -586,6 +800,11 @@ pub struct Params { /// that can be queued for a single consumer before the provider chain halts. #[prost(int64, tag = "8")] pub max_throttled_packets: i64, + /// The fee required to be paid to add a reward denom + #[prost(message, optional, tag = "9")] + pub consumer_reward_denom_registration_fee: ::core::option::Option< + super::super::super::super::cosmos::base::v1beta1::Coin, + >, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -595,7 +814,7 @@ pub struct HandshakeMetadata { #[prost(string, tag = "2")] pub version: ::prost::alloc::string::String, } -/// SlashAcks contains addesses of consumer chain validators +/// SlashAcks contains cons addresses of consumer chain validators /// successfully slashed on the provider chain #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -685,6 +904,42 @@ pub struct KeyAssignmentReplacement { #[prost(int64, tag = "3")] pub power: i64, } +/// Used to serialize the ValidatorConsumerPubKey index from key assignment +/// ValidatorConsumerPubKey: (chainID, providerAddr consAddr) -> consumerKey tmprotocrypto.PublicKey +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ValidatorConsumerPubKey { + #[prost(string, tag = "1")] + pub chain_id: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub provider_addr: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "3")] + pub consumer_key: ::core::option::Option<::tendermint_proto::crypto::PublicKey>, +} +/// Used to serialize the ValidatorConsumerAddr index from key assignment +/// ValidatorByConsumerAddr: (chainID, consumerAddr consAddr) -> providerAddr consAddr +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ValidatorByConsumerAddr { + #[prost(string, tag = "1")] + pub chain_id: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub consumer_addr: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "3")] + pub provider_addr: ::prost::alloc::vec::Vec, +} +/// Used to serialize the ConsumerAddrsToPrune index from key assignment +/// ConsumerAddrsToPrune: (chainID, vscID uint64) -> consumerAddrs AddressList +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ConsumerAddrsToPrune { + #[prost(string, tag = "1")] + pub chain_id: ::prost::alloc::string::String, + #[prost(uint64, tag = "2")] + pub vsc_id: u64, + #[prost(message, optional, tag = "3")] + pub consumer_addrs: ::core::option::Option, +} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct QueryConsumerGenesisRequest { @@ -831,6 +1086,15 @@ pub mod throttled_packet_data_wrapper { VscMaturedPacket(super::super::super::v1::VscMaturedPacketData), } } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryRegisteredConsumerRewardDenomsRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct QueryRegisteredConsumerRewardDenomsResponse { + #[prost(string, repeated, tag = "1")] + pub denoms: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} /// Generated client implementations. #[cfg(feature = "client")] pub mod query_client { @@ -1176,6 +1440,39 @@ pub mod query_client { ); self.inner.unary(req, path, codec).await } + /// QueryRegisteredConsumerRewardDenoms returns a list of consumer reward denoms that are registered + pub async fn query_registered_consumer_reward_denoms( + &mut self, + request: impl tonic::IntoRequest< + super::QueryRegisteredConsumerRewardDenomsRequest, + >, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/interchain_security.ccv.provider.v1.Query/QueryRegisteredConsumerRewardDenoms", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "interchain_security.ccv.provider.v1.Query", + "QueryRegisteredConsumerRewardDenoms", + ), + ); + self.inner.unary(req, path, codec).await + } } } /// Generated server implementations. @@ -1255,6 +1552,14 @@ pub mod query_server { tonic::Response, tonic::Status, >; + /// QueryRegisteredConsumerRewardDenoms returns a list of consumer reward denoms that are registered + async fn query_registered_consumer_reward_denoms( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct QueryServer { @@ -1718,6 +2023,57 @@ pub mod query_server { }; Box::pin(fut) } + "/interchain_security.ccv.provider.v1.Query/QueryRegisteredConsumerRewardDenoms" => { + #[allow(non_camel_case_types)] + struct QueryRegisteredConsumerRewardDenomsSvc(pub Arc); + impl< + T: Query, + > tonic::server::UnaryService< + super::QueryRegisteredConsumerRewardDenomsRequest, + > for QueryRegisteredConsumerRewardDenomsSvc { + type Response = super::QueryRegisteredConsumerRewardDenomsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::QueryRegisteredConsumerRewardDenomsRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner) + .query_registered_consumer_reward_denoms(request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = QueryRegisteredConsumerRewardDenomsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( @@ -1840,39 +2196,3 @@ pub struct ValsetUpdateIdToHeight { #[prost(uint64, tag = "2")] pub height: u64, } -/// Used to serialize the ValidatorConsumerPubKey index from key assignment -/// ValidatorConsumerPubKey: (chainID, providerAddr consAddr) -> consumerKey tmprotocrypto.PublicKey -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ValidatorConsumerPubKey { - #[prost(string, tag = "1")] - pub chain_id: ::prost::alloc::string::String, - #[prost(bytes = "vec", tag = "2")] - pub provider_addr: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "3")] - pub consumer_key: ::core::option::Option<::tendermint_proto::crypto::PublicKey>, -} -/// Used to serialize the ValidatorConsumerAddr index from key assignment -/// ValidatorByConsumerAddr: (chainID, consumerAddr consAddr) -> providerAddr consAddr -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ValidatorByConsumerAddr { - #[prost(string, tag = "1")] - pub chain_id: ::prost::alloc::string::String, - #[prost(bytes = "vec", tag = "2")] - pub consumer_addr: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "3")] - pub provider_addr: ::prost::alloc::vec::Vec, -} -/// Used to serialize the ConsumerAddrsToPrune index from key assignment -/// ConsumerAddrsToPrune: (chainID, vscID uint64) -> consumerAddrs AddressList -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConsumerAddrsToPrune { - #[prost(string, tag = "1")] - pub chain_id: ::prost::alloc::string::String, - #[prost(uint64, tag = "2")] - pub vsc_id: u64, - #[prost(message, optional, tag = "3")] - pub consumer_addrs: ::core::option::Option, -} diff --git a/src/prost/interchain_security.ccv.v1.rs b/src/prost/interchain_security.ccv.v1.rs index 7db20bc2..ba6f17cd 100644 --- a/src/prost/interchain_security.ccv.v1.rs +++ b/src/prost/interchain_security.ccv.v1.rs @@ -1,439 +1,3 @@ -/// Generated client implementations. -#[cfg(feature = "client")] -pub mod msg_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - use tonic::codegen::http::Uri; - /// Msg defines the Msg service. - #[derive(Debug, Clone)] - pub struct MsgClient { - inner: tonic::client::Grpc, - } - impl MsgClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl MsgClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> MsgClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + Send + Sync, - { - MsgClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - } -} -/// Generated server implementations. -#[cfg(feature = "server")] -pub mod msg_server { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with MsgServer. - #[async_trait] - pub trait Msg: Send + Sync + 'static {} - /// Msg defines the Msg service. - #[derive(Debug)] - pub struct MsgServer { - inner: _Inner, - accept_compression_encodings: EnabledCompressionEncodings, - send_compression_encodings: EnabledCompressionEncodings, - max_decoding_message_size: Option, - max_encoding_message_size: Option, - } - struct _Inner(Arc); - impl MsgServer { - pub fn new(inner: T) -> Self { - Self::from_arc(Arc::new(inner)) - } - pub fn from_arc(inner: Arc) -> Self { - let inner = _Inner(inner); - Self { - inner, - accept_compression_encodings: Default::default(), - send_compression_encodings: Default::default(), - max_decoding_message_size: None, - max_encoding_message_size: None, - } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> InterceptedService - where - F: tonic::service::Interceptor, - { - InterceptedService::new(Self::new(inner), interceptor) - } - /// Enable decompressing requests with the given encoding. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.accept_compression_encodings.enable(encoding); - self - } - /// Compress responses with the given encoding, if the client supports it. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.send_compression_encodings.enable(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.max_decoding_message_size = Some(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.max_encoding_message_size = Some(limit); - self - } - } - impl tonic::codegen::Service> for MsgServer - where - T: Msg, - B: Body + Send + 'static, - B::Error: Into + Send + 'static, - { - type Response = http::Response; - type Error = std::convert::Infallible; - type Future = BoxFuture; - fn poll_ready( - &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { - Poll::Ready(Ok(())) - } - fn call(&mut self, req: http::Request) -> Self::Future { - let inner = self.inner.clone(); - match req.uri().path() { - _ => { - Box::pin(async move { - Ok( - http::Response::builder() - .status(200) - .header("grpc-status", "12") - .header("content-type", "application/grpc") - .body(empty_body()) - .unwrap(), - ) - }) - } - } - } - } - impl Clone for MsgServer { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - Self { - inner, - accept_compression_encodings: self.accept_compression_encodings, - send_compression_encodings: self.send_compression_encodings, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } - } - } - impl Clone for _Inner { - fn clone(&self) -> Self { - Self(Arc::clone(&self.0)) - } - } - impl std::fmt::Debug for _Inner { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } - impl tonic::server::NamedService for MsgServer { - const NAME: &'static str = "interchain_security.ccv.v1.Msg"; - } -} -/// Generated client implementations. -#[cfg(feature = "client")] -pub mod query_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - use tonic::codegen::http::Uri; - /// Query defines the gRPC querier service. - #[derive(Debug, Clone)] - pub struct QueryClient { - inner: tonic::client::Grpc, - } - impl QueryClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl QueryClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> QueryClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + Send + Sync, - { - QueryClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - } -} -/// Generated server implementations. -#[cfg(feature = "server")] -pub mod query_server { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with QueryServer. - #[async_trait] - pub trait Query: Send + Sync + 'static {} - /// Query defines the gRPC querier service. - #[derive(Debug)] - pub struct QueryServer { - inner: _Inner, - accept_compression_encodings: EnabledCompressionEncodings, - send_compression_encodings: EnabledCompressionEncodings, - max_decoding_message_size: Option, - max_encoding_message_size: Option, - } - struct _Inner(Arc); - impl QueryServer { - pub fn new(inner: T) -> Self { - Self::from_arc(Arc::new(inner)) - } - pub fn from_arc(inner: Arc) -> Self { - let inner = _Inner(inner); - Self { - inner, - accept_compression_encodings: Default::default(), - send_compression_encodings: Default::default(), - max_decoding_message_size: None, - max_encoding_message_size: None, - } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> InterceptedService - where - F: tonic::service::Interceptor, - { - InterceptedService::new(Self::new(inner), interceptor) - } - /// Enable decompressing requests with the given encoding. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.accept_compression_encodings.enable(encoding); - self - } - /// Compress responses with the given encoding, if the client supports it. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.send_compression_encodings.enable(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.max_decoding_message_size = Some(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.max_encoding_message_size = Some(limit); - self - } - } - impl tonic::codegen::Service> for QueryServer - where - T: Query, - B: Body + Send + 'static, - B::Error: Into + Send + 'static, - { - type Response = http::Response; - type Error = std::convert::Infallible; - type Future = BoxFuture; - fn poll_ready( - &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { - Poll::Ready(Ok(())) - } - fn call(&mut self, req: http::Request) -> Self::Future { - let inner = self.inner.clone(); - match req.uri().path() { - _ => { - Box::pin(async move { - Ok( - http::Response::builder() - .status(200) - .header("grpc-status", "12") - .header("content-type", "application/grpc") - .body(empty_body()) - .unwrap(), - ) - }) - } - } - } - } - impl Clone for QueryServer { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - Self { - inner, - accept_compression_encodings: self.accept_compression_encodings, - send_compression_encodings: self.send_compression_encodings, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } - } - } - impl Clone for _Inner { - fn clone(&self) -> Self { - Self(Arc::clone(&self.0)) - } - } - impl std::fmt::Debug for _Inner { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) - } - } - impl tonic::server::NamedService for QueryServer { - const NAME: &'static str = "interchain_security.ccv.v1.Query"; - } -} /// This packet is sent from provider chain to consumer chain if the validator /// set for consumer chain changes (due to new bonding/unbonding messages or /// slashing events) A VSCMatured packet from consumer chain will be sent diff --git a/src/prost/proto_descriptor.bin b/src/prost/proto_descriptor.bin index f15a7f83cd8645ed47c85a0929b6b8dfbd957050..cffb037e0d0a6139d28f3b662129d0fbe86aea86 100644 GIT binary patch delta 45823 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