Skip to content
Open
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
91 changes: 86 additions & 5 deletions crates/cardano/src/estart/reset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ use std::sync::Arc;
use dolos_core::{ChainError, Genesis, NsKey};
use pallas::ledger::primitives::Epoch;
use serde::{Deserialize, Serialize};
use tracing::debug;

use crate::{
estart::{AccountId, PoolId, WorkContext},
pots::{apply_delta, PotDelta, Pots},
AccountState, CardanoDelta, EpochState, EraTransition, FixedNamespace as _, PoolState,
pallas_ratio,
pots::{self, apply_delta, EpochIncentives, Eta, PotDelta, Pots},
ratio, AccountState, CardanoDelta, EpochState, EraTransition, FixedNamespace as _, PoolState,
CURRENT_EPOCH_KEY,
};

Expand Down Expand Up @@ -84,6 +86,7 @@ impl dolos_core::EntityDelta for PoolTransition {
pub struct EpochTransition {
new_epoch: Epoch,
new_pots: Pots,
new_incentives: EpochIncentives,
era_transition: Option<EraTransition>,

#[serde(skip)]
Expand Down Expand Up @@ -113,6 +116,7 @@ impl dolos_core::EntityDelta for EpochTransition {

entity.number = self.new_epoch;
entity.initial_pots = self.new_pots.clone();
entity.incentives = self.new_incentives.clone();
entity.rolling.default_transition(self.new_epoch);
entity.pparams.default_transition(self.new_epoch);

Expand All @@ -135,6 +139,79 @@ impl dolos_core::EntityDelta for EpochTransition {
}
}

fn define_eta(genesis: &Genesis, epoch: &EpochState) -> Result<Eta, ChainError> {
if epoch.pparams.mark().is_none_or(|x| x.is_byron()) {
return Ok(ratio!(1));
}

let blocks_minted = epoch.rolling.mark().map(|x| x.blocks_minted);

let Some(blocks_minted) = blocks_minted else {
// TODO: check if returning eta = 1 on epoch 0 is what the specs says.
return Ok(ratio!(1));
};

let f_param = genesis
.shelley
.active_slots_coeff
.ok_or(ChainError::GenesisFieldMissing(
"active_slots_coeff".to_string(),
))?;

let d_param = epoch.pparams.mark().unwrap().ensure_d()?;
let epoch_length = epoch.pparams.mark().unwrap().ensure_epoch_length()?;

let eta = pots::calculate_eta(
blocks_minted as u64,
pallas_ratio!(d_param),
f_param,
epoch_length,
);

Ok(eta)
}

fn define_new_incentives(
ctx: &WorkContext,
new_pots: &Pots,
) -> Result<EpochIncentives, ChainError> {
let state = ctx.ended_state();

let pparams = state.pparams.unwrap_live();

if pparams.is_byron() {
debug!("no pot changes during Byron epoch");
return Ok(EpochIncentives::neutral());
}

let rho_param = pparams.ensure_rho()?;
let tau_param = pparams.ensure_tau()?;

let fee_ss = match state.rolling.mark() {
Some(rolling) => rolling.gathered_fees,
None => 0,
};

let eta = define_eta(&ctx.genesis, state)?;

let incentives = pots::epoch_incentives(
new_pots.reserves,
fee_ss,
pallas_ratio!(rho_param),
pallas_ratio!(tau_param),
eta,
);

debug!(
%incentives.total,
%incentives.treasury_tax,
%incentives.available_rewards,
"defined new incentives"
);

Ok(incentives)
}

pub fn define_new_pots(ctx: &super::WorkContext) -> Pots {
let epoch = ctx.ended_state();

Expand Down Expand Up @@ -171,15 +248,15 @@ pub fn define_new_pots(ctx: &super::WorkContext) -> Pots {
.unwrap_or(0),
};

let pots = apply_delta(epoch.initial_pots.clone(), &end.epoch_incentives, &delta);
let pots = apply_delta(epoch.initial_pots.clone(), &epoch.incentives, &delta);

tracing::debug!(
rewards = pots.rewards,
reserves = pots.reserves,
treasury = pots.treasury,
fees = pots.fees,
utxos = pots.utxos,
"pots after reset"
"defined new pots"
);

if !pots.is_consistent(epoch.initial_pots.max_supply()) {
Expand Down Expand Up @@ -233,9 +310,13 @@ impl super::BoundaryVisitor for BoundaryVisitor {
ctx.add_delta(delta);
}

let new_pots = define_new_pots(ctx);
let new_incentives = define_new_incentives(ctx, &new_pots)?;

ctx.deltas.add_for_entity(EpochTransition {
new_epoch: ctx.starting_epoch_no(),
new_pots: define_new_pots(ctx),
new_pots,
new_incentives,
era_transition: ctx.ended_state().pparams.era_transition(),
genesis: Some(ctx.genesis.clone()),
});
Expand Down
8 changes: 3 additions & 5 deletions crates/cardano/src/ewrap/wrapup.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
AccountState, CardanoDelta, EndStats, EpochState, FixedNamespace as _, PoolHash, PoolState,
CURRENT_EPOCH_KEY,
pots::EpochIncentives, AccountState, CardanoDelta, EndStats, EpochState, FixedNamespace as _,
PoolHash, PoolState, CURRENT_EPOCH_KEY,
};
use dolos_core::{ChainError, NsKey};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -122,20 +122,18 @@ fn define_end_stats(ctx: &super::BoundaryWork) -> EndStats {
let proposal_valid_refunds = define_proposal_valid_refunds(ctx);
let proposal_invalid_refunds = proposal_total_refunds - proposal_valid_refunds;

let incentives = ctx.rewards.incentives();

EndStats {
pool_deposit_count: ctx.new_pools.len() as u64,
pool_refund_count: pool_refund_count as u64,
pool_invalid_refund_count: pool_invalid_refund_count as u64,
epoch_incentives: incentives.clone(),
effective_rewards: ctx.rewards.applied_effective(),
unspendable_rewards: ctx.rewards.applied_unspendable(),
proposal_refunds: proposal_valid_refunds,
proposal_invalid_refunds,
// TODO: deprecate
__drep_deposits: 0,
__drep_refunds: 0,
__epoch_incentives: EpochIncentives::default(),
}
}

Expand Down
7 changes: 5 additions & 2 deletions crates/cardano/src/genesis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ use dolos_core::{
};

use crate::{
pots::Pots, utils::nonce_stability_window, EpochState, EpochValue, EraBoundary, EraSummary,
Lovelace, Nonces, PParamsSet, RollingStats, CURRENT_EPOCH_KEY,
pots::{EpochIncentives, Pots},
utils::nonce_stability_window,
EpochState, EpochValue, EraBoundary, EraSummary, Lovelace, Nonces, PParamsSet, RollingStats,
CURRENT_EPOCH_KEY,
};

mod staking;
Expand Down Expand Up @@ -71,6 +73,7 @@ pub fn bootstrap_epoch<D: Domain>(
previous_nonce_tail: None,
number: 0,
rolling: EpochValue::with_live(0, RollingStats::default()),
incentives: EpochIncentives::default(),
end: None,
};

Expand Down
6 changes: 5 additions & 1 deletion crates/cardano/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1460,8 +1460,9 @@ pub struct EndStats {
#[n(2)]
pub pool_invalid_refund_count: u64,

// TODO: deprecate
#[n(3)]
pub epoch_incentives: EpochIncentives,
pub __epoch_incentives: EpochIncentives,

#[n(4)]
pub effective_rewards: u64,
Expand Down Expand Up @@ -1495,6 +1496,9 @@ pub struct EpochState {
#[n(2)]
pub rolling: EpochValue<RollingStats>,

#[n(3)]
pub incentives: EpochIncentives,

#[n(9)]
pub pparams: EpochValue<PParamsSet>,

Expand Down
14 changes: 13 additions & 1 deletion crates/cardano/src/pots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,19 @@ pub struct EpochIncentives {
pub used_fees: u64,
}

#[derive(Debug, Clone, Encode, Decode, Serialize, Deserialize)]
impl EpochIncentives {
// TODO: this and default are same, commit to one
pub fn neutral() -> Self {
Self {
total: 0,
treasury_tax: 0,
available_rewards: 0,
used_fees: 0,
}
}
}

#[derive(Debug, Clone, Encode, Decode, Serialize, Deserialize, Default)]
pub struct PotDelta {
#[n(0)]
pub produced_utxos: Lovelace,
Expand Down
17 changes: 9 additions & 8 deletions crates/cardano/src/rewards/mocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::{
pallas_ratio,
pots::{EpochIncentives, Pots},

Check warning on line 6 in crates/cardano/src/rewards/mocking.rs

View workflow job for this annotation

GitHub Actions / Check Build

unused import: `EpochIncentives`

Check warning on line 6 in crates/cardano/src/rewards/mocking.rs

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

unused import: `EpochIncentives`
PParamsSet, PoolHash, PoolParams,
};

Expand Down Expand Up @@ -134,9 +134,9 @@
/// Converted pool params for efficient lookup
#[serde(skip)]
pool_params_converted: HashMap<String, PoolParams>,
/// Computed pot delta for the rewards calculation
/// Computed available rewards for the epoch
#[serde(skip)]
incentives: Option<EpochIncentives>,
available_rewards: Option<u64>,
}

impl MockContext {
Expand All @@ -156,13 +156,15 @@

context.pool_params_converted = converted;

context.incentives = Some(crate::pots::epoch_incentives(
let incentives = crate::pots::epoch_incentives(
context.pots.reserves,
context.epoch_fee_ss,
pallas_ratio!(context.pparams.ensure_rho()?),
pallas_ratio!(context.pparams.ensure_tau()?),
pallas_ratio!(context.epoch_eta),
));
);

context.available_rewards = Some(incentives.available_rewards);

Ok(context)
}
Expand Down Expand Up @@ -196,10 +198,9 @@
}

impl super::RewardsContext for MockContext {
fn incentives(&self) -> &EpochIncentives {
self.incentives
.as_ref()
.expect("epoch incentives not computed")
fn available_rewards(&self) -> u64 {
self.available_rewards
.expect("available rewards not computed")
}

fn pots(&self) -> &Pots {
Expand Down
22 changes: 5 additions & 17 deletions crates/cardano/src/rewards/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ use dolos_core::ChainError;
use pallas::ledger::primitives::StakeCredential;
use tracing::debug;

use crate::{
pallas_extras, pallas_ratio,
pots::{EpochIncentives, Pots},
Lovelace, PParamsSet, PoolHash, PoolParams,
};
use crate::{pallas_extras, pallas_ratio, pots::Pots, Lovelace, PParamsSet, PoolHash, PoolParams};

mod formulas;

Expand Down Expand Up @@ -145,7 +141,6 @@ impl Reward {

#[derive(Debug)]
pub struct RewardMap<C: RewardsContext> {
incentives: EpochIncentives,
pending: HashMap<StakeCredential, Reward>,
applied_effective: u64,
applied_unspendable: u64,
Expand Down Expand Up @@ -179,7 +174,6 @@ impl<C: RewardsContext> std::fmt::Display for RewardMap<C> {
impl<C: RewardsContext> Default for RewardMap<C> {
fn default() -> Self {
Self {
incentives: EpochIncentives::default(),
pending: HashMap::new(),
applied_effective: 0,
applied_unspendable: 0,
Expand All @@ -191,7 +185,6 @@ impl<C: RewardsContext> Default for RewardMap<C> {
impl<C: RewardsContext> Clone for RewardMap<C> {
fn clone(&self) -> Self {
Self {
incentives: self.incentives.clone(),
pending: self.pending.clone(),
applied_effective: self.applied_effective,
applied_unspendable: self.applied_unspendable,
Expand All @@ -201,9 +194,8 @@ impl<C: RewardsContext> Clone for RewardMap<C> {
}

impl<C: RewardsContext> RewardMap<C> {
fn new(incentives: EpochIncentives) -> Self {
fn new() -> Self {
Self {
incentives,
pending: HashMap::new(),
applied_effective: 0,
applied_unspendable: 0,
Expand Down Expand Up @@ -285,10 +277,6 @@ impl<C: RewardsContext> RewardMap<C> {
}
}

pub fn incentives(&self) -> &EpochIncentives {
&self.incentives
}

pub fn applied_effective(&self) -> u64 {
assert!(self.pending.is_empty());
self.applied_effective
Expand All @@ -301,7 +289,7 @@ impl<C: RewardsContext> RewardMap<C> {
}

pub trait RewardsContext {
fn incentives(&self) -> &EpochIncentives;
fn available_rewards(&self) -> u64;
fn pots(&self) -> &Pots;

fn pre_allegra(&self) -> bool;
Expand Down Expand Up @@ -330,7 +318,7 @@ pub trait RewardsContext {
}

pub fn define_rewards<C: RewardsContext>(ctx: &C) -> Result<RewardMap<C>, ChainError> {
let mut map = RewardMap::<C>::new(ctx.incentives().clone());
let mut map = RewardMap::<C>::new();

for pool in ctx.iter_all_pools() {
let pool_params = ctx.pool_params(pool);
Expand All @@ -347,7 +335,7 @@ pub fn define_rewards<C: RewardsContext>(ctx: &C) -> Result<RewardMap<C>, ChainE
let live_pledge = ctx.live_pledge(pool, &owners);
let circulating_supply = ctx.pots().circulating();
let pool_stake = ctx.pool_stake(pool);
let epoch_rewards = ctx.incentives().available_rewards;
let epoch_rewards = ctx.available_rewards();
let total_active_stake = ctx.active_stake();
let epoch_blocks = ctx.epoch_blocks();
let pool_blocks = ctx.pool_blocks(pool);
Expand Down
Loading
Loading