Skip to content

Commit

Permalink
Add ID filtering to AuctionsRequest; add local_seq to AuctionsResponse (
Browse files Browse the repository at this point in the history
#4472)

## Describe your changes

This PR makes two changes:
1. Add an `auction_ids_filter` to `AuctionsRequest`, so that clients can
make requests (e.g., with `queryLatestState`) for just specific auctions
rather than all auctions at once.
2. Add a `local_seq` property to `AuctionsResponse` to indicate the
local view service's own knowledge of the sequence number for an
auction. (See
#4385 (comment).)

Relevant changes are to the protobuf
[here](https://github.com/penumbra-zone/penumbra/pull/4472/files#diff-03b7341d5bf81ab9c8d8542d220d5ba4ae122bd3837531309742b685d7ec1619),
plus a couple TODO items
[here](https://github.com/penumbra-zone/penumbra/pull/4472/files#diff-9f4ca4cefeac93c9275a2f9d962d6670f6ab1c1381fd3d7c806f9316e3779ccbR986)
and
[here](https://github.com/penumbra-zone/penumbra/pull/4472/files#diff-36188e6ab5083e8be9d29039370cc523cfcfede683b223327b2d90e3f75d40c7R461).

## Issue ticket number and link
penumbra-zone/web#1059 and
#4385 (comment)

## 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:

  > Only touches Auctions RPC methods.
  • Loading branch information
jessepinho authored May 24, 2024
1 parent e49f1aa commit fcb50c2
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 24 deletions.
Binary file modified crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs
Binary file not shown.
24 changes: 21 additions & 3 deletions crates/proto/src/gen/penumbra.view.v1.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// 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)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AuctionsRequest {
Expand All @@ -12,6 +14,11 @@ pub struct AuctionsRequest {
/// If set, query a fullnode for the current state of the auctions.
#[prost(bool, tag = "3")]
pub query_latest_state: bool,
/// If present, filter to only include auctions whose IDs are in this array.
#[prost(message, repeated, tag = "4")]
pub auction_ids_filter: ::prost::alloc::vec::Vec<
super::super::core::component::auction::v1::AuctionId,
>,
}
impl ::prost::Name for AuctionsRequest {
const NAME: &'static str = "AuctionsRequest";
Expand All @@ -27,9 +34,6 @@ pub struct AuctionsResponse {
pub id: ::core::option::Option<
super::super::core::component::auction::v1::AuctionId,
>,
/// The note recording the auction NFT.
#[prost(message, optional, tag = "4")]
pub note_record: ::core::option::Option<SpendableNoteRecord>,
/// The state of the returned auction.
///
/// Only present when `query_latest_state` was provided.
Expand All @@ -43,6 +47,20 @@ pub struct AuctionsResponse {
pub positions: ::prost::alloc::vec::Vec<
super::super::core::component::dex::v1::Position,
>,
/// The note recording the auction NFT.
#[prost(message, optional, tag = "4")]
pub note_record: ::core::option::Option<SpendableNoteRecord>,
/// The sequence number of the auction state *as known to the local view
/// service*. Note that the local view service may lag behind the fullnode. For
/// example, if the chain hits an auction's `end_height`, but the user hasn't
/// yet exchanged their sequence-0 (opened) auction NFT for a sequence-1
/// (closed) auction NFT, the local view service will have a sequnce number of
/// 0.
///
/// Dutch auctions move from:
/// 0 (opened) => 1 (closed) => n (withdrawn)
#[prost(uint64, tag = "5")]
pub local_seq: u64,
}
impl ::prost::Name for AuctionsResponse {
const NAME: &'static str = "AuctionsResponse";
Expand Down
75 changes: 57 additions & 18 deletions crates/proto/src/gen/penumbra.view.v1.serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,9 @@ impl serde::Serialize for AuctionsRequest {
if self.query_latest_state {
len += 1;
}
if !self.auction_ids_filter.is_empty() {
len += 1;
}
let mut struct_ser = serializer.serialize_struct("penumbra.view.v1.AuctionsRequest", len)?;
if let Some(v) = self.account_filter.as_ref() {
struct_ser.serialize_field("accountFilter", v)?;
Expand All @@ -874,6 +877,9 @@ impl serde::Serialize for AuctionsRequest {
if self.query_latest_state {
struct_ser.serialize_field("queryLatestState", &self.query_latest_state)?;
}
if !self.auction_ids_filter.is_empty() {
struct_ser.serialize_field("auctionIdsFilter", &self.auction_ids_filter)?;
}
struct_ser.end()
}
}
Expand All @@ -890,13 +896,16 @@ impl<'de> serde::Deserialize<'de> for AuctionsRequest {
"includeInactive",
"query_latest_state",
"queryLatestState",
"auction_ids_filter",
"auctionIdsFilter",
];

#[allow(clippy::enum_variant_names)]
enum GeneratedField {
AccountFilter,
IncludeInactive,
QueryLatestState,
AuctionIdsFilter,
__SkipField__,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
Expand All @@ -922,6 +931,7 @@ impl<'de> serde::Deserialize<'de> for AuctionsRequest {
"accountFilter" | "account_filter" => Ok(GeneratedField::AccountFilter),
"includeInactive" | "include_inactive" => Ok(GeneratedField::IncludeInactive),
"queryLatestState" | "query_latest_state" => Ok(GeneratedField::QueryLatestState),
"auctionIdsFilter" | "auction_ids_filter" => Ok(GeneratedField::AuctionIdsFilter),
_ => Ok(GeneratedField::__SkipField__),
}
}
Expand All @@ -944,6 +954,7 @@ impl<'de> serde::Deserialize<'de> for AuctionsRequest {
let mut account_filter__ = None;
let mut include_inactive__ = None;
let mut query_latest_state__ = None;
let mut auction_ids_filter__ = None;
while let Some(k) = map_.next_key()? {
match k {
GeneratedField::AccountFilter => {
Expand All @@ -964,6 +975,12 @@ impl<'de> serde::Deserialize<'de> for AuctionsRequest {
}
query_latest_state__ = Some(map_.next_value()?);
}
GeneratedField::AuctionIdsFilter => {
if auction_ids_filter__.is_some() {
return Err(serde::de::Error::duplicate_field("auctionIdsFilter"));
}
auction_ids_filter__ = Some(map_.next_value()?);
}
GeneratedField::__SkipField__ => {
let _ = map_.next_value::<serde::de::IgnoredAny>()?;
}
Expand All @@ -973,6 +990,7 @@ impl<'de> serde::Deserialize<'de> for AuctionsRequest {
account_filter: account_filter__,
include_inactive: include_inactive__.unwrap_or_default(),
query_latest_state: query_latest_state__.unwrap_or_default(),
auction_ids_filter: auction_ids_filter__.unwrap_or_default(),
})
}
}
Expand All @@ -990,28 +1008,35 @@ impl serde::Serialize for AuctionsResponse {
if self.id.is_some() {
len += 1;
}
if self.note_record.is_some() {
len += 1;
}
if self.auction.is_some() {
len += 1;
}
if !self.positions.is_empty() {
len += 1;
}
if self.note_record.is_some() {
len += 1;
}
if self.local_seq != 0 {
len += 1;
}
let mut struct_ser = serializer.serialize_struct("penumbra.view.v1.AuctionsResponse", len)?;
if let Some(v) = self.id.as_ref() {
struct_ser.serialize_field("id", v)?;
}
if let Some(v) = self.note_record.as_ref() {
struct_ser.serialize_field("noteRecord", 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)?;
}
if let Some(v) = self.note_record.as_ref() {
struct_ser.serialize_field("noteRecord", v)?;
}
if self.local_seq != 0 {
#[allow(clippy::needless_borrow)]
struct_ser.serialize_field("localSeq", ToString::to_string(&self.local_seq).as_str())?;
}
struct_ser.end()
}
}
Expand All @@ -1023,18 +1048,21 @@ impl<'de> serde::Deserialize<'de> for AuctionsResponse {
{
const FIELDS: &[&str] = &[
"id",
"note_record",
"noteRecord",
"auction",
"positions",
"note_record",
"noteRecord",
"local_seq",
"localSeq",
];

#[allow(clippy::enum_variant_names)]
enum GeneratedField {
Id,
NoteRecord,
Auction,
Positions,
NoteRecord,
LocalSeq,
__SkipField__,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
Expand All @@ -1058,9 +1086,10 @@ impl<'de> serde::Deserialize<'de> for AuctionsResponse {
{
match value {
"id" => Ok(GeneratedField::Id),
"noteRecord" | "note_record" => Ok(GeneratedField::NoteRecord),
"auction" => Ok(GeneratedField::Auction),
"positions" => Ok(GeneratedField::Positions),
"noteRecord" | "note_record" => Ok(GeneratedField::NoteRecord),
"localSeq" | "local_seq" => Ok(GeneratedField::LocalSeq),
_ => Ok(GeneratedField::__SkipField__),
}
}
Expand All @@ -1081,9 +1110,10 @@ impl<'de> serde::Deserialize<'de> for AuctionsResponse {
V: serde::de::MapAccess<'de>,
{
let mut id__ = None;
let mut note_record__ = None;
let mut auction__ = None;
let mut positions__ = None;
let mut note_record__ = None;
let mut local_seq__ = None;
while let Some(k) = map_.next_key()? {
match k {
GeneratedField::Id => {
Expand All @@ -1092,12 +1122,6 @@ impl<'de> serde::Deserialize<'de> for AuctionsResponse {
}
id__ = map_.next_value()?;
}
GeneratedField::NoteRecord => {
if note_record__.is_some() {
return Err(serde::de::Error::duplicate_field("noteRecord"));
}
note_record__ = map_.next_value()?;
}
GeneratedField::Auction => {
if auction__.is_some() {
return Err(serde::de::Error::duplicate_field("auction"));
Expand All @@ -1110,16 +1134,31 @@ impl<'de> serde::Deserialize<'de> for AuctionsResponse {
}
positions__ = Some(map_.next_value()?);
}
GeneratedField::NoteRecord => {
if note_record__.is_some() {
return Err(serde::de::Error::duplicate_field("noteRecord"));
}
note_record__ = map_.next_value()?;
}
GeneratedField::LocalSeq => {
if local_seq__.is_some() {
return Err(serde::de::Error::duplicate_field("localSeq"));
}
local_seq__ =
Some(map_.next_value::<::pbjson::private::NumberDeserialize<_>>()?.0)
;
}
GeneratedField::__SkipField__ => {
let _ = map_.next_value::<serde::de::IgnoredAny>()?;
}
}
}
Ok(AuctionsResponse {
id: id__,
note_record: note_record__,
auction: auction__,
positions: positions__.unwrap_or_default(),
note_record: note_record__,
local_seq: local_seq__.unwrap_or_default(),
})
}
}
Expand Down
Binary file modified crates/proto/src/gen/proto_descriptor.bin.no_lfs
Binary file not shown.
1 change: 1 addition & 0 deletions crates/view/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,7 @@ where
account_filter: account_filter.map(Into::into),
include_inactive,
query_latest_state,
auction_ids_filter: Vec::new(), // TODO: Support `auction_ids_filter`
});

let auctions: Vec<pb::AuctionsResponse> =
Expand Down
1 change: 1 addition & 0 deletions crates/view/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ impl ViewService for ViewServer {
note_record: Some(note_record.into()),
auction: any_state,
positions,
local_seq: 0, // TODO: implement with real values
})
}
}))
Expand Down
19 changes: 16 additions & 3 deletions proto/penumbra/penumbra/view/v1/view.proto
Original file line number Diff line number Diff line change
Expand Up @@ -147,20 +147,21 @@ service ViewService {
rpc Auctions(AuctionsRequest) returns (stream AuctionsResponse);
}

// 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 {
// If present, filter balances to only include the account specified by the `AddressIndex`.
core.keys.v1.AddressIndex account_filter = 1;
// If present, include inactive auctions as well as active ones.
bool include_inactive = 2;
// If set, query a fullnode for the current state of the auctions.
bool query_latest_state = 3;
// If present, filter to only include auctions whose IDs are in this array.
repeated core.component.auction.v1.AuctionId auction_ids_filter = 4;
}

message AuctionsResponse {
core.component.auction.v1.AuctionId id = 1;
// The note recording the auction NFT.
SpendableNoteRecord note_record = 4;

// The state of the returned auction.
//
// Only present when `query_latest_state` was provided.
Expand All @@ -170,6 +171,18 @@ message AuctionsResponse {
// Only present when `query_latest_state` was provided.
// Could be empty, depending on the auction state.
repeated core.component.dex.v1.Position positions = 3;
// The note recording the auction NFT.
SpendableNoteRecord note_record = 4;
// The sequence number of the auction state _as known to the local view
// service_. Note that the local view service may lag behind the fullnode. For
// example, if the chain hits an auction's `end_height`, but the user hasn't
// yet exchanged their sequence-0 (opened) auction NFT for a sequence-1
// (closed) auction NFT, the local view service will have a sequnce number of
// 0.
//
// Dutch auctions move from:
// 0 (opened) => 1 (closed) => n (withdrawn)
uint64 local_seq = 5;
}

message AuthorizeAndBuildRequest {
Expand Down

0 comments on commit fcb50c2

Please sign in to comment.