From 16f904e0f40a4aeb855a0b79f672eb38efa0decb Mon Sep 17 00:00:00 2001 From: Tal Derei <70081547+TalDerei@users.noreply.github.com> Date: Fri, 19 Apr 2024 16:59:21 -0700 Subject: [PATCH] auction: pd service rpc (#4233) ## Describe your changes Define minimal auction pd rpc service in the protos. ## Issue ticket number and link References https://github.com/penumbra-zone/penumbra/issues/4226 ## Checklist before requesting a review - [x] If this code contains consensus-breaking changes, I have added the "consensus-breaking" label. Otherwise, I declare my belief that there are not consensus-breaking changes, for the following reason: --- Cargo.lock | 1 + crates/core/component/auction/Cargo.toml | 1 + .../auction/src/component/auction_store.rs | 2 +- .../component/auction/src/component/rpc.rs | 50 +- ...enumbra.core.component.auction.v1alpha1.rs | 266 ++++++++++- ...a.core.component.auction.v1alpha1.serde.rs | 431 ++++++++++++++++++ .../proto/src/gen/proto_descriptor.bin.no_lfs | Bin 390628 -> 392453 bytes .../component/auction/v1alpha1/auction.proto | 39 +- 8 files changed, 781 insertions(+), 9 deletions(-) mode change 100644 => 100755 crates/core/component/auction/src/component/rpc.rs mode change 100644 => 100755 proto/penumbra/penumbra/core/component/auction/v1alpha1/auction.proto diff --git a/Cargo.lock b/Cargo.lock index 329f698219..d0a0f70c9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4772,6 +4772,7 @@ dependencies = [ "im", "metrics", "once_cell", + "pbjson-types", "penumbra-asset", "penumbra-dex", "penumbra-keys", diff --git a/crates/core/component/auction/Cargo.toml b/crates/core/component/auction/Cargo.toml index 165e1eb3da..8c5bf8eb87 100644 --- a/crates/core/component/auction/Cargo.toml +++ b/crates/core/component/auction/Cargo.toml @@ -77,6 +77,7 @@ tendermint = {workspace = true, default-features = true} tokio = {workspace = true, features = ["full", "tracing"], optional = true} tonic = {workspace = true, optional = true} tracing = {workspace = true} +pbjson-types = "0.6.0" [dev-dependencies] ed25519-consensus = {workspace = true} diff --git a/crates/core/component/auction/src/component/auction_store.rs b/crates/core/component/auction/src/component/auction_store.rs index 3c730d5c42..a0722d3d1d 100644 --- a/crates/core/component/auction/src/component/auction_store.rs +++ b/crates/core/component/auction/src/component/auction_store.rs @@ -1,11 +1,11 @@ use anyhow::Result; use async_trait::async_trait; use cnidarium::StateRead; +use pbjson_types::Any; use penumbra_proto::core::component::auction::v1alpha1 as pb; use penumbra_proto::DomainType; use penumbra_proto::Name; use penumbra_proto::StateReadProto; -use prost_types::Any; use crate::{ auction::{dutch::DutchAuction, id::AuctionId}, diff --git a/crates/core/component/auction/src/component/rpc.rs b/crates/core/component/auction/src/component/rpc.rs old mode 100644 new mode 100755 index 6b83abcca8..57c8a233cc --- a/crates/core/component/auction/src/component/rpc.rs +++ b/crates/core/component/auction/src/component/rpc.rs @@ -1,16 +1,23 @@ #![allow(unused)] // TODO: remove this when filling in the RPCs use penumbra_proto::{ - core::component::auction::v1alpha1::query_service_server::QueryService, DomainType, + core::component::auction::v1alpha1::{ + query_service_server::QueryService, AuctionStateByIdRequest, AuctionStateByIdResponse, + AuctionStateByIdsRequest, AuctionStateByIdsResponse, DutchAuctionState, + }, + DomainType, }; use async_stream::try_stream; -use cnidarium::Storage; use futures::{StreamExt, TryStreamExt}; +use penumbra_proto::Message; use std::pin::Pin; use tonic::Status; use tracing::instrument; +use super::AuctionStoreRead; +use cnidarium::Storage; + pub struct Server { storage: Storage, } @@ -22,4 +29,41 @@ impl Server { } #[tonic::async_trait] -impl QueryService for Server {} +impl QueryService for Server { + #[instrument(skip(self, request))] + async fn auction_state_by_id( + &self, + request: tonic::Request, + ) -> Result, Status> { + let state = self.storage.latest_snapshot(); + let request = request.into_inner(); + + let id = request + .id + .ok_or_else(|| Status::invalid_argument("missing auction id"))? + .try_into() + .map_err(|_| Status::invalid_argument("invalid auction id"))?; + + let auction_data = state + .get_raw_auction(id) + .await + .ok_or_else(|| tonic::Status::not_found("auction data not found for specified id"))?; + + Ok(tonic::Response::new(AuctionStateByIdResponse { + auction: Some(auction_data), + positions: Vec::new(), + })) + } + + type AuctionStateByIdsStream = Pin< + Box> + Send>, + >; + + #[instrument(skip(self, request))] + async fn auction_state_by_ids( + &self, + request: tonic::Request, + ) -> Result, Status> { + todo!() + } +} diff --git a/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.rs b/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.rs index 07b4f355ab..9cb11332f5 100644 --- a/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.rs +++ b/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.rs @@ -28,6 +28,82 @@ impl ::prost::Name for GenesisContent { ) } } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AuctionStateByIdRequest { + #[prost(message, optional, tag = "1")] + pub id: ::core::option::Option, +} +impl ::prost::Name for AuctionStateByIdRequest { + const NAME: &'static str = "AuctionStateByIdRequest"; + const PACKAGE: &'static str = "penumbra.core.component.auction.v1alpha1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!( + "penumbra.core.component.auction.v1alpha1.{}", Self::NAME + ) + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AuctionStateByIdResponse { + /// If present, the state of the auction. If not present, no such auction is known. + #[prost(message, optional, tag = "2")] + pub auction: ::core::option::Option<::pbjson_types::Any>, + /// The state of any DEX positions relevant to the returned auction. + /// + /// Could be empty, depending on the auction state. + #[prost(message, repeated, tag = "3")] + pub positions: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for AuctionStateByIdResponse { + const NAME: &'static str = "AuctionStateByIdResponse"; + const PACKAGE: &'static str = "penumbra.core.component.auction.v1alpha1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!( + "penumbra.core.component.auction.v1alpha1.{}", Self::NAME + ) + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AuctionStateByIdsRequest { + /// The auction IDs to request. Only known IDs will be returned in the response. + #[prost(message, repeated, tag = "1")] + pub id: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for AuctionStateByIdsRequest { + const NAME: &'static str = "AuctionStateByIdsRequest"; + const PACKAGE: &'static str = "penumbra.core.component.auction.v1alpha1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!( + "penumbra.core.component.auction.v1alpha1.{}", Self::NAME + ) + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AuctionStateByIdsResponse { + /// The auction ID of the returned auction. + #[prost(message, optional, tag = "1")] + pub id: ::core::option::Option, + /// The state of the returned auction. + #[prost(message, optional, tag = "2")] + pub auction: ::core::option::Option, + /// The state of any DEX positions relevant to the returned auction. + /// + /// Could be empty, depending on the auction state. + #[prost(message, repeated, tag = "3")] + pub positions: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for AuctionStateByIdsResponse { + const NAME: &'static str = "AuctionStateByIdsResponse"; + const PACKAGE: &'static str = "penumbra.core.component.auction.v1alpha1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!( + "penumbra.core.component.auction.v1alpha1.{}", Self::NAME + ) + } +} /// A unique identifier for an auction, obtained from hashing a domain separator /// along with the immutable part of an auction description. #[allow(clippy::derive_partial_eq_without_eq)] @@ -303,7 +379,7 @@ pub mod query_service_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] use tonic::codegen::*; use tonic::codegen::http::Uri; - /// Query operations for the Auction component. + /// Query operations for the auction component. #[derive(Debug, Clone)] pub struct QueryServiceClient { inner: tonic::client::Grpc, @@ -384,6 +460,68 @@ pub mod query_service_client { self.inner = self.inner.max_encoding_message_size(limit); self } + /// Get the current state of an auction by ID. + pub async fn auction_state_by_id( + &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( + "/penumbra.core.component.auction.v1alpha1.QueryService/AuctionStateById", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "penumbra.core.component.auction.v1alpha1.QueryService", + "AuctionStateById", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Get the current state of a group of auctions by ID. + pub async fn auction_state_by_ids( + &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( + "/penumbra.core.component.auction.v1alpha1.QueryService/AuctionStateByIds", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "penumbra.core.component.auction.v1alpha1.QueryService", + "AuctionStateByIds", + ), + ); + self.inner.server_streaming(req, path, codec).await + } } } /// Generated server implementations. @@ -393,8 +531,34 @@ pub mod query_service_server { use tonic::codegen::*; /// Generated trait containing gRPC methods that should be implemented for use with QueryServiceServer. #[async_trait] - pub trait QueryService: Send + Sync + 'static {} - /// Query operations for the Auction component. + pub trait QueryService: Send + Sync + 'static { + /// Get the current state of an auction by ID. + async fn auction_state_by_id( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Server streaming response type for the AuctionStateByIds method. + type AuctionStateByIdsStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result< + super::AuctionStateByIdsResponse, + tonic::Status, + >, + > + + Send + + 'static; + /// Get the current state of a group of auctions by ID. + async fn auction_state_by_ids( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + } + /// Query operations for the auction component. #[derive(Debug)] pub struct QueryServiceServer { inner: _Inner, @@ -474,6 +638,102 @@ pub mod query_service_server { fn call(&mut self, req: http::Request) -> Self::Future { let inner = self.inner.clone(); match req.uri().path() { + "/penumbra.core.component.auction.v1alpha1.QueryService/AuctionStateById" => { + #[allow(non_camel_case_types)] + struct AuctionStateByIdSvc(pub Arc); + impl< + T: QueryService, + > tonic::server::UnaryService + for AuctionStateByIdSvc { + type Response = super::AuctionStateByIdResponse; + 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 { + ::auction_state_by_id(&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 = AuctionStateByIdSvc(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) + } + "/penumbra.core.component.auction.v1alpha1.QueryService/AuctionStateByIds" => { + #[allow(non_camel_case_types)] + struct AuctionStateByIdsSvc(pub Arc); + impl< + T: QueryService, + > tonic::server::ServerStreamingService< + super::AuctionStateByIdsRequest, + > for AuctionStateByIdsSvc { + type Response = super::AuctionStateByIdsResponse; + type ResponseStream = T::AuctionStateByIdsStream; + 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 { + ::auction_state_by_ids(&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 = AuctionStateByIdsSvc(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.core.component.auction.v1alpha1.serde.rs b/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.serde.rs index ee693da763..7f8cd6a68f 100644 --- a/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.serde.rs +++ b/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.serde.rs @@ -1021,6 +1021,437 @@ impl<'de> serde::Deserialize<'de> for AuctionParameters { deserializer.deserialize_struct("penumbra.core.component.auction.v1alpha1.AuctionParameters", FIELDS, GeneratedVisitor) } } +impl serde::Serialize for AuctionStateByIdRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.id.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("penumbra.core.component.auction.v1alpha1.AuctionStateByIdRequest", len)?; + if let Some(v) = self.id.as_ref() { + struct_ser.serialize_field("id", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for AuctionStateByIdRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "id", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Id, + __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 { + "id" => Ok(GeneratedField::Id), + _ => Ok(GeneratedField::__SkipField__), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = AuctionStateByIdRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct penumbra.core.component.auction.v1alpha1.AuctionStateByIdRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut id__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Id => { + if id__.is_some() { + return Err(serde::de::Error::duplicate_field("id")); + } + id__ = map_.next_value()?; + } + GeneratedField::__SkipField__ => { + let _ = map_.next_value::()?; + } + } + } + Ok(AuctionStateByIdRequest { + id: id__, + }) + } + } + deserializer.deserialize_struct("penumbra.core.component.auction.v1alpha1.AuctionStateByIdRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for AuctionStateByIdResponse { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.auction.is_some() { + len += 1; + } + if !self.positions.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("penumbra.core.component.auction.v1alpha1.AuctionStateByIdResponse", len)?; + if let Some(v) = self.auction.as_ref() { + struct_ser.serialize_field("auction", v)?; + } + if !self.positions.is_empty() { + struct_ser.serialize_field("positions", &self.positions)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for AuctionStateByIdResponse { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "auction", + "positions", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Auction, + Positions, + __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 { + "auction" => Ok(GeneratedField::Auction), + "positions" => Ok(GeneratedField::Positions), + _ => Ok(GeneratedField::__SkipField__), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = AuctionStateByIdResponse; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct penumbra.core.component.auction.v1alpha1.AuctionStateByIdResponse") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut auction__ = None; + let mut positions__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Auction => { + if auction__.is_some() { + return Err(serde::de::Error::duplicate_field("auction")); + } + auction__ = map_.next_value()?; + } + GeneratedField::Positions => { + if positions__.is_some() { + return Err(serde::de::Error::duplicate_field("positions")); + } + positions__ = Some(map_.next_value()?); + } + GeneratedField::__SkipField__ => { + let _ = map_.next_value::()?; + } + } + } + Ok(AuctionStateByIdResponse { + auction: auction__, + positions: positions__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("penumbra.core.component.auction.v1alpha1.AuctionStateByIdResponse", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for AuctionStateByIdsRequest { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if !self.id.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("penumbra.core.component.auction.v1alpha1.AuctionStateByIdsRequest", len)?; + if !self.id.is_empty() { + struct_ser.serialize_field("id", &self.id)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for AuctionStateByIdsRequest { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "id", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Id, + __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 { + "id" => Ok(GeneratedField::Id), + _ => Ok(GeneratedField::__SkipField__), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = AuctionStateByIdsRequest; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct penumbra.core.component.auction.v1alpha1.AuctionStateByIdsRequest") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut id__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Id => { + if id__.is_some() { + return Err(serde::de::Error::duplicate_field("id")); + } + id__ = Some(map_.next_value()?); + } + GeneratedField::__SkipField__ => { + let _ = map_.next_value::()?; + } + } + } + Ok(AuctionStateByIdsRequest { + id: id__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("penumbra.core.component.auction.v1alpha1.AuctionStateByIdsRequest", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for AuctionStateByIdsResponse { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.id.is_some() { + len += 1; + } + if self.auction.is_some() { + len += 1; + } + if !self.positions.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("penumbra.core.component.auction.v1alpha1.AuctionStateByIdsResponse", len)?; + if let Some(v) = self.id.as_ref() { + struct_ser.serialize_field("id", v)?; + } + if let Some(v) = self.auction.as_ref() { + struct_ser.serialize_field("auction", v)?; + } + if !self.positions.is_empty() { + struct_ser.serialize_field("positions", &self.positions)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for AuctionStateByIdsResponse { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "id", + "auction", + "positions", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Id, + Auction, + Positions, + __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 { + "id" => Ok(GeneratedField::Id), + "auction" => Ok(GeneratedField::Auction), + "positions" => Ok(GeneratedField::Positions), + _ => Ok(GeneratedField::__SkipField__), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = AuctionStateByIdsResponse; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct penumbra.core.component.auction.v1alpha1.AuctionStateByIdsResponse") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut id__ = None; + let mut auction__ = None; + let mut positions__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Id => { + if id__.is_some() { + return Err(serde::de::Error::duplicate_field("id")); + } + id__ = map_.next_value()?; + } + GeneratedField::Auction => { + if auction__.is_some() { + return Err(serde::de::Error::duplicate_field("auction")); + } + auction__ = map_.next_value()?; + } + GeneratedField::Positions => { + if positions__.is_some() { + return Err(serde::de::Error::duplicate_field("positions")); + } + positions__ = Some(map_.next_value()?); + } + GeneratedField::__SkipField__ => { + let _ = map_.next_value::()?; + } + } + } + Ok(AuctionStateByIdsResponse { + id: id__, + auction: auction__, + positions: positions__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("penumbra.core.component.auction.v1alpha1.AuctionStateByIdsResponse", FIELDS, GeneratedVisitor) + } +} impl serde::Serialize for DutchAuction { #[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 f537de9326419611cb453f5eeba87c4dd15d3bd0..8abb21f0fea4d352b9315cefd37d1b781b46562c 100644 GIT binary patch delta 37162 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ⅆyL;tFJCyCJSXR<;`w<7028xA{?7#atX2yg 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 SaNs4!5A~alADX!D`Tqy?!mV8Z diff --git a/proto/penumbra/penumbra/core/component/auction/v1alpha1/auction.proto b/proto/penumbra/penumbra/core/component/auction/v1alpha1/auction.proto old mode 100644 new mode 100755 index ee6507f3ef..3e900af140 --- a/proto/penumbra/penumbra/core/component/auction/v1alpha1/auction.proto +++ b/proto/penumbra/penumbra/core/component/auction/v1alpha1/auction.proto @@ -4,6 +4,7 @@ package penumbra.core.component.auction.v1alpha1; import "penumbra/core/asset/v1/asset.proto"; import "penumbra/core/component/dex/v1/dex.proto"; import "penumbra/core/num/v1/num.proto"; +import "google/protobuf/any.proto"; // The configuration parameters for the auction component. message AuctionParameters {} @@ -14,8 +15,42 @@ message GenesisContent { AuctionParameters params = 1; } -// Query operations for the Auction component. -service QueryService {} +// Query operations for the auction component. +service QueryService { + // Get the current state of an auction by ID. + rpc AuctionStateById(AuctionStateByIdRequest) returns (AuctionStateByIdResponse); + // Get the current state of a group of auctions by ID. + rpc AuctionStateByIds(AuctionStateByIdsRequest) returns (stream AuctionStateByIdsResponse); +} + +message AuctionStateByIdRequest { + AuctionId id = 1; +} + +message AuctionStateByIdResponse { + // If present, the state of the auction. If not present, no such auction is known. + google.protobuf.Any auction = 2; + // The state of any DEX positions relevant to the returned auction. + // + // Could be empty, depending on the auction state. + repeated core.component.dex.v1.Position positions = 3; +} + +message AuctionStateByIdsRequest { + // The auction IDs to request. Only known IDs will be returned in the response. + repeated AuctionId id = 1; +} + +message AuctionStateByIdsResponse { + // The auction ID of the returned auction. + AuctionId id = 1; + // The state of the returned auction. + DutchAuctionState auction = 2; + // The state of any DEX positions relevant to the returned auction. + // + // Could be empty, depending on the auction state. + repeated core.component.dex.v1.Position positions = 3; +} // A unique identifier for an auction, obtained from hashing a domain separator // along with the immutable part of an auction description.