From 188bdcc97be43a97c91c8452594cbeb53f1f5a66 Mon Sep 17 00:00:00 2001 From: Lucas Meier Date: Fri, 29 Mar 2024 11:26:48 -0700 Subject: [PATCH] Define FMD Meta Parameters BREAKING: sorta, this requires an upgrade to chain logic, but the protos are backwards compat, or they should be, unless I messed up --- crates/core/app/src/params/change.rs | 10 +- .../core/component/shielded-pool/src/fmd.rs | 43 ++++++ .../component/shielded-pool/src/params.rs | 10 +- ...enumbra.core.component.shielded_pool.v1.rs | 26 +++- ...a.core.component.shielded_pool.v1.serde.rs | 126 ++++++++++++++++-- .../proto/src/gen/proto_descriptor.bin.no_lfs | Bin 380322 -> 380660 bytes .../shielded_pool/v1/shielded_pool.proto | 10 +- 7 files changed, 197 insertions(+), 28 deletions(-) diff --git a/crates/core/app/src/params/change.rs b/crates/core/app/src/params/change.rs index 9f96c61478..b5b69fc5ff 100644 --- a/crates/core/app/src/params/change.rs +++ b/crates/core/app/src/params/change.rs @@ -55,10 +55,7 @@ impl AppParameters { outbound_ics20_transfers_enabled: _, }, sct_params: SctParameters { epoch_duration }, - shielded_pool_params: - ShieldedPoolParameters { - fixed_fmd_params: _, - }, + shielded_pool_params: ShieldedPoolParameters { fmd_meta_params: _ }, stake_params: StakeParameters { active_validator_limit, @@ -149,10 +146,7 @@ impl AppParameters { outbound_ics20_transfers_enabled, }, sct_params: SctParameters { epoch_duration }, - shielded_pool_params: - ShieldedPoolParameters { - fixed_fmd_params: _, - }, + shielded_pool_params: ShieldedPoolParameters { fmd_meta_params: _ }, stake_params: StakeParameters { active_validator_limit, diff --git a/crates/core/component/shielded-pool/src/fmd.rs b/crates/core/component/shielded-pool/src/fmd.rs index 3929bea813..7590df6e96 100644 --- a/crates/core/component/shielded-pool/src/fmd.rs +++ b/crates/core/component/shielded-pool/src/fmd.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use decaf377_fmd::Precision; use penumbra_proto::{core::component::shielded_pool::v1 as pb, DomainType}; use serde::{Deserialize, Serialize}; @@ -45,3 +46,45 @@ impl Default for Parameters { } } } + +/// Meta parameters are an algorithm for dynamically choosing FMD parameters. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[serde(try_from = "pb::FmdMetaParameters", into = "pb::FmdMetaParameters")] +pub enum MetaParameters { + /// Used a fixed precision forever. + Fixed(Precision), +} + +impl TryFrom for MetaParameters { + type Error = anyhow::Error; + + fn try_from(value: pb::FmdMetaParameters) -> Result { + match value.algorithm.ok_or(anyhow!("missing algorithm"))? { + pb::fmd_meta_parameters::Algorithm::FixedPrecisionBits(p) => { + Ok(MetaParameters::Fixed(Precision::new(p as u8)?)) + } + } + } +} + +impl From for pb::FmdMetaParameters { + fn from(value: MetaParameters) -> Self { + match value { + MetaParameters::Fixed(p) => pb::FmdMetaParameters { + algorithm: Some(pb::fmd_meta_parameters::Algorithm::FixedPrecisionBits( + p.bits().into(), + )), + }, + } + } +} + +impl DomainType for MetaParameters { + type Proto = pb::FmdMetaParameters; +} + +impl Default for MetaParameters { + fn default() -> Self { + Self::Fixed(Precision::default()) + } +} diff --git a/crates/core/component/shielded-pool/src/params.rs b/crates/core/component/shielded-pool/src/params.rs index 8c59d0c40c..7168b06573 100644 --- a/crates/core/component/shielded-pool/src/params.rs +++ b/crates/core/component/shielded-pool/src/params.rs @@ -11,7 +11,7 @@ use crate::fmd; into = "pb::ShieldedPoolParameters" )] pub struct ShieldedPoolParameters { - pub fixed_fmd_params: fmd::Parameters, + pub fmd_meta_params: fmd::MetaParameters, } impl DomainType for ShieldedPoolParameters { @@ -23,9 +23,9 @@ impl TryFrom for ShieldedPoolParameters { fn try_from(msg: pb::ShieldedPoolParameters) -> anyhow::Result { Ok(ShieldedPoolParameters { - fixed_fmd_params: msg - .fixed_fmd_params - .ok_or_else(|| anyhow::anyhow!("missing fmd_parameters"))? + fmd_meta_params: msg + .fmd_meta_params + .ok_or_else(|| anyhow::anyhow!("missing fmd_meta_params"))? .try_into()?, }) } @@ -34,7 +34,7 @@ impl TryFrom for ShieldedPoolParameters { impl From for pb::ShieldedPoolParameters { fn from(params: ShieldedPoolParameters) -> Self { pb::ShieldedPoolParameters { - fixed_fmd_params: Some(params.fixed_fmd_params.into()), + fmd_meta_params: Some(params.fmd_meta_params.into()), } } } diff --git a/crates/proto/src/gen/penumbra.core.component.shielded_pool.v1.rs b/crates/proto/src/gen/penumbra.core.component.shielded_pool.v1.rs index 3bcf1abb61..48688a23c5 100644 --- a/crates/proto/src/gen/penumbra.core.component.shielded_pool.v1.rs +++ b/crates/proto/src/gen/penumbra.core.component.shielded_pool.v1.rs @@ -3,7 +3,7 @@ #[derive(Clone, PartialEq, ::prost::Message)] pub struct ShieldedPoolParameters { #[prost(message, optional, tag = "1")] - pub fixed_fmd_params: ::core::option::Option, + pub fmd_meta_params: ::core::option::Option, } impl ::prost::Name for ShieldedPoolParameters { const NAME: &'static str = "ShieldedPoolParameters"; @@ -57,6 +57,30 @@ impl ::prost::Name for GenesisContent { ) } } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FmdMetaParameters { + #[prost(oneof = "fmd_meta_parameters::Algorithm", tags = "1")] + pub algorithm: ::core::option::Option, +} +/// Nested message and enum types in `FmdMetaParameters`. +pub mod fmd_meta_parameters { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Algorithm { + #[prost(uint32, tag = "1")] + FixedPrecisionBits(u32), + } +} +impl ::prost::Name for FmdMetaParameters { + const NAME: &'static str = "FmdMetaParameters"; + const PACKAGE: &'static str = "penumbra.core.component.shielded_pool.v1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!( + "penumbra.core.component.shielded_pool.v1.{}", Self::NAME + ) + } +} /// Parameters for Fuzzy Message Detection #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/crates/proto/src/gen/penumbra.core.component.shielded_pool.v1.serde.rs b/crates/proto/src/gen/penumbra.core.component.shielded_pool.v1.serde.rs index 04f1e6056c..4a99b003f5 100644 --- a/crates/proto/src/gen/penumbra.core.component.shielded_pool.v1.serde.rs +++ b/crates/proto/src/gen/penumbra.core.component.shielded_pool.v1.serde.rs @@ -381,6 +381,106 @@ impl<'de> serde::Deserialize<'de> for EventSpend { deserializer.deserialize_struct("penumbra.core.component.shielded_pool.v1.EventSpend", FIELDS, GeneratedVisitor) } } +impl serde::Serialize for FmdMetaParameters { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.algorithm.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("penumbra.core.component.shielded_pool.v1.FmdMetaParameters", len)?; + if let Some(v) = self.algorithm.as_ref() { + match v { + fmd_meta_parameters::Algorithm::FixedPrecisionBits(v) => { + struct_ser.serialize_field("fixedPrecisionBits", v)?; + } + } + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for FmdMetaParameters { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "fixed_precision_bits", + "fixedPrecisionBits", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + FixedPrecisionBits, + __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 { + "fixedPrecisionBits" | "fixed_precision_bits" => Ok(GeneratedField::FixedPrecisionBits), + _ => Ok(GeneratedField::__SkipField__), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = FmdMetaParameters; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct penumbra.core.component.shielded_pool.v1.FmdMetaParameters") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut algorithm__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::FixedPrecisionBits => { + if algorithm__.is_some() { + return Err(serde::de::Error::duplicate_field("fixedPrecisionBits")); + } + algorithm__ = map_.next_value::<::std::option::Option<::pbjson::private::NumberDeserialize<_>>>()?.map(|x| fmd_meta_parameters::Algorithm::FixedPrecisionBits(x.0)); + } + GeneratedField::__SkipField__ => { + let _ = map_.next_value::()?; + } + } + } + Ok(FmdMetaParameters { + algorithm: algorithm__, + }) + } + } + deserializer.deserialize_struct("penumbra.core.component.shielded_pool.v1.FmdMetaParameters", FIELDS, GeneratedVisitor) + } +} impl serde::Serialize for FmdParameters { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result @@ -2049,12 +2149,12 @@ impl serde::Serialize for ShieldedPoolParameters { { use serde::ser::SerializeStruct; let mut len = 0; - if self.fixed_fmd_params.is_some() { + if self.fmd_meta_params.is_some() { len += 1; } let mut struct_ser = serializer.serialize_struct("penumbra.core.component.shielded_pool.v1.ShieldedPoolParameters", len)?; - if let Some(v) = self.fixed_fmd_params.as_ref() { - struct_ser.serialize_field("fixedFmdParams", v)?; + if let Some(v) = self.fmd_meta_params.as_ref() { + struct_ser.serialize_field("fmdMetaParams", v)?; } struct_ser.end() } @@ -2066,13 +2166,13 @@ impl<'de> serde::Deserialize<'de> for ShieldedPoolParameters { D: serde::Deserializer<'de>, { const FIELDS: &[&str] = &[ - "fixed_fmd_params", - "fixedFmdParams", + "fmd_meta_params", + "fmdMetaParams", ]; #[allow(clippy::enum_variant_names)] enum GeneratedField { - FixedFmdParams, + FmdMetaParams, __SkipField__, } impl<'de> serde::Deserialize<'de> for GeneratedField { @@ -2095,7 +2195,7 @@ impl<'de> serde::Deserialize<'de> for ShieldedPoolParameters { E: serde::de::Error, { match value { - "fixedFmdParams" | "fixed_fmd_params" => Ok(GeneratedField::FixedFmdParams), + "fmdMetaParams" | "fmd_meta_params" => Ok(GeneratedField::FmdMetaParams), _ => Ok(GeneratedField::__SkipField__), } } @@ -2115,14 +2215,14 @@ impl<'de> serde::Deserialize<'de> for ShieldedPoolParameters { where V: serde::de::MapAccess<'de>, { - let mut fixed_fmd_params__ = None; + let mut fmd_meta_params__ = None; while let Some(k) = map_.next_key()? { match k { - GeneratedField::FixedFmdParams => { - if fixed_fmd_params__.is_some() { - return Err(serde::de::Error::duplicate_field("fixedFmdParams")); + GeneratedField::FmdMetaParams => { + if fmd_meta_params__.is_some() { + return Err(serde::de::Error::duplicate_field("fmdMetaParams")); } - fixed_fmd_params__ = map_.next_value()?; + fmd_meta_params__ = map_.next_value()?; } GeneratedField::__SkipField__ => { let _ = map_.next_value::()?; @@ -2130,7 +2230,7 @@ impl<'de> serde::Deserialize<'de> for ShieldedPoolParameters { } } Ok(ShieldedPoolParameters { - fixed_fmd_params: fixed_fmd_params__, + fmd_meta_params: fmd_meta_params__, }) } } diff --git a/crates/proto/src/gen/proto_descriptor.bin.no_lfs b/crates/proto/src/gen/proto_descriptor.bin.no_lfs index 8a26d29b046550f594d789bdc692d546f5431d8b..775a9fb4bf9bc485e46746025dc8868e659db58c 100644 GIT binary patch delta 4506 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 diff --git a/proto/penumbra/penumbra/core/component/shielded_pool/v1/shielded_pool.proto b/proto/penumbra/penumbra/core/component/shielded_pool/v1/shielded_pool.proto index 46555ca999..207c65aee3 100644 --- a/proto/penumbra/penumbra/core/component/shielded_pool/v1/shielded_pool.proto +++ b/proto/penumbra/penumbra/core/component/shielded_pool/v1/shielded_pool.proto @@ -10,7 +10,7 @@ import "penumbra/crypto/tct/v1/tct.proto"; // Configuration data for the shielded pool component. message ShieldedPoolParameters { - FmdParameters fixed_fmd_params = 1; + FmdMetaParameters fmd_meta_params = 1; } // Genesis data for the shielded pool component. @@ -26,6 +26,14 @@ message GenesisContent { repeated Allocation allocations = 3; } +message FmdMetaParameters { + // Because this used to be FmdParameters, which used as_of_block_height + reserved 2; + oneof algorithm { + uint32 fixed_precision_bits = 1; + } +} + // Parameters for Fuzzy Message Detection message FmdParameters { uint32 precision_bits = 1;