Skip to content

Commit

Permalink
Make the FMD parameter grace period a parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
cronokirby committed May 9, 2024
1 parent cfd3a35 commit 6a2e04f
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 40 deletions.
15 changes: 10 additions & 5 deletions crates/core/app/src/action_handler/transaction/stateful.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ use penumbra_transaction::{Transaction, TransactionParameters};

use crate::app::StateReadExt;

const FMD_GRACE_PERIOD_BLOCKS: u64 = 10;

pub async fn tx_parameters_historical_check<S: StateRead>(
state: S,
transaction: &Transaction,
Expand Down Expand Up @@ -73,6 +71,11 @@ pub async fn expiry_height_is_valid<S: StateRead>(state: S, expiry_height: u64)
}

pub async fn fmd_parameters_valid<S: StateRead>(state: S, transaction: &Transaction) -> Result<()> {
let meta_params = state
.get_shielded_pool_params()
.await
.expect("chain params request must succeed")
.fmd_meta_params;
let previous_fmd_parameters = state
.get_previous_fmd_parameters()
.await
Expand All @@ -84,6 +87,7 @@ pub async fn fmd_parameters_valid<S: StateRead>(state: S, transaction: &Transact
let height = state.get_block_height().await?;
fmd_precision_within_grace_period(
transaction,
meta_params,
previous_fmd_parameters,
current_fmd_parameters,
height,
Expand All @@ -101,6 +105,7 @@ pub async fn fmd_parameters_valid<S: StateRead>(state: S, transaction: &Transact
)]
pub fn fmd_precision_within_grace_period(
tx: &Transaction,
meta_params: fmd::MetaParameters,
previous_fmd_parameters: fmd::Parameters,
current_fmd_parameters: fmd::Parameters,
block_height: u64,
Expand All @@ -112,12 +117,12 @@ pub fn fmd_precision_within_grace_period(
.fmd_clues
{
// Clue must be using the current `fmd::Parameters`, or be within
// `FMD_GRACE_PERIOD_BLOCKS` of the previous `fmd::Parameters`.
// `fmd_grace_period_blocks` of the previous `fmd::Parameters`.
let clue_precision = clue.precision()?;
let using_current_precision = clue_precision == current_fmd_parameters.precision;
let using_previous_precision = clue_precision == previous_fmd_parameters.precision;
let within_grace_period =
block_height < previous_fmd_parameters.as_of_block_height + FMD_GRACE_PERIOD_BLOCKS;
let within_grace_period = block_height
< previous_fmd_parameters.as_of_block_height + meta_params.fmd_grace_period_blocks;
if using_current_precision || (using_previous_precision && within_grace_period) {
continue;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use {
self::common::BuilderExt,
anyhow::anyhow,
cnidarium::TempStorage,
decaf377_fmd::Precision,
penumbra_app::{
genesis::{self, AppState},
server::consensus::Consensus,
},
decaf377_fmd::Precision,
penumbra_keys::test_keys,
penumbra_mock_client::MockClient,
penumbra_mock_consensus::TestNode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ impl Component for ShieldedPool {
.height
.try_into()
.expect("height should not be negative");
if should_update_fmd_params(height) {
let state = Arc::get_mut(state).expect("the state should not be shared");
let meta_params = state
.get_shielded_pool_params()
.await
.expect("should be able to read state")
.fmd_meta_params;
let state = Arc::get_mut(state).expect("the state should not be shared");
let meta_params = state
.get_shielded_pool_params()
.await
.expect("should be able to read state")
.fmd_meta_params;
if should_update_fmd_params(meta_params.fmd_grace_period_blocks, height) {
let old = state
.get_current_fmd_parameters()
.await
Expand Down
65 changes: 41 additions & 24 deletions crates/core/component/shielded-pool/src/fmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ use serde::{Deserialize, Serialize};
pub mod state_key;

/// How long users have to switch to updated parameters.
pub const FMD_GRACE_PERIOD_BLOCKS: u64 = 1 << 4;
/// How often we update the params.
pub const FMD_UPDATE_FREQUENCY_BLOCKS: u64 = 1 << 6;
/// How many blocks we expect per day, approximately.
const _BLOCKS_PER_DAY: u64 = 1 << 13;

pub fn should_update_fmd_params(height: u64) -> bool {
height % FMD_UPDATE_FREQUENCY_BLOCKS == 0
pub const FMD_GRACE_PERIOD_BLOCKS_DEFAULT: u64 = 1 << 4;
/// How often we update the params, in terms of the number of grace periods
pub const FMD_UPDATE_FREQUENCY_GRACE_PERIOD: u64 = 4;

pub fn should_update_fmd_params(fmd_grace_period_blocks: u64, height: u64) -> bool {
height % (fmd_grace_period_blocks * FMD_UPDATE_FREQUENCY_GRACE_PERIOD) == 0
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
Expand Down Expand Up @@ -61,34 +59,50 @@ 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 {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MetaParametersAlgorithm {
/// Used a fixed precision forever.
Fixed(Precision),
}

/// Meta paramaters governing how FMD parameters change.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(try_from = "pb::FmdMetaParameters", into = "pb::FmdMetaParameters")]
pub struct MetaParameters {
pub fmd_grace_period_blocks: u64,
pub algorithm: MetaParametersAlgorithm,
}

impl TryFrom<pb::FmdMetaParameters> for MetaParameters {
type Error = anyhow::Error;

fn try_from(value: pb::FmdMetaParameters) -> Result<Self> {
match value.algorithm.ok_or(anyhow!("missing algorithm"))? {
let fmd_grace_period_blocks = value.fmd_grace_period_blocks;
let algorithm = match value
.algorithm
.ok_or(anyhow!("FmdMetaParameters missing algorithm"))?
{
pb::fmd_meta_parameters::Algorithm::FixedPrecisionBits(p) => {
Ok(MetaParameters::Fixed(Precision::new(p as u8)?))
MetaParametersAlgorithm::Fixed(Precision::new(p as u8)?)
}
}
};
Ok(MetaParameters {
fmd_grace_period_blocks,
algorithm,
})
}
}

impl From<MetaParameters> 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(),
)),
},
let algorithm = match value.algorithm {
MetaParametersAlgorithm::Fixed(p) => {
pb::fmd_meta_parameters::Algorithm::FixedPrecisionBits(p.bits().into())
}
};
pb::FmdMetaParameters {
fmd_grace_period_blocks: value.fmd_grace_period_blocks,
algorithm: Some(algorithm),
}
}
}
Expand All @@ -99,7 +113,10 @@ impl DomainType for MetaParameters {

impl Default for MetaParameters {
fn default() -> Self {
Self::Fixed(Precision::default())
Self {
fmd_grace_period_blocks: FMD_GRACE_PERIOD_BLOCKS_DEFAULT,
algorithm: MetaParametersAlgorithm::Fixed(Precision::default()),
}
}
}

Expand All @@ -110,8 +127,8 @@ impl MetaParameters {
height: u64,
_clue_count_delta: (u64, u64),
) -> Parameters {
match *self {
MetaParameters::Fixed(precision) => Parameters {
match self.algorithm {
MetaParametersAlgorithm::Fixed(precision) => Parameters {
precision,
as_of_block_height: height,
},
Expand Down
10 changes: 8 additions & 2 deletions crates/proto/src/gen/penumbra.core.component.shielded_pool.v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,24 @@ impl ::prost::Name for GenesisContent {
)
}
}
/// The parameters which control how the FMD parameters evolve over time.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct FmdMetaParameters {
#[prost(oneof = "fmd_meta_parameters::Algorithm", tags = "1")]
/// How much time users have to transition to new parameters.
#[prost(uint64, tag = "1")]
pub fmd_grace_period_blocks: u64,
/// The algorithm governing how the parameters change.
#[prost(oneof = "fmd_meta_parameters::Algorithm", tags = "2")]
pub algorithm: ::core::option::Option<fmd_meta_parameters::Algorithm>,
}
/// Nested message and enum types in `FmdMetaParameters`.
pub mod fmd_meta_parameters {
/// The algorithm governing how the parameters change.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Algorithm {
#[prost(uint32, tag = "1")]
#[prost(uint32, tag = "2")]
FixedPrecisionBits(u32),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -693,10 +693,17 @@ impl serde::Serialize for FmdMetaParameters {
{
use serde::ser::SerializeStruct;
let mut len = 0;
if self.fmd_grace_period_blocks != 0 {
len += 1;
}
if self.algorithm.is_some() {
len += 1;
}
let mut struct_ser = serializer.serialize_struct("penumbra.core.component.shielded_pool.v1.FmdMetaParameters", len)?;
if self.fmd_grace_period_blocks != 0 {
#[allow(clippy::needless_borrow)]
struct_ser.serialize_field("fmdGracePeriodBlocks", ToString::to_string(&self.fmd_grace_period_blocks).as_str())?;
}
if let Some(v) = self.algorithm.as_ref() {
match v {
fmd_meta_parameters::Algorithm::FixedPrecisionBits(v) => {
Expand All @@ -714,12 +721,15 @@ impl<'de> serde::Deserialize<'de> for FmdMetaParameters {
D: serde::Deserializer<'de>,
{
const FIELDS: &[&str] = &[
"fmd_grace_period_blocks",
"fmdGracePeriodBlocks",
"fixed_precision_bits",
"fixedPrecisionBits",
];

#[allow(clippy::enum_variant_names)]
enum GeneratedField {
FmdGracePeriodBlocks,
FixedPrecisionBits,
__SkipField__,
}
Expand All @@ -743,6 +753,7 @@ impl<'de> serde::Deserialize<'de> for FmdMetaParameters {
E: serde::de::Error,
{
match value {
"fmdGracePeriodBlocks" | "fmd_grace_period_blocks" => Ok(GeneratedField::FmdGracePeriodBlocks),
"fixedPrecisionBits" | "fixed_precision_bits" => Ok(GeneratedField::FixedPrecisionBits),
_ => Ok(GeneratedField::__SkipField__),
}
Expand All @@ -763,9 +774,18 @@ impl<'de> serde::Deserialize<'de> for FmdMetaParameters {
where
V: serde::de::MapAccess<'de>,
{
let mut fmd_grace_period_blocks__ = None;
let mut algorithm__ = None;
while let Some(k) = map_.next_key()? {
match k {
GeneratedField::FmdGracePeriodBlocks => {
if fmd_grace_period_blocks__.is_some() {
return Err(serde::de::Error::duplicate_field("fmdGracePeriodBlocks"));
}
fmd_grace_period_blocks__ =
Some(map_.next_value::<::pbjson::private::NumberDeserialize<_>>()?.0)
;
}
GeneratedField::FixedPrecisionBits => {
if algorithm__.is_some() {
return Err(serde::de::Error::duplicate_field("fixedPrecisionBits"));
Expand All @@ -778,6 +798,7 @@ impl<'de> serde::Deserialize<'de> for FmdMetaParameters {
}
}
Ok(FmdMetaParameters {
fmd_grace_period_blocks: fmd_grace_period_blocks__.unwrap_or_default(),
algorithm: algorithm__,
})
}
Expand Down
Binary file modified crates/proto/src/gen/proto_descriptor.bin.no_lfs
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ message GenesisContent {
repeated Allocation allocations = 3;
}

// The parameters which control how the FMD parameters evolve over time.
message FmdMetaParameters {
// How much time users have to transition to new parameters.
uint64 fmd_grace_period_blocks = 1;
// The algorithm governing how the parameters change.
oneof algorithm {
uint32 fixed_precision_bits = 1;
uint32 fixed_precision_bits = 2;
}
}

Expand Down

0 comments on commit 6a2e04f

Please sign in to comment.