use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable};
use dusk_pki::{Ownable, PublicSpendKey, StealthAddress};
use dusk_poseidon::sponge::hash;
use rand_core::{CryptoRng, RngCore};
#[cfg(feature = "rkyv-impl")]
use rkyv::{Archive, Deserialize, Serialize};
use core::cmp;
use crate::{BlsScalar, JubJubScalar};
mod remainder;
pub use remainder::Remainder;
#[derive(Clone, Copy, Debug)]
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, Serialize, Deserialize),
archive_attr(derive(bytecheck::CheckBytes))
)]
pub struct Fee {
pub gas_limit: u64,
pub gas_price: u64,
pub(crate) stealth_address: StealthAddress,
}
impl PartialEq for Fee {
fn eq(&self, other: &Self) -> bool {
self.hash() == other.hash()
}
}
impl Eq for Fee {}
impl Fee {
pub fn new<R: RngCore + CryptoRng>(
rng: &mut R,
gas_limit: u64,
gas_price: u64,
psk: &PublicSpendKey,
) -> Self {
let r = JubJubScalar::random(rng);
Self::deterministic(gas_limit, gas_price, &r, psk)
}
pub fn deterministic(
gas_limit: u64,
gas_price: u64,
r: &JubJubScalar,
psk: &PublicSpendKey,
) -> Self {
let stealth_address = psk.gen_stealth_address(r);
Fee {
gas_limit,
gas_price,
stealth_address,
}
}
pub fn hash(&self) -> BlsScalar {
let pk_r = self.stealth_address().pk_r().as_ref().to_hash_inputs();
hash(&[
BlsScalar::from(self.gas_limit),
BlsScalar::from(self.gas_price),
pk_r[0],
pk_r[1],
])
}
pub fn gen_remainder(&self, gas_consumed: u64) -> Remainder {
let gas_consumed = cmp::min(gas_consumed, self.gas_limit);
let gas_changes = (self.gas_limit - gas_consumed) * self.gas_price;
Remainder {
gas_changes,
stealth_address: self.stealth_address,
}
}
}
impl Serializable<{ 8 * 2 + StealthAddress::SIZE }> for Fee {
type Error = BytesError;
fn to_bytes(&self) -> [u8; Self::SIZE] {
let mut buf = [0u8; Self::SIZE];
buf[..8].copy_from_slice(&self.gas_limit.to_le_bytes());
buf[8..16].copy_from_slice(&self.gas_price.to_le_bytes());
buf[16..].copy_from_slice(&self.stealth_address.to_bytes());
buf
}
fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
let mut one_u64 = [0u8; 8];
one_u64.copy_from_slice(&bytes[..8]);
let gas_limit = u64::from_le_bytes(one_u64);
one_u64.copy_from_slice(&bytes[8..16]);
let gas_price = u64::from_le_bytes(one_u64);
let stealth_address = StealthAddress::from_slice(&bytes[16..])?;
Ok(Fee {
gas_limit,
gas_price,
stealth_address,
})
}
}
impl Ownable for Fee {
fn stealth_address(&self) -> &StealthAddress {
&self.stealth_address
}
}