use std::collections::BTreeMap;
use casper_types::{
bytesrepr::{self, FromBytes, ToBytes},
ContractHash, HashAddr,
};
use crate::shared::{system_config::SystemConfig, wasm_config::WasmConfig};
const DEFAULT_ADDRESS: [u8; 32] = [0; 32];
pub const DEFAULT_WASMLESS_TRANSFER_COST: u32 = 10_000;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ProtocolData {
wasm_config: WasmConfig,
system_config: SystemConfig,
mint: ContractHash,
handle_payment: ContractHash,
standard_payment: ContractHash,
auction: ContractHash,
}
impl Default for ProtocolData {
fn default() -> ProtocolData {
ProtocolData {
wasm_config: WasmConfig::default(),
system_config: SystemConfig::default(),
mint: DEFAULT_ADDRESS.into(),
handle_payment: DEFAULT_ADDRESS.into(),
standard_payment: DEFAULT_ADDRESS.into(),
auction: DEFAULT_ADDRESS.into(),
}
}
}
impl ProtocolData {
pub fn new(
wasm_config: WasmConfig,
system_costs: SystemConfig,
mint: ContractHash,
handle_payment: ContractHash,
standard_payment: ContractHash,
auction: ContractHash,
) -> Self {
ProtocolData {
wasm_config,
system_config: system_costs,
mint,
handle_payment,
standard_payment,
auction,
}
}
pub fn partial_with_mint(mint: ContractHash) -> Self {
ProtocolData {
mint,
..Default::default()
}
}
pub fn partial_without_standard_payment(
wasm_config: WasmConfig,
mint: ContractHash,
handle_payment: ContractHash,
) -> Self {
ProtocolData {
wasm_config,
mint,
handle_payment,
..Default::default()
}
}
pub fn wasm_config(&self) -> &WasmConfig {
&self.wasm_config
}
pub fn system_config(&self) -> &SystemConfig {
&self.system_config
}
pub fn mint(&self) -> ContractHash {
self.mint
}
pub fn handle_payment(&self) -> ContractHash {
self.handle_payment
}
pub fn standard_payment(&self) -> ContractHash {
self.standard_payment
}
pub fn auction(&self) -> ContractHash {
self.auction
}
pub fn system_contracts(&self) -> Vec<ContractHash> {
let mut vec = Vec::with_capacity(4);
if self.mint != DEFAULT_ADDRESS.into() {
vec.push(self.mint)
}
if self.handle_payment != DEFAULT_ADDRESS.into() {
vec.push(self.handle_payment)
}
if self.standard_payment != DEFAULT_ADDRESS.into() {
vec.push(self.standard_payment)
}
if self.auction != DEFAULT_ADDRESS.into() {
vec.push(self.auction)
}
vec
}
pub fn update_from(&mut self, updates: BTreeMap<ContractHash, ContractHash>) -> bool {
for (old_hash, new_hash) in updates {
if old_hash == self.mint {
self.mint = new_hash;
} else if old_hash == self.handle_payment {
self.handle_payment = new_hash;
} else if old_hash == self.standard_payment {
self.standard_payment = new_hash;
} else if old_hash == self.auction {
self.auction = new_hash;
} else {
return false;
}
}
true
}
}
impl ToBytes for ProtocolData {
fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
let mut ret = bytesrepr::unchecked_allocate_buffer(self);
ret.append(&mut self.wasm_config.to_bytes()?);
ret.append(&mut self.system_config.to_bytes()?);
ret.append(&mut self.mint.to_bytes()?);
ret.append(&mut self.handle_payment.to_bytes()?);
ret.append(&mut self.standard_payment.to_bytes()?);
ret.append(&mut self.auction.to_bytes()?);
Ok(ret)
}
fn serialized_length(&self) -> usize {
self.wasm_config.serialized_length()
+ self.system_config.serialized_length()
+ self.mint.serialized_length()
+ self.handle_payment.serialized_length()
+ self.standard_payment.serialized_length()
+ self.auction.serialized_length()
}
}
impl FromBytes for ProtocolData {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
let (wasm_config, rem) = WasmConfig::from_bytes(bytes)?;
let (system_config, rem) = FromBytes::from_bytes(rem)?;
let (mint, rem) = HashAddr::from_bytes(rem)?;
let (handle_payment, rem) = HashAddr::from_bytes(rem)?;
let (standard_payment, rem) = HashAddr::from_bytes(rem)?;
let (auction, rem) = HashAddr::from_bytes(rem)?;
Ok((
ProtocolData {
wasm_config,
mint: mint.into(),
handle_payment: handle_payment.into(),
standard_payment: standard_payment.into(),
auction: auction.into(),
system_config,
},
rem,
))
}
}
#[cfg(test)]
pub(crate) mod gens {
use proptest::prop_compose;
use crate::shared::{
system_config::gens::system_config_arb, wasm_config::gens::wasm_config_arb,
};
use casper_types::gens;
use super::ProtocolData;
prop_compose! {
pub fn protocol_data_arb()(
wasm_config in wasm_config_arb(),
system_config in system_config_arb(),
mint in gens::u8_slice_32(),
handle_payment in gens::u8_slice_32(),
standard_payment in gens::u8_slice_32(),
auction in gens::u8_slice_32(),
) -> ProtocolData {
ProtocolData {
wasm_config,
system_config,
mint: mint.into(),
handle_payment: handle_payment.into(),
standard_payment: standard_payment.into(),
auction: auction.into(),
}
}
}
}
#[cfg(test)]
mod tests {
use proptest::proptest;
use crate::shared::{system_config::SystemConfig, wasm_config::WasmConfig};
use casper_types::{bytesrepr, ContractHash};
use super::{gens, ProtocolData};
#[test]
fn should_return_all_system_contracts() {
let mint_reference = [1u8; 32].into();
let handle_payment_reference = [2u8; 32].into();
let standard_payment_reference = [3u8; 32].into();
let auction_reference = [4u8; 32].into();
let protocol_data = {
let wasm_config = WasmConfig::default();
let system_config = SystemConfig::default();
ProtocolData::new(
wasm_config,
system_config,
mint_reference,
handle_payment_reference,
standard_payment_reference,
auction_reference,
)
};
let actual = {
let mut items = protocol_data.system_contracts();
items.sort_unstable();
items
};
assert_eq!(actual.len(), 4);
assert_eq!(actual[0], mint_reference);
assert_eq!(actual[1], handle_payment_reference);
assert_eq!(actual[2], standard_payment_reference);
assert_eq!(actual[3], auction_reference);
}
#[test]
fn should_return_only_valid_system_contracts() {
let expected: Vec<ContractHash> = vec![];
assert_eq!(ProtocolData::default().system_contracts(), expected);
let mint_reference = [0u8; 32].into();
let handle_payment_reference = [2u8; 32].into();
let standard_payment_reference = [3u8; 32].into();
let auction_reference = [4u8; 32].into();
let protocol_data = {
let wasm_config = WasmConfig::default();
let system_config = SystemConfig::default();
ProtocolData::new(
wasm_config,
system_config,
mint_reference,
handle_payment_reference,
standard_payment_reference,
auction_reference,
)
};
let actual = {
let mut items = protocol_data.system_contracts();
items.sort_unstable();
items
};
assert_eq!(actual.len(), 3);
assert_eq!(actual[0], handle_payment_reference);
assert_eq!(actual[1], standard_payment_reference);
assert_eq!(actual[2], auction_reference);
}
proptest! {
#[test]
fn should_serialize_and_deserialize_with_arbitrary_values(
protocol_data in gens::protocol_data_arb()
) {
bytesrepr::test_serialization_roundtrip(&protocol_data);
}
}
}