use async_graphql::InputObject;
use linera_base::data_types::{Amount, ArithmeticError};
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Eq, PartialEq, Hash, Clone, Debug, Serialize, Deserialize, InputObject)]
pub struct ResourceControlPolicy {
pub certificate: Amount,
pub fuel: Amount,
pub storage_num_reads: Amount,
pub storage_bytes_read: Amount,
pub storage_bytes_written: Amount,
pub maximum_bytes_read_per_block: u64,
pub maximum_bytes_written_per_block: u64,
pub messages: Amount,
}
impl Default for ResourceControlPolicy {
fn default() -> Self {
ResourceControlPolicy {
certificate: Amount::default(),
fuel: Amount::default(),
storage_num_reads: Amount::default(),
storage_bytes_read: Amount::default(),
storage_bytes_written: Amount::default(),
maximum_bytes_read_per_block: u64::MAX / 2,
maximum_bytes_written_per_block: u64::MAX / 2,
messages: Amount::default(),
}
}
}
impl ResourceControlPolicy {
pub fn certificate_price(&self) -> Amount {
self.certificate
}
pub fn messages_price(&self, data: &impl Serialize) -> Result<Amount, PricingError> {
let size =
u128::try_from(bcs::serialized_size(data)?).map_err(|_| ArithmeticError::Overflow)?;
Ok(self.messages.try_mul(size)?)
}
pub fn storage_num_reads_price(&self, count: &u64) -> Result<Amount, PricingError> {
let count = *count as u128;
Ok(self.storage_num_reads.try_mul(count)?)
}
pub fn storage_bytes_read_price(&self, count: &u64) -> Result<Amount, PricingError> {
let count = *count as u128;
Ok(self.storage_bytes_read.try_mul(count)?)
}
pub fn storage_bytes_written_price(&self, count: &u64) -> Result<Amount, PricingError> {
let count = *count as u128;
Ok(self.storage_bytes_written.try_mul(count)?)
}
pub fn storage_bytes_written_price_raw(
&self,
data: &impl Serialize,
) -> Result<Amount, PricingError> {
let size =
u128::try_from(bcs::serialized_size(data)?).map_err(|_| ArithmeticError::Overflow)?;
Ok(self.storage_bytes_written.try_mul(size)?)
}
pub fn fuel_price(&self, fuel: u64) -> Result<Amount, PricingError> {
Ok(self.fuel.try_mul(u128::from(fuel))?)
}
pub fn remaining_fuel(&self, balance: Amount) -> u64 {
u64::try_from(balance.saturating_div(self.fuel)).unwrap_or(u64::MAX)
}
#[cfg(any(test, feature = "test"))]
pub fn only_fuel() -> Self {
ResourceControlPolicy {
certificate: Amount::ZERO,
fuel: Amount::from_atto(1_000_000_000_000),
storage_num_reads: Amount::ZERO,
storage_bytes_read: Amount::ZERO,
storage_bytes_written: Amount::ZERO,
maximum_bytes_read_per_block: u64::MAX / 2,
maximum_bytes_written_per_block: u64::MAX / 2,
messages: Amount::ZERO,
}
}
#[cfg(any(test, feature = "test"))]
pub fn fuel_and_certificate() -> Self {
ResourceControlPolicy {
certificate: Amount::from_milli(1),
fuel: Amount::from_atto(1_000_000_000_000),
storage_num_reads: Amount::ZERO,
storage_bytes_read: Amount::ZERO,
storage_bytes_written: Amount::ZERO,
maximum_bytes_read_per_block: u64::MAX,
maximum_bytes_written_per_block: u64::MAX,
messages: Amount::ZERO,
}
}
#[cfg(any(test, feature = "test"))]
pub fn all_categories() -> Self {
ResourceControlPolicy {
certificate: Amount::from_milli(1),
fuel: Amount::from_atto(1_000_000_000),
storage_num_reads: Amount::ZERO,
storage_bytes_read: Amount::from_atto(100),
storage_bytes_written: Amount::from_atto(1_000),
maximum_bytes_read_per_block: u64::MAX,
maximum_bytes_written_per_block: u64::MAX,
messages: Amount::from_atto(1),
}
}
}
#[derive(Error, Debug)]
pub enum PricingError {
#[error(transparent)]
ArithmeticError(#[from] ArithmeticError),
#[error(transparent)]
SerializationError(#[from] bcs::Error),
}