Skip to content

Commit

Permalink
add t-addr fetching to view service
Browse files Browse the repository at this point in the history
  • Loading branch information
hdevalence committed Dec 12, 2024
1 parent 9da6487 commit 621d982
Show file tree
Hide file tree
Showing 6 changed files with 330 additions and 0 deletions.
Binary file modified crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs
Binary file not shown.
112 changes: 112 additions & 0 deletions crates/proto/src/gen/penumbra.view.v1.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
/// There's only one transparent address per wallet, so this request has no parameters;
/// the message exists to satisfy forward-compatibility properties.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TransparentAddressRequest {}
impl ::prost::Name for TransparentAddressRequest {
const NAME: &'static str = "TransparentAddressRequest";
const PACKAGE: &'static str = "penumbra.view.v1";
fn full_name() -> ::prost::alloc::string::String {
::prost::alloc::format!("penumbra.view.v1.{}", Self::NAME)
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TransparentAddressResponse {
/// The raw (binary) transparent address
#[prost(message, optional, tag = "1")]
pub address: ::core::option::Option<super::super::core::keys::v1::Address>,
/// The t-address encoding of the transparent address
#[prost(string, tag = "2")]
pub encoding: ::prost::alloc::string::String,
}
impl ::prost::Name for TransparentAddressResponse {
const NAME: &'static str = "TransparentAddressResponse";
const PACKAGE: &'static str = "penumbra.view.v1";
fn full_name() -> ::prost::alloc::string::String {
::prost::alloc::format!("penumbra.view.v1.{}", Self::NAME)
}
}
/// Filters in an `AuctionsRequest` will be combined using `AND` logic -- that
/// is, the more filters you add, the fewer responses you're likely to get.
#[allow(clippy::derive_partial_eq_without_eq)]
Expand Down Expand Up @@ -2117,6 +2146,34 @@ pub mod view_service_client {
);
self.inner.unary(req, path, codec).await
}
/// Returns the transparent address for the user's wallet.
pub async fn transparent_address(
&mut self,
request: impl tonic::IntoRequest<super::TransparentAddressRequest>,
) -> std::result::Result<
tonic::Response<super::TransparentAddressResponse>,
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/TransparentAddress",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(
GrpcMethod::new("penumbra.view.v1.ViewService", "TransparentAddress"),
);
self.inner.unary(req, path, codec).await
}
/// Query for wallet id
pub async fn wallet_id(
&mut self,
Expand Down Expand Up @@ -2800,6 +2857,14 @@ pub mod view_service_server {
tonic::Response<super::AddressByIndexResponse>,
tonic::Status,
>;
/// Returns the transparent address for the user's wallet.
async fn transparent_address(
&self,
request: tonic::Request<super::TransparentAddressRequest>,
) -> std::result::Result<
tonic::Response<super::TransparentAddressResponse>,
tonic::Status,
>;
/// Query for wallet id
async fn wallet_id(
&self,
Expand Down Expand Up @@ -3596,6 +3661,53 @@ pub mod view_service_server {
};
Box::pin(fut)
}
"/penumbra.view.v1.ViewService/TransparentAddress" => {
#[allow(non_camel_case_types)]
struct TransparentAddressSvc<T: ViewService>(pub Arc<T>);
impl<
T: ViewService,
> tonic::server::UnaryService<super::TransparentAddressRequest>
for TransparentAddressSvc<T> {
type Response = super::TransparentAddressResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::TransparentAddressRequest>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as ViewService>::transparent_address(&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 = TransparentAddressSvc(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.view.v1.ViewService/WalletId" => {
#[allow(non_camel_case_types)]
struct WalletIdSvc<T: ViewService>(pub Arc<T>);
Expand Down
184 changes: 184 additions & 0 deletions crates/proto/src/gen/penumbra.view.v1.serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8305,6 +8305,190 @@ impl<'de> serde::Deserialize<'de> for TransactionPlannerResponse {
deserializer.deserialize_struct("penumbra.view.v1.TransactionPlannerResponse", FIELDS, GeneratedVisitor)
}
}
impl serde::Serialize for TransparentAddressRequest {
#[allow(deprecated)]
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStruct;
let len = 0;
let struct_ser = serializer.serialize_struct("penumbra.view.v1.TransparentAddressRequest", len)?;
struct_ser.end()
}
}
impl<'de> serde::Deserialize<'de> for TransparentAddressRequest {
#[allow(deprecated)]
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
const FIELDS: &[&str] = &[
];

#[allow(clippy::enum_variant_names)]
enum GeneratedField {
__SkipField__,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
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<E>(self, value: &str) -> std::result::Result<GeneratedField, E>
where
E: serde::de::Error,
{
Ok(GeneratedField::__SkipField__)
}
}
deserializer.deserialize_identifier(GeneratedVisitor)
}
}
struct GeneratedVisitor;
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
type Value = TransparentAddressRequest;

fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("struct penumbra.view.v1.TransparentAddressRequest")
}

fn visit_map<V>(self, mut map_: V) -> std::result::Result<TransparentAddressRequest, V::Error>
where
V: serde::de::MapAccess<'de>,
{
while map_.next_key::<GeneratedField>()?.is_some() {
let _ = map_.next_value::<serde::de::IgnoredAny>()?;
}
Ok(TransparentAddressRequest {
})
}
}
deserializer.deserialize_struct("penumbra.view.v1.TransparentAddressRequest", FIELDS, GeneratedVisitor)
}
}
impl serde::Serialize for TransparentAddressResponse {
#[allow(deprecated)]
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStruct;
let mut len = 0;
if self.address.is_some() {
len += 1;
}
if !self.encoding.is_empty() {
len += 1;
}
let mut struct_ser = serializer.serialize_struct("penumbra.view.v1.TransparentAddressResponse", len)?;
if let Some(v) = self.address.as_ref() {
struct_ser.serialize_field("address", v)?;
}
if !self.encoding.is_empty() {
struct_ser.serialize_field("encoding", &self.encoding)?;
}
struct_ser.end()
}
}
impl<'de> serde::Deserialize<'de> for TransparentAddressResponse {
#[allow(deprecated)]
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
const FIELDS: &[&str] = &[
"address",
"encoding",
];

#[allow(clippy::enum_variant_names)]
enum GeneratedField {
Address,
Encoding,
__SkipField__,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
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<E>(self, value: &str) -> std::result::Result<GeneratedField, E>
where
E: serde::de::Error,
{
match value {
"address" => Ok(GeneratedField::Address),
"encoding" => Ok(GeneratedField::Encoding),
_ => Ok(GeneratedField::__SkipField__),
}
}
}
deserializer.deserialize_identifier(GeneratedVisitor)
}
}
struct GeneratedVisitor;
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
type Value = TransparentAddressResponse;

fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("struct penumbra.view.v1.TransparentAddressResponse")
}

fn visit_map<V>(self, mut map_: V) -> std::result::Result<TransparentAddressResponse, V::Error>
where
V: serde::de::MapAccess<'de>,
{
let mut address__ = None;
let mut encoding__ = None;
while let Some(k) = map_.next_key()? {
match k {
GeneratedField::Address => {
if address__.is_some() {
return Err(serde::de::Error::duplicate_field("address"));
}
address__ = map_.next_value()?;
}
GeneratedField::Encoding => {
if encoding__.is_some() {
return Err(serde::de::Error::duplicate_field("encoding"));
}
encoding__ = Some(map_.next_value()?);
}
GeneratedField::__SkipField__ => {
let _ = map_.next_value::<serde::de::IgnoredAny>()?;
}
}
}
Ok(TransparentAddressResponse {
address: address__,
encoding: encoding__.unwrap_or_default(),
})
}
}
deserializer.deserialize_struct("penumbra.view.v1.TransparentAddressResponse", FIELDS, GeneratedVisitor)
}
}
impl serde::Serialize for UnbondingTokensByAddressIndexRequest {
#[allow(deprecated)]
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
Expand Down
Binary file modified crates/proto/src/gen/proto_descriptor.bin.no_lfs
Binary file not shown.
19 changes: 19 additions & 0 deletions crates/view/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,25 @@ impl ViewService for ViewServer {
address_index: fvk.address_index(&address).map(Into::into),
}))
}
async fn transparent_address(
&self,
_request: tonic::Request<pb::TransparentAddressRequest>,
) -> Result<tonic::Response<pb::TransparentAddressResponse>, tonic::Status> {
let fvk =
self.storage.full_viewing_key().await.map_err(|_| {
tonic::Status::failed_precondition("Error retrieving full viewing key")
})?;

let encoding = fvk.incoming().transparent_address();
let address: Address = encoding
.parse()
.map_err(|_| tonic::Status::internal("could not parse newly generated address"))?;

Ok(tonic::Response::new(pb::TransparentAddressResponse {
address: Some(address.into()),
encoding,
}))
}

#[instrument(skip_all, level = "trace")]
async fn ephemeral_address(
Expand Down
15 changes: 15 additions & 0 deletions proto/penumbra/penumbra/view/v1/view.proto
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ service ViewService {
// Query for an address given an address index
rpc AddressByIndex(AddressByIndexRequest) returns (AddressByIndexResponse);

// Returns the transparent address for the user's wallet.
rpc TransparentAddress(TransparentAddressRequest) returns (TransparentAddressResponse);

// Query for wallet id
rpc WalletId(WalletIdRequest) returns (WalletIdResponse);

Expand Down Expand Up @@ -148,6 +151,18 @@ service ViewService {
rpc Auctions(AuctionsRequest) returns (stream AuctionsResponse);
}

// There's only one transparent address per wallet, so this request has no parameters;
// the message exists to satisfy forward-compatibility properties.
message TransparentAddressRequest {
}

message TransparentAddressResponse {
// The raw (binary) transparent address
core.keys.v1.Address address = 1;
// The t-address encoding of the transparent address
string encoding = 2;
}

// Filters in an `AuctionsRequest` will be combined using `AND` logic -- that
// is, the more filters you add, the fewer responses you're likely to get.
message AuctionsRequest {
Expand Down

0 comments on commit 621d982

Please sign in to comment.