diff --git a/crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs b/crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs index aea1e9b9c1..67d781308d 100644 Binary files a/crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs and b/crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs differ diff --git a/crates/proto/src/gen/penumbra.view.v1.rs b/crates/proto/src/gen/penumbra.view.v1.rs index 4c385be3f3..abe7ec260d 100644 --- a/crates/proto/src/gen/penumbra.view.v1.rs +++ b/crates/proto/src/gen/penumbra.view.v1.rs @@ -1352,6 +1352,97 @@ impl ::prost::Name for AssetMetadataByIdResponse { ::prost::alloc::format!("penumbra.view.v1.{}", Self::NAME) } } +/// Requests `ValueView`s of delegation tokens for the given address index. The +/// returned `ValueView`s will include the `ValidatorInfo` for the delegated +/// validator in their `extended_metadata` fields. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DelegationsByAddressIndexRequest { + /// The address index to fetch delegation balances for. + #[prost(message, optional, tag = "1")] + pub address_index: ::core::option::Option< + super::super::core::keys::v1::AddressIndex, + >, + #[prost(enumeration = "delegations_by_address_index_request::Filter", tag = "2")] + pub filter: i32, +} +/// Nested message and enum types in `DelegationsByAddressIndexRequest`. +pub mod delegations_by_address_index_request { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Filter { + /// Return delegations for all active validators. For validators that the + /// given address index has no delegation tokens for, a `ValueView` with a + /// balance of `0` will be returned. + AllActive = 0, + /// Like `ALL_ACTIVE`, but excludes validators that the given address index + /// holds no delegation tokens for. + AllActiveWithNonzeroBalances = 1, + /// Return delegations for all validators, whether active or not. For + /// validators that the given address index has no delegation tokens for, a + /// `ValueView` with a balance of `0` will be returned. + All = 2, + } + impl Filter { + /// 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 { + Filter::AllActive => "ALL_ACTIVE", + Filter::AllActiveWithNonzeroBalances => { + "ALL_ACTIVE_WITH_NONZERO_BALANCES" + } + Filter::All => "ALL", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "ALL_ACTIVE" => Some(Self::AllActive), + "ALL_ACTIVE_WITH_NONZERO_BALANCES" => { + Some(Self::AllActiveWithNonzeroBalances) + } + "ALL" => Some(Self::All), + _ => None, + } + } + } +} +impl ::prost::Name for DelegationsByAddressIndexRequest { + const NAME: &'static str = "DelegationsByAddressIndexRequest"; + const PACKAGE: &'static str = "penumbra.view.v1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!("penumbra.view.v1.{}", Self::NAME) + } +} +/// Contains a `ValueView` of delegation tokens for the requested address index. +/// The `ValueView` includes the `ValidatorInfo` for the delegated validator in +/// cits `extended_metadata` field. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DelegationsByAddressIndexResponse { + #[prost(message, optional, tag = "1")] + pub value_view: ::core::option::Option, +} +impl ::prost::Name for DelegationsByAddressIndexResponse { + const NAME: &'static str = "DelegationsByAddressIndexResponse"; + const PACKAGE: &'static str = "penumbra.view.v1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!("penumbra.view.v1.{}", Self::NAME) + } +} /// Generated client implementations. #[cfg(feature = "rpc")] pub mod view_service_client { @@ -2191,6 +2282,39 @@ pub mod view_service_client { ); self.inner.server_streaming(req, path, codec).await } + /// Get delegation tokens for a given address index. + pub async fn delegations_by_address_index( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response< + tonic::codec::Streaming, + >, + 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( + "/penumbra.view.v1.ViewService/DelegationsByAddressIndex", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "penumbra.view.v1.ViewService", + "DelegationsByAddressIndex", + ), + ); + self.inner.server_streaming(req, path, codec).await + } } } /// Generated server implementations. @@ -2501,6 +2625,23 @@ pub mod view_service_server { tonic::Response, tonic::Status, >; + /// Server streaming response type for the DelegationsByAddressIndex method. + type DelegationsByAddressIndexStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result< + super::DelegationsByAddressIndexResponse, + tonic::Status, + >, + > + + Send + + 'static; + /// Get delegation tokens for a given address index. + async fn delegations_by_address_index( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } /// The view RPC is used by a view client, who wants to do some /// transaction-related actions, to request data from a view service, which is @@ -3808,6 +3949,60 @@ pub mod view_service_server { }; Box::pin(fut) } + "/penumbra.view.v1.ViewService/DelegationsByAddressIndex" => { + #[allow(non_camel_case_types)] + struct DelegationsByAddressIndexSvc(pub Arc); + impl< + T: ViewService, + > tonic::server::ServerStreamingService< + super::DelegationsByAddressIndexRequest, + > for DelegationsByAddressIndexSvc { + type Response = super::DelegationsByAddressIndexResponse; + type ResponseStream = T::DelegationsByAddressIndexStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::DelegationsByAddressIndexRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::delegations_by_address_index( + &inner, + 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 = DelegationsByAddressIndexSvc(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.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/crates/proto/src/gen/penumbra.view.v1.serde.rs b/crates/proto/src/gen/penumbra.view.v1.serde.rs index c5deca7293..4da3884093 100644 --- a/crates/proto/src/gen/penumbra.view.v1.serde.rs +++ b/crates/proto/src/gen/penumbra.view.v1.serde.rs @@ -1949,6 +1949,291 @@ impl<'de> serde::Deserialize<'de> for broadcast_transaction_response::Confirmed deserializer.deserialize_struct("penumbra.view.v1.BroadcastTransactionResponse.Confirmed", FIELDS, GeneratedVisitor) } } +impl serde::Serialize for DelegationsByAddressIndexRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.address_index.is_some() { + len += 1; + } + if self.filter != 0 { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("penumbra.view.v1.DelegationsByAddressIndexRequest", len)?; + if let Some(v) = self.address_index.as_ref() { + struct_ser.serialize_field("addressIndex", v)?; + } + if self.filter != 0 { + let v = delegations_by_address_index_request::Filter::try_from(self.filter) + .map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", self.filter)))?; + struct_ser.serialize_field("filter", &v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for DelegationsByAddressIndexRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "address_index", + "addressIndex", + "filter", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + AddressIndex, + Filter, + __SkipField__, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "addressIndex" | "address_index" => Ok(GeneratedField::AddressIndex), + "filter" => Ok(GeneratedField::Filter), + _ => Ok(GeneratedField::__SkipField__), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = DelegationsByAddressIndexRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct penumbra.view.v1.DelegationsByAddressIndexRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut address_index__ = None; + let mut filter__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::AddressIndex => { + if address_index__.is_some() { + return Err(serde::de::Error::duplicate_field("addressIndex")); + } + address_index__ = map_.next_value()?; + } + GeneratedField::Filter => { + if filter__.is_some() { + return Err(serde::de::Error::duplicate_field("filter")); + } + filter__ = Some(map_.next_value::()? as i32); + } + GeneratedField::__SkipField__ => { + let _ = map_.next_value::()?; + } + } + } + Ok(DelegationsByAddressIndexRequest { + address_index: address_index__, + filter: filter__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("penumbra.view.v1.DelegationsByAddressIndexRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for delegations_by_address_index_request::Filter { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let variant = match self { + Self::AllActive => "ALL_ACTIVE", + Self::AllActiveWithNonzeroBalances => "ALL_ACTIVE_WITH_NONZERO_BALANCES", + Self::All => "ALL", + }; + serializer.serialize_str(variant) + } +} +impl<'de> serde::Deserialize<'de> for delegations_by_address_index_request::Filter { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "ALL_ACTIVE", + "ALL_ACTIVE_WITH_NONZERO_BALANCES", + "ALL", + ]; + + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = delegations_by_address_index_request::Filter; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + fn visit_i64(self, v: i64) -> std::result::Result + where + E: serde::de::Error, + { + i32::try_from(v) + .ok() + .and_then(|x| x.try_into().ok()) + .ok_or_else(|| { + serde::de::Error::invalid_value(serde::de::Unexpected::Signed(v), &self) + }) + } + + fn visit_u64(self, v: u64) -> std::result::Result + where + E: serde::de::Error, + { + i32::try_from(v) + .ok() + .and_then(|x| x.try_into().ok()) + .ok_or_else(|| { + serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(v), &self) + }) + } + + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "ALL_ACTIVE" => Ok(delegations_by_address_index_request::Filter::AllActive), + "ALL_ACTIVE_WITH_NONZERO_BALANCES" => Ok(delegations_by_address_index_request::Filter::AllActiveWithNonzeroBalances), + "ALL" => Ok(delegations_by_address_index_request::Filter::All), + _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), + } + } + } + deserializer.deserialize_any(GeneratedVisitor) + } +} +impl serde::Serialize for DelegationsByAddressIndexResponse { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.value_view.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("penumbra.view.v1.DelegationsByAddressIndexResponse", len)?; + if let Some(v) = self.value_view.as_ref() { + struct_ser.serialize_field("valueView", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for DelegationsByAddressIndexResponse { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "value_view", + "valueView", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + ValueView, + __SkipField__, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "valueView" | "value_view" => Ok(GeneratedField::ValueView), + _ => Ok(GeneratedField::__SkipField__), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = DelegationsByAddressIndexResponse; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct penumbra.view.v1.DelegationsByAddressIndexResponse") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut value_view__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::ValueView => { + if value_view__.is_some() { + return Err(serde::de::Error::duplicate_field("valueView")); + } + value_view__ = map_.next_value()?; + } + GeneratedField::__SkipField__ => { + let _ = map_.next_value::()?; + } + } + } + Ok(DelegationsByAddressIndexResponse { + value_view: value_view__, + }) + } + } + deserializer.deserialize_struct("penumbra.view.v1.DelegationsByAddressIndexResponse", FIELDS, GeneratedVisitor) + } +} impl serde::Serialize for EphemeralAddressRequest { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result diff --git a/crates/proto/src/gen/proto_descriptor.bin.no_lfs b/crates/proto/src/gen/proto_descriptor.bin.no_lfs index f0c25300d2..8436bcaea0 100644 Binary files a/crates/proto/src/gen/proto_descriptor.bin.no_lfs and b/crates/proto/src/gen/proto_descriptor.bin.no_lfs differ