Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ run:
fmt:
$(CARGO) fmt --all

check:
$(CARGO) fmt --all -- --check
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add a new target or rename this.

Suggested change
$(CARGO) fmt --all -- --check
fmt:
$(CARGO) fmt --all
fmt-check:
$(CARGO) fmt --all -- --check

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the fence about this, as it now matches what CI/CD does, which is my intent. One-stop shopping! I like a simple name when possible. I don't know if anyone else was even using it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought about it some more and made the change, though you may not like it. I used "check" for the new name. It wasn't taken yet, and it can be my one-stop-shopping target for CI/CD compliance.


clippy:
$(CARGO) clippy --workspace -- -D warnings

Expand Down
114 changes: 114 additions & 0 deletions common/examples/test_streaming_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//
// Usage: cargo run --example test_streaming_parser --release -- <snapshot_path>

use acropolis_common::snapshot::protocol_parameters::ProtocolParameters;
use acropolis_common::snapshot::streaming_snapshot::GovernanceProtocolParametersCallback;
use acropolis_common::snapshot::EpochCallback;
use acropolis_common::snapshot::{
AccountState, DRepCallback, DRepInfo, GovernanceProposal, PoolCallback, PoolInfo,
Expand Down Expand Up @@ -30,6 +32,9 @@ struct CountingCallbacks {
sample_accounts: Vec<AccountState>,
sample_dreps: Vec<DRepInfo>,
sample_proposals: Vec<GovernanceProposal>,
gs_previous_params: Option<ProtocolParameters>,
gs_current_params: Option<ProtocolParameters>,
gs_future_params: Option<ProtocolParameters>,
}

impl UtxoCallback for CountingCallbacks {
Expand Down Expand Up @@ -162,6 +167,115 @@ impl ProposalCallback for CountingCallbacks {
}
}

impl GovernanceProtocolParametersCallback for CountingCallbacks {
fn on_gs_protocol_parameters(
&mut self,
gs_previous_params: ProtocolParameters,
gs_current_params: ProtocolParameters,
gs_future_params: ProtocolParameters,
) -> Result<()> {
eprintln!("\n=== Governance Protocol Parameters ===\n");

eprintln!("Previous Protocol Parameters:");
eprintln!(
" Protocol Version: {}.{}",
gs_previous_params.protocol_version.major, gs_previous_params.protocol_version.minor
);
eprintln!(" Min Fee A: {}", gs_previous_params.min_fee_a);
eprintln!(" Min Fee B: {}", gs_previous_params.min_fee_b);
eprintln!(
" Max Block Body Size: {}",
gs_previous_params.max_block_body_size
);
eprintln!(
" Max Transaction Size: {}",
gs_previous_params.max_transaction_size
);
eprintln!(
" Max Block Header Size: {}",
gs_previous_params.max_block_header_size
);
eprintln!(
" Stake Pool Deposit: {}",
gs_previous_params.stake_pool_deposit
);
eprintln!(
" Stake Credential Deposit: {}",
gs_previous_params.stake_credential_deposit
);
eprintln!(" Min Pool Cost: {}", gs_previous_params.min_pool_cost);
eprintln!(
" Monetary Expansion: {}/{}",
gs_previous_params.monetary_expansion_rate.numerator,
gs_previous_params.monetary_expansion_rate.denominator
);
eprintln!(
" Treasury Expansion: {}/{}",
gs_previous_params.treasury_expansion_rate.numerator,
gs_previous_params.treasury_expansion_rate.denominator
);

eprintln!("\nCurrent Protocol Parameters:");
eprintln!(
" Protocol Version: {}.{}",
gs_current_params.protocol_version.major, gs_current_params.protocol_version.minor
);
eprintln!(" Min Fee A: {}", gs_current_params.min_fee_a);
eprintln!(" Min Fee B: {}", gs_current_params.min_fee_b);
eprintln!(
" Max Block Body Size: {}",
gs_current_params.max_block_body_size
);
eprintln!(
" Max Transaction Size: {}",
gs_current_params.max_transaction_size
);
eprintln!(
" Max Block Header Size: {}",
gs_current_params.max_block_header_size
);
eprintln!(
" Stake Pool Deposit: {}",
gs_current_params.stake_pool_deposit
);
eprintln!(
" Stake Credential Deposit: {}",
gs_current_params.stake_credential_deposit
);
eprintln!(" Min Pool Cost: {}", gs_current_params.min_pool_cost);
eprintln!(
" Monetary Expansion: {}/{}",
gs_current_params.monetary_expansion_rate.numerator,
gs_current_params.monetary_expansion_rate.denominator
);
eprintln!(
" Treasury Expansion: {}/{}",
gs_current_params.treasury_expansion_rate.numerator,
gs_current_params.treasury_expansion_rate.denominator
);

eprintln!("\nFuture Protocol Parameters:");
eprintln!(
" Protocol Version: {}.{}",
gs_future_params.protocol_version.major, gs_future_params.protocol_version.minor
);
eprintln!(" Min Fee A: {}", gs_future_params.min_fee_a);
eprintln!(" Min Fee B: {}", gs_future_params.min_fee_b);
eprintln!(
" Max Block Body Size: {}",
gs_future_params.max_block_body_size
);

// Store for later display
self.gs_previous_params = Some(gs_previous_params);
self.gs_current_params = Some(gs_current_params);
self.gs_future_params = Some(gs_future_params);

eprintln!("\n=== End Protocol Parameters ===\n");
Ok(())
}
}

impl EpochCallback for CountingCallbacks {
fn on_epoch(&mut self, data: EpochBootstrapData) -> Result<()> {
info!(
Expand Down
4 changes: 2 additions & 2 deletions common/src/protocol_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl PraosParams {

impl From<&ShelleyParams> for PraosParams {
fn from(params: &ShelleyParams) -> Self {
let active_slots_coeff = params.active_slots_coeff;
let active_slots_coeff = &params.active_slots_coeff;
let security_param = params.security_param;
let stability_window =
(security_param as u64) * active_slots_coeff.denom() / active_slots_coeff.numer() * 3;
Expand All @@ -204,7 +204,7 @@ impl From<&ShelleyParams> for PraosParams {

Self {
security_param,
active_slots_coeff,
active_slots_coeff: active_slots_coeff.clone(),
epoch_length: params.epoch_length,
max_kes_evolutions: params.max_kes_evolutions,
max_lovelace_supply: params.max_lovelace_supply,
Expand Down
75 changes: 73 additions & 2 deletions common/src/rational_number.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,89 @@
use anyhow::{anyhow, Result};
use bigdecimal::BigDecimal;
use minicbor::Decode;
use num_rational::Ratio;
use num_traits::ToPrimitive;
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::{DeserializeAs, SerializeAs};
use std::fmt;
use std::ops::Deref;
use std::str::FromStr;

pub type RationalNumber = num_rational::Ratio<u64>;
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider deriving Copy for RationalNumber since it wraps Ratio<u64> which is essentially two u64 values (16 bytes total). This would improve performance in critical paths like block VRF validation (see modules/block_vrf_validator/src/state.rs:98,103) where RationalNumber values are currently cloned. Add #[derive(Copy)] to the struct definition alongside the existing derives.

Suggested change
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]

Copilot uses AI. Check for mistakes.
pub struct RationalNumber(pub Ratio<u64>);

pub fn rational_number_from_f32(f: f32) -> Result<RationalNumber> {
RationalNumber::approximate_float_unsigned(f)
.ok_or_else(|| anyhow!("Cannot convert {f} to Rational"))
}

impl RationalNumber {
pub const fn new(numerator: u64, denominator: u64) -> Self {
RationalNumber(Ratio::new_raw(numerator, denominator))
}
pub fn approximate_float_unsigned(f: f32) -> Option<Self> {
// Call the underlying Ratio function and map the result back to Self (RationalNumber)
Ratio::approximate_float_unsigned(f).map(RationalNumber)
}
pub fn from(numerator: u64, denominator: u64) -> Self {
RationalNumber(Ratio::new(numerator, denominator))
}
pub const ZERO: RationalNumber = Self::new(0, 1);
pub const ONE: RationalNumber = Self::new(1, 1);
}

// Implement Deref to automatically access Ratio's methods
impl Deref for RationalNumber {
type Target = Ratio<u64>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl FromStr for RationalNumber {
// The associated error type must implement Debug
type Err = num_rational::ParseRatioError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
// Delegate the parsing logic to the underlying Ratio<u64> implementation
Ratio::from_str(s).map(RationalNumber)
}
}

impl fmt::Display for RationalNumber {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Delegate the formatting task to the inner Ratio<u64> field (self.0)
write!(f, "{}", self.0)
}
}

// Implement the required minicbor::Decode
impl<'a, C> Decode<'a, C> for RationalNumber {
fn decode(
d: &mut minicbor::Decoder<'a>,
_ctx: &mut C,
) -> Result<Self, minicbor::decode::Error> {
// Handle optional CBOR tag 30 for rationals (used in snapshots)
if matches!(d.datatype()?, minicbor::data::Type::Tag) {
d.tag()?; // consume the tag
}

d.array()?;
let num: u64 = d.u64()?;
let den: u64 = d.u64()?;

if den == 0 {
return Err(minicbor::decode::Error::message(
"Denominator cannot be zero",
));
}

Ok(RationalNumber(Ratio::new(num, den)))
}
}

#[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug, Clone)]
#[serde(untagged)]
pub enum ChameleonFraction {
Expand Down Expand Up @@ -112,7 +183,7 @@ impl SerializeAs<RationalNumber> for ChameleonFraction {
where
S: Serializer,
{
let ch = ChameleonFraction::from_rational(*src);
let ch = ChameleonFraction::from_rational(src.clone());
ch.serialize(serializer)
}
}
Expand Down
Loading