use crate::{hash_raw_concat, Entropy, Mmr, WorkReport};
use bounded_collections::ConstU32;
use codec::{Decode, Encode};
use jam_types::{
deposit_per_account, deposit_per_byte, deposit_per_item, opaque, AuthQueue, AuthWindow,
AuthorizerHash, Balance, BoundedVec, CodeHash, CoreCount, EpochPeriod, FixedVec, Hash,
HeaderHash, MmrPeakHash, RecentBlockCount, SegmentTreeRoot, ServiceId, ServiceInfo, Slot,
StateRootHash, UnsignedGas, VecMap, VecSet, WorkPackageHash, WorkReportHash,
};
opaque! {
pub struct StorageKey(pub [u8; 31]);
}
#[derive(Debug, Encode, Decode, Copy, Clone, Eq, PartialEq)]
pub enum SystemKey {
Reserved0 = 0,
AuthPools = 1,
AuthQueues = 2,
RecentBlocks = 3,
Safrole = 4,
Disputes = 5,
Entropy = 6,
Designates = 7,
Validators = 8,
PrevValidators = 9,
Availability = 10,
CurrentTime = 11,
Privileges = 12,
Statistics = 13,
ReadyQueue = 14,
Accumulated = 15,
AccumulationOutput = 16,
}
impl From<SystemKey> for StorageKey {
fn from(value: SystemKey) -> Self {
let k = value.encode();
let mut r = [0; StorageKey::LEN];
r[..k.len()].copy_from_slice(&k[..]);
r.into()
}
}
impl IntoStorageKey for SystemKey {}
impl IntoStorageKey for StorageKey {}
#[derive(Clone)]
pub enum ServiceKey<'a> {
Info { id: ServiceId },
Value { id: ServiceId, key: &'a [u8] },
Request { id: ServiceId, len: u32, hash: [u8; 32] },
Preimage { id: ServiceId, hash: [u8; 32] },
}
pub trait IntoStorageKey: Into<StorageKey> {
fn service_id(&self) -> Option<ServiceId> {
None
}
}
impl IntoStorageKey for ServiceKey<'_> {
fn service_id(&self) -> Option<ServiceId> {
Some(match self {
Self::Info { id, .. } |
Self::Value { id, .. } |
Self::Request { id, .. } |
Self::Preimage { id, .. } => *id,
})
}
}
impl<'a> From<ServiceKey<'a>> for StorageKey {
fn from(k: ServiceKey<'a>) -> Self {
use ServiceKey::*;
let id = match k {
Info { id } | Value { id, .. } | Request { id, .. } | Preimage { id, .. } => id,
}
.to_le_bytes();
let mut r = [0; StorageKey::LEN];
let hash = match k {
Info { .. } => {
r[0] = 255;
r[1] = id[0];
r[3] = id[1];
r[5] = id[2];
r[7] = id[3];
return r.into();
},
Value { key, .. } => hash_raw_concat([&[0xff, 0xff, 0xff, 0xff], key]),
Preimage { hash, .. } => hash_raw_concat([&[0xfe, 0xff, 0xff, 0xff], &hash[..]]),
Request { len, hash, .. } => hash_raw_concat([&len.to_le_bytes(), &hash[..]]),
};
r[..8].copy_from_slice(&[id[0], hash[0], id[1], hash[1], id[2], hash[2], id[3], hash[3]]);
r[8..].copy_from_slice(&hash[4..27]);
r.into()
}
}
const SERVICE_VERSION: u8 = 0;
#[derive(Debug, Clone)]
pub struct Service {
pub code_hash: CodeHash,
pub balance: Balance,
pub min_item_gas: UnsignedGas,
pub min_memo_gas: UnsignedGas,
pub bytes: u64,
pub deposit_offset: Balance,
pub items: u32,
pub creation_slot: Slot,
pub last_accumulation_slot: Slot,
pub parent_service: ServiceId,
}
impl From<Service> for ServiceInfo {
fn from(service: Service) -> Self {
ServiceInfo {
code_hash: service.code_hash,
balance: service.balance,
min_item_gas: service.min_item_gas,
min_memo_gas: service.min_memo_gas,
bytes: service.bytes,
items: service.items,
threshold: service.threshold(),
deposit_offset: service.deposit_offset,
creation_slot: service.creation_slot,
last_accumulation_slot: service.last_accumulation_slot,
parent_service: service.parent_service,
}
}
}
impl Encode for Service {
fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
dest.push_byte(SERVICE_VERSION);
self.code_hash.encode_to(dest);
self.balance.encode_to(dest);
self.min_item_gas.encode_to(dest);
self.min_memo_gas.encode_to(dest);
self.bytes.encode_to(dest);
self.deposit_offset.encode_to(dest);
self.items.encode_to(dest);
self.creation_slot.encode_to(dest);
self.last_accumulation_slot.encode_to(dest);
self.parent_service.encode_to(dest);
}
}
impl Decode for Service {
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
if u8::decode(input)? != SERVICE_VERSION {
return Err("Invalid service version".into())
}
Ok(Self {
code_hash: CodeHash::decode(input)?,
balance: Balance::decode(input)?,
min_item_gas: UnsignedGas::decode(input)?,
min_memo_gas: UnsignedGas::decode(input)?,
bytes: u64::decode(input)?,
deposit_offset: Balance::decode(input)?,
items: u32::decode(input)?,
creation_slot: Slot::decode(input)?,
last_accumulation_slot: Slot::decode(input)?,
parent_service: ServiceId::decode(input)?,
})
}
}
impl Service {
pub fn threshold(&self) -> Balance {
Self::deposit_required(self.items, self.bytes, self.deposit_offset)
}
pub fn free(&self) -> Balance {
self.balance.saturating_sub(self.threshold())
}
pub fn deposit_required(items: u32, bytes: u64, deposit_offset: Balance) -> Balance {
let base_deposit =
items as u64 * deposit_per_item() + bytes * deposit_per_byte() + deposit_per_account();
base_deposit.saturating_sub(deposit_offset)
}
}
pub type AuthPool = BoundedVec<AuthorizerHash, AuthWindow>;
pub type AuthPools = FixedVec<AuthPool, CoreCount>;
pub type AuthQueues = FixedVec<AuthQueue, CoreCount>;
#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone)]
pub struct AvailabilityAssignment {
pub report: WorkReport,
pub report_slot: Slot,
}
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
pub struct Privileges {
pub bless: ServiceId,
pub assign: FixedVec<ServiceId, CoreCount>,
pub designate: ServiceId,
pub register: ServiceId,
pub always_acc: VecMap<ServiceId, UnsignedGas>,
}
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
pub struct Disputes {
pub good: VecSet<WorkReportHash>,
pub bad: VecSet<WorkReportHash>,
pub wonky: VecSet<WorkReportHash>,
pub offenders: VecSet<super::ed25519::Public>,
}
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
pub struct ValActivityRecord {
pub blocks: u32,
pub tickets: u32,
pub preimages: u32,
pub preimages_size: u32,
pub guarantees: u32,
pub assurances: u32,
}
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
pub struct ServiceActivityRecord {
#[codec(compact)]
pub provided_count: u16,
#[codec(compact)]
pub provided_size: u32,
#[codec(compact)]
pub refinement_count: u32,
#[codec(compact)]
pub refinement_gas_used: UnsignedGas,
#[codec(compact)]
pub imports: u32,
#[codec(compact)]
pub extrinsic_count: u32,
#[codec(compact)]
pub extrinsic_size: u32,
#[codec(compact)]
pub exports: u32,
#[codec(compact)]
pub accumulate_count: u32,
#[codec(compact)]
pub accumulate_gas_used: UnsignedGas,
}
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
pub struct CoreActivityRecord {
#[codec(compact)]
pub da_load: u32,
#[codec(compact)]
pub popularity: u16,
#[codec(compact)]
pub imports: u16,
#[codec(compact)]
pub extrinsic_count: u16,
#[codec(compact)]
pub extrinsic_size: u32,
#[codec(compact)]
pub exports: u16,
#[codec(compact)]
pub bundle_size: u32,
#[codec(compact)]
pub gas_used: UnsignedGas,
}
pub type ValidatorsStats = FixedVec<ValActivityRecord, jam_types::ValCount>;
pub type CoresStats = FixedVec<CoreActivityRecord, CoreCount>;
pub type ServicesStats = VecMap<ServiceId, ServiceActivityRecord>;
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
pub struct Statistics {
pub vals_curr: ValidatorsStats,
pub vals_last: ValidatorsStats,
pub cores: CoresStats,
pub services: ServicesStats,
}
impl Statistics {
pub fn reset(&mut self) {
self.cores = Default::default();
self.services = Default::default();
}
}
pub type EntropyBuffer = FixedVec<Entropy, ConstU32<4>>;
#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone)]
pub struct BlockInfo {
pub hash: HeaderHash,
pub beefy_root: MmrPeakHash,
pub state_root: StateRootHash,
pub reported: VecMap<WorkPackageHash, SegmentTreeRoot>,
}
pub type RecentBlocksHistory = BoundedVec<BlockInfo, RecentBlockCount>;
#[derive(Clone, Encode, Decode, Default, Debug)]
pub struct RecentBlocks {
pub history: RecentBlocksHistory,
pub mmr: Mmr,
}
pub type AvailabilityAssignments = FixedVec<Option<AvailabilityAssignment>, CoreCount>;
#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
pub struct ReadyRecord {
pub report: WorkReport,
pub deps: VecSet<WorkPackageHash>,
}
pub type ReadyQueue = FixedVec<Vec<ReadyRecord>, EpochPeriod>;
pub type Accumulated = FixedVec<Vec<WorkPackageHash>, EpochPeriod>;
pub type AccumulationOutput = Vec<(ServiceId, Hash)>;