penumbra_fee/component/view.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use cnidarium::{StateRead, StateWrite};
use penumbra_asset::asset;
use penumbra_num::Amount;
use penumbra_proto::{StateReadProto, StateWriteProto};
use crate::{params::FeeParameters, state_key, Fee, GasPrices};
/// This trait provides read access to fee-related parts of the Penumbra
/// state store.
#[async_trait]
pub trait StateReadExt: StateRead {
/// Gets the fee parameters from the JMT.
async fn get_fee_params(&self) -> Result<FeeParameters> {
self.get(state_key::fee_params())
.await?
.ok_or_else(|| anyhow!("Missing FeeParameters"))
}
/// Gets the current gas prices for the fee token.
async fn get_gas_prices(&self) -> Result<GasPrices> {
// When we implement dynamic gas pricing, we will want
// to read the prices we computed. But until then, we need to
// read these from the _fee params_ instead, since those are
// the values that will get updated by governance.
let params = self.get_fee_params().await?;
Ok(params.fixed_gas_prices)
}
/// Gets the current gas prices for alternative fee tokens.
async fn get_alt_gas_prices(&self) -> Result<Vec<GasPrices>> {
// When we implement dynamic gas pricing, we will want
// to read the prices we computed. But until then, we need to
// read these from the _fee params_ instead, since those are
// the values that will get updated by governance.
let params = self.get_fee_params().await?;
Ok(params.fixed_alt_gas_prices)
}
/// Returns true if the gas prices have been changed in this block.
fn gas_prices_changed(&self) -> bool {
self.object_get::<()>(state_key::gas_prices_changed())
.is_some()
}
/// The accumulated base fees and tips for this block, indexed by asset ID.
fn accumulated_base_fees_and_tips(&self) -> im::OrdMap<asset::Id, (Amount, Amount)> {
self.object_get(state_key::fee_accumulator())
.unwrap_or_default()
}
}
impl<T: StateRead + ?Sized> StateReadExt for T {}
#[async_trait]
pub trait StateWriteExt: StateWrite {
/// Writes the provided fee parameters to the JMT.
fn put_fee_params(&mut self, params: FeeParameters) {
self.put(state_key::fee_params().into(), params);
// This could have changed the gas prices, so mark them as changed.
self.object_put(state_key::gas_prices_changed(), ());
}
/*
We shouldn't be setting gas prices directly, until we have dynamic gas pricing.
/// Writes the provided gas prices to the JMT.
fn put_gas_prices(&mut self, gas_prices: GasPrices) {
// Change the gas prices:
self.put(state_key::gas_prices().into(), gas_prices);
// Mark that they've changed
self.object_put(state_key::gas_prices_changed(), ());
}
*/
/// Takes the accumulated base fees and tips for this block, resetting them to zero.
fn take_accumulated_base_fees_and_tips(&mut self) -> im::OrdMap<asset::Id, (Amount, Amount)> {
let old = self.accumulated_base_fees_and_tips();
let new = im::OrdMap::<asset::Id, (Amount, Amount)>::new();
self.object_put(state_key::fee_accumulator(), new);
old
}
fn raw_accumulate_base_fee(&mut self, base_fee: Fee) {
let old = self.accumulated_base_fees_and_tips();
let new = old.alter(
|maybe_amounts| match maybe_amounts {
Some((base, tip)) => Some((base + base_fee.amount(), tip)),
None => Some((base_fee.amount(), Amount::zero())),
},
base_fee.asset_id(),
);
self.object_put(state_key::fee_accumulator(), new);
}
fn raw_accumulate_tip(&mut self, tip_fee: Fee) {
let old = self.accumulated_base_fees_and_tips();
let new = old.alter(
|maybe_amounts| match maybe_amounts {
Some((base, tip)) => Some((base, tip + tip_fee.amount())),
None => Some((Amount::zero(), tip_fee.amount())),
},
tip_fee.asset_id(),
);
self.object_put(state_key::fee_accumulator(), new);
}
}
impl<T: StateWrite + ?Sized> StateWriteExt for T {}