use super::{Extrinsic, Header};
use core::fmt;
use jam_types::{
chain_params, max_exports, max_imports, max_input, opaque, val_count, Balance, CoreIndex,
FixedVec, SegmentSliceLen, Slot, UnsignedGas, ValIndex,
};
use scale::{Decode, Encode};
use std::{sync::atomic::Ordering::Relaxed, time::Duration};
pub const SLOT_PERIOD_IN_NS: u64 = 6_000_000_000;
pub const SLOT_PERIOD: Duration = Duration::from_nanos(SLOT_PERIOD_IN_NS);
pub type TicketAttempt = u8;
#[cfg(feature = "tiny")]
mod defaults {
use super::{Slot, TicketAttempt};
pub(super) const EPOCH_PERIOD: Slot = 12;
pub(super) const ROTATION_PERIOD: Slot = 4;
pub(super) const MAX_TICKETS_PER_BLOCK: usize = 3;
pub(super) const TICKETS_ATTEMPTS_NUMBER: TicketAttempt = 3;
}
#[cfg(not(feature = "tiny"))]
mod defaults {
use super::{Slot, TicketAttempt};
pub(super) const EPOCH_PERIOD: Slot = 600;
pub(super) const ROTATION_PERIOD: Slot = 10;
pub(super) const MAX_TICKETS_PER_BLOCK: usize = 16;
pub(super) const TICKETS_ATTEMPTS_NUMBER: TicketAttempt = 2;
}
chain_params! {
static ROTATION_PERIOD: _ = _(defaults::ROTATION_PERIOD);
pub fn rotation_period() -> Slot;
pub struct RotationPeriod; impl Get<_> for _ {}
static EPOCH_PERIOD: _ = _(defaults::EPOCH_PERIOD);
pub fn epoch_period() -> Slot;
pub struct EpochPeriod; impl Get<_> for _ {}
static MAX_TICKETS_PER_BLOCK: _ = _(defaults::MAX_TICKETS_PER_BLOCK);
pub fn max_tickets_per_block() -> usize;
pub struct MaxTicketsPerBlock; impl Get<_> for _ {}
static TICKETS_ATTEMPTS_NUMBER: _ = _(defaults::TICKETS_ATTEMPTS_NUMBER);
pub fn tickets_attempts_number() -> TicketAttempt;
static DEPOSIT_PER_ACCOUNT: _ = _(100);
pub fn deposit_per_account() -> Balance;
static DEPOSIT_PER_ITEM: _ = _(10);
pub fn deposit_per_item() -> Balance;
static DEPOSIT_PER_BYTE: _ = _(1);
pub fn deposit_per_byte() -> Balance;
static BLOCK_GAS_LIMIT: _ = _(3_500_000_000);
pub fn block_gas_limit() -> UnsignedGas;
static MAX_IS_AUTHORIZED_GAS: _ = _(50_000_000);
pub fn max_is_authorized_gas() -> UnsignedGas;
static MAX_REFINE_GAS: _ = _(5_000_000_000);
pub fn max_refine_gas() -> UnsignedGas;
static MAX_ACCUMULATE_GAS: _ = _(10_000_000);
pub fn max_accumulate_gas() -> UnsignedGas;
static MAX_REFINE_CODE_SIZE: _ = _(10 * 1024 * 1024);
pub fn max_refine_code_size() -> usize;
static MAX_IS_AUTHORIZED_CODE_SIZE: _ = _(64 * 1024);
pub fn max_is_authorized_code_size() -> usize;
static MAX_REFINE_MEMORY: _ = _(1024 * 1024 * 1024);
pub fn max_refine_memory() -> usize;
static MAX_IS_AUTHORIZED_MEMORY: _ = _(256 * 1024);
pub fn max_is_authorized_memory() -> usize;
static RECENT_BLOCK_COUNT: _ = _(8);
pub fn recent_block_count() -> Slot;
pub struct RecentBlockCount; impl Get<_> for _ {}
pub const VALS_PER_CORE: _ = 3;
pub fn vals_per_core() -> usize;
pub struct ValsPerCore; impl Get<_> for _ {}
pub fn core_count() -> CoreIndex {
(val_count() as usize / VALS_PER_CORE) as CoreIndex
}
pub struct CoreCount; impl Get<_> for _ {}
pub fn max_export_segments() -> u32 {
max_exports() + max_exports().div_ceil(PROVEN_PER_SEGMENT as u32)
}
pub struct MaxExportSegments; impl Get<_> for _ {}
pub fn max_import_segments() -> u32 { max_imports() * 2 }
pub struct MaxImportSegments; impl Get<_> for _ {}
static AVAILABILITY_TIMEOUT: _ = _(5);
pub fn availability_timeout() -> Slot;
static AUTH_WINDOW: _ = _(8);
pub fn auth_window() -> usize;
pub struct AuthWindow; impl Get<_> for _ {}
static MAX_LOOKUP_ANCHOR_AGE: _ = _(24 * 600);
pub fn max_lookup_anchor_age() -> Slot;
}
pub fn max_bundle_size() -> usize {
max_input() as usize + 1024 * 1024
}
#[derive(
Copy, Clone, Eq, PartialEq, Debug, Encode, Decode, serde::Serialize, serde::Deserialize,
)]
pub struct Parameters {
pub val_count: ValIndex,
pub basic_piece_len: u32,
pub auth_queue_len: u32,
pub min_turnaround_period: Slot,
pub max_work_items: u32,
pub max_imports: u32,
pub max_exports: u32,
pub max_extrinsics: u32,
pub max_dependencies: u32,
pub max_input: u32,
pub epoch_period: Slot,
pub rotation_period: Slot,
pub block_gas_limit: UnsignedGas,
pub recent_block_count: Slot,
pub max_tickets_per_block: u32,
pub tickets_attempts_number: TicketAttempt,
pub deposit_per_account: Balance,
pub deposit_per_item: Balance,
pub deposit_per_byte: Balance,
pub max_is_authorized_gas: UnsignedGas,
pub max_refine_gas: UnsignedGas,
pub max_accumulate_gas: UnsignedGas,
pub max_refine_code_size: u32,
pub max_is_authorized_code_size: u32,
pub max_refine_memory: u32,
pub max_is_authorized_memory: u32,
pub availability_timeout: Slot,
pub auth_window: u32,
pub max_lookup_anchor_age: Slot,
}
impl fmt::Display for Parameters {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"\n\
val_count: {}\n\
basic_piece_len: {}\n\
auth_queue_len: {}\n\
min_turnaround_period: {}\n\
max_work_items: {}\n\
max_imports: {}\n\
max_exports: {}\n\
max_extrinsics: {}\n\
max_dependencies: {}\n\
max_input: {}\n\
epoch_period: {}\n\
rotation_period: {}\n\
block_gas_limit: {}\n\
recent_block_count: {}\n\
max_tickets_per_block: {}\n\
tickets_attempts_number: {}\n\
deposit_per_account: {}\n\
deposit_per_item: {}\n\
deposit_per_byte: {}\n\
max_is_authorized_gas: {}\n\
max_refine_gas: {}\n\
max_accumulate_gas: {}\n\
max_refine_code_size: {}\n\
max_is_authorized_code_size: {}\n\
max_refine_memory: {}\n\
max_is_authorized_memory: {}\n\
availability_timeout: {}\n\
auth_window: {}\n\
max_lookup_anchor_age: {}\n\
",
self.val_count,
self.basic_piece_len,
self.auth_queue_len,
self.min_turnaround_period,
self.max_work_items,
self.max_imports,
self.max_exports,
self.max_extrinsics,
self.max_dependencies,
self.max_input,
self.epoch_period,
self.rotation_period,
self.block_gas_limit,
self.recent_block_count,
self.max_tickets_per_block,
self.tickets_attempts_number,
self.deposit_per_account,
self.deposit_per_item,
self.deposit_per_byte,
self.max_is_authorized_gas,
self.max_refine_gas,
self.max_accumulate_gas,
self.max_refine_code_size,
self.max_is_authorized_code_size,
self.max_refine_memory,
self.max_is_authorized_memory,
self.availability_timeout,
self.auth_window,
self.max_lookup_anchor_age,
)
}
}
impl Parameters {
pub fn tiny() -> Self {
Self {
val_count: 6,
basic_piece_len: 4,
auth_queue_len: 80,
min_turnaround_period: 28_800,
max_work_items: 16,
max_imports: 3072,
max_exports: 3072,
max_extrinsics: 128,
max_dependencies: 8,
max_input: 12 * 1024 * 1024,
epoch_period: 12,
rotation_period: 4,
block_gas_limit: 20_000_000,
recent_block_count: 8,
max_tickets_per_block: 3,
tickets_attempts_number: 3,
deposit_per_account: 100,
deposit_per_item: 10,
deposit_per_byte: 1,
max_is_authorized_gas: 50_000_000,
max_refine_gas: 1_600_000_000,
max_accumulate_gas: 10_000_000,
max_refine_code_size: 10 * 1024 * 1024,
max_is_authorized_code_size: 64 * 1024,
max_refine_memory: 1024 * 1024 * 1024,
max_is_authorized_memory: 256 * 1024,
availability_timeout: 5,
auth_window: 8,
max_lookup_anchor_age: 24 * 600,
}
}
pub fn full() -> Self {
Self {
val_count: 1023,
basic_piece_len: 684,
auth_queue_len: 80,
min_turnaround_period: 28_800,
max_work_items: 16,
max_imports: 3072,
max_exports: 3072,
max_extrinsics: 128,
max_dependencies: 8,
max_input: 12 * 1024 * 1024,
epoch_period: 600,
rotation_period: 10,
block_gas_limit: 3_500_000_000,
recent_block_count: 8,
max_tickets_per_block: 16,
tickets_attempts_number: 2,
deposit_per_account: 100,
deposit_per_item: 10,
deposit_per_byte: 1,
max_is_authorized_gas: 50_000_000,
max_refine_gas: 5_000_000_000,
max_accumulate_gas: 10_000_000,
max_refine_code_size: 10 * 1024 * 1024,
max_is_authorized_code_size: 64 * 1024,
max_refine_memory: 1024 * 1024 * 1024,
max_is_authorized_memory: 256 * 1024,
availability_timeout: 5,
auth_window: 8,
max_lookup_anchor_age: 24 * 600,
}
}
pub fn get() -> Self {
let jam_types::Parameters {
val_count,
basic_piece_len,
auth_queue_len,
min_turnaround_period,
max_work_items,
max_imports,
max_exports,
max_extrinsics,
max_dependencies,
max_input,
} = jam_types::Parameters::get();
Self {
val_count,
basic_piece_len,
auth_queue_len,
min_turnaround_period,
max_work_items,
max_imports,
max_exports,
max_extrinsics,
max_dependencies,
max_input,
epoch_period: EPOCH_PERIOD.load(Relaxed),
rotation_period: ROTATION_PERIOD.load(Relaxed),
block_gas_limit: BLOCK_GAS_LIMIT.load(Relaxed),
recent_block_count: RECENT_BLOCK_COUNT.load(Relaxed),
max_tickets_per_block: MAX_TICKETS_PER_BLOCK.load(Relaxed) as _,
tickets_attempts_number: TICKETS_ATTEMPTS_NUMBER.load(Relaxed),
deposit_per_account: DEPOSIT_PER_ACCOUNT.load(Relaxed),
deposit_per_item: DEPOSIT_PER_ITEM.load(Relaxed),
deposit_per_byte: DEPOSIT_PER_BYTE.load(Relaxed),
max_is_authorized_gas: MAX_IS_AUTHORIZED_GAS.load(Relaxed),
max_refine_gas: MAX_REFINE_GAS.load(Relaxed),
max_accumulate_gas: MAX_ACCUMULATE_GAS.load(Relaxed),
max_refine_code_size: MAX_REFINE_CODE_SIZE.load(Relaxed) as _,
max_is_authorized_code_size: MAX_IS_AUTHORIZED_CODE_SIZE.load(Relaxed) as _,
max_refine_memory: MAX_REFINE_MEMORY.load(Relaxed) as _,
max_is_authorized_memory: MAX_IS_AUTHORIZED_MEMORY.load(Relaxed) as _,
availability_timeout: AVAILABILITY_TIMEOUT.load(Relaxed),
auth_window: AUTH_WINDOW.load(Relaxed) as _,
max_lookup_anchor_age: MAX_LOOKUP_ANCHOR_AGE.load(Relaxed),
}
}
pub fn validate(self) -> Result<jam_types::Parameters, &'static str> {
let r = jam_types::Parameters {
val_count: self.val_count,
basic_piece_len: self.basic_piece_len,
auth_queue_len: self.auth_queue_len,
min_turnaround_period: self.min_turnaround_period,
max_work_items: self.max_work_items,
max_imports: self.max_imports,
max_exports: self.max_exports,
max_extrinsics: self.max_extrinsics,
max_dependencies: self.max_dependencies,
max_input: self.max_input,
};
r.validate()?;
if self.epoch_period % self.rotation_period != 0 {
return Err("`rotation_period` does not divide into `epoch_period`")
}
if self.val_count as usize % VALS_PER_CORE != 0 {
return Err("`val_count` does not divide by `VALS_PER_CORE` (3)")
}
if recent_block_count() > 255 {
return Err("`recent_block_count` may be no larger than `BlockIndex::MAX` (255)")
}
Ok(r)
}
pub fn apply(self) -> Result<(), &'static str> {
let base = self.validate()?;
base.apply()?;
EPOCH_PERIOD.store(self.epoch_period, Relaxed);
ROTATION_PERIOD.store(self.rotation_period, Relaxed);
BLOCK_GAS_LIMIT.store(self.block_gas_limit, Relaxed);
RECENT_BLOCK_COUNT.store(self.recent_block_count, Relaxed);
MAX_TICKETS_PER_BLOCK.store(self.max_tickets_per_block as _, Relaxed);
TICKETS_ATTEMPTS_NUMBER.store(self.tickets_attempts_number, Relaxed);
DEPOSIT_PER_ACCOUNT.store(self.deposit_per_account, Relaxed);
DEPOSIT_PER_ITEM.store(self.deposit_per_item, Relaxed);
DEPOSIT_PER_BYTE.store(self.deposit_per_byte, Relaxed);
MAX_IS_AUTHORIZED_GAS.store(self.max_is_authorized_gas, Relaxed);
MAX_REFINE_GAS.store(self.max_refine_gas, Relaxed);
MAX_ACCUMULATE_GAS.store(self.max_accumulate_gas, Relaxed);
MAX_REFINE_CODE_SIZE.store(self.max_refine_code_size as _, Relaxed);
MAX_IS_AUTHORIZED_CODE_SIZE.store(self.max_is_authorized_code_size as _, Relaxed);
MAX_REFINE_MEMORY.store(self.max_refine_memory as _, Relaxed);
MAX_IS_AUTHORIZED_MEMORY.store(self.max_is_authorized_memory as _, Relaxed);
RECENT_BLOCK_COUNT.store(self.recent_block_count, Relaxed);
AVAILABILITY_TIMEOUT.store(self.availability_timeout, Relaxed);
AUTH_WINDOW.store(self.auth_window as _, Relaxed);
MAX_LOOKUP_ANCHOR_AGE.store(self.max_lookup_anchor_age, Relaxed);
Ok(())
}
}
pub const SANE_MAX_PACKAGE_SIZE: usize = 100 * 1024;
pub const MAX_REPORT_ELECTIVE_DATA: usize = 48 * 1024;
pub const GUARANTEE_MIN_SIGNATURES: usize = (VALS_PER_CORE * 2).div_ceil(3);
opaque! { pub struct Entropy(pub [u8; 32]); }
#[derive(Clone, Encode, Decode, Debug)]
pub struct Block {
pub header: Header,
pub extrinsic: Extrinsic,
}
pub const SUFFIX_SKIP_LEN: usize = 6;
pub const PROVEN_PER_SEGMENT: usize = 1 << SUFFIX_SKIP_LEN;
pub type SegmentSlice = FixedVec<u8, SegmentSliceLen>;
pub type TrancheIndex = u8;