1use crate::{hash_raw_concat, Entropy, Mmr, WorkReport};
2use bounded_collections::ConstU32;
3use codec::{Decode, Encode};
4use jam_types::{
5 deposit_per_account, deposit_per_byte, deposit_per_item, opaque, AuthQueue, AuthWindow,
6 AuthorizerHash, Balance, BoundedVec, CodeHash, CoreCount, EpochPeriod, FixedVec, Hash,
7 HeaderHash, MmrPeakHash, RecentBlockCount, SegmentTreeRoot, ServiceId, ServiceInfo, Slot,
8 StateRootHash, UnsignedGas, VecMap, VecSet, WorkPackageHash, WorkReportHash,
9};
10
11opaque! {
12 pub struct StorageKey(pub [u8; 31]);
13}
14
15#[derive(Debug, Encode, Decode, Copy, Clone, Eq, PartialEq)]
16pub enum SystemKey {
17 Reserved0 = 0,
18 AuthPools = 1,
19 AuthQueues = 2,
20 RecentBlocks = 3,
21 Safrole = 4,
22 Disputes = 5,
23 Entropy = 6,
24 Designates = 7,
25 Validators = 8,
26 PrevValidators = 9,
27 Availability = 10,
28 CurrentTime = 11,
29 Privileges = 12,
30 Statistics = 13,
31 ReadyQueue = 14,
32 Accumulated = 15,
33 AccumulationOutput = 16,
34}
35
36impl From<SystemKey> for StorageKey {
37 fn from(value: SystemKey) -> Self {
38 let k = value.encode();
39 let mut r = [0; StorageKey::LEN];
40 r[..k.len()].copy_from_slice(&k[..]);
41 r.into()
42 }
43}
44
45impl IntoStorageKey for SystemKey {}
46
47impl IntoStorageKey for StorageKey {}
48
49#[derive(Clone)]
50pub enum ServiceKey<'a> {
51 Info { id: ServiceId },
52 Value { id: ServiceId, key: &'a [u8] },
53 Request { id: ServiceId, len: u32, hash: [u8; 32] },
54 Preimage { id: ServiceId, hash: [u8; 32] },
55}
56
57pub trait IntoStorageKey: Into<StorageKey> {
58 fn service_id(&self) -> Option<ServiceId> {
59 None
60 }
61}
62
63impl IntoStorageKey for ServiceKey<'_> {
64 fn service_id(&self) -> Option<ServiceId> {
65 Some(match self {
66 Self::Info { id, .. } |
67 Self::Value { id, .. } |
68 Self::Request { id, .. } |
69 Self::Preimage { id, .. } => *id,
70 })
71 }
72}
73
74impl<'a> From<ServiceKey<'a>> for StorageKey {
75 fn from(k: ServiceKey<'a>) -> Self {
76 use ServiceKey::*;
77 let id = match k {
78 Info { id } | Value { id, .. } | Request { id, .. } | Preimage { id, .. } => id,
79 }
80 .to_le_bytes();
81 let mut r = [0; StorageKey::LEN];
82 let hash = match k {
83 Info { .. } => {
84 r[0] = 255;
85 r[1] = id[0];
86 r[3] = id[1];
87 r[5] = id[2];
88 r[7] = id[3];
89 return r.into();
90 },
91 Value { key, .. } => hash_raw_concat([&[0xff, 0xff, 0xff, 0xff], key]),
92 Preimage { hash, .. } => hash_raw_concat([&[0xfe, 0xff, 0xff, 0xff], &hash[..]]),
93 Request { len, hash, .. } => hash_raw_concat([&len.to_le_bytes(), &hash[..]]),
94 };
95 r[..8].copy_from_slice(&[id[0], hash[0], id[1], hash[1], id[2], hash[2], id[3], hash[3]]);
96 r[8..].copy_from_slice(&hash[4..27]);
97 r.into()
98 }
99}
100
101const SERVICE_VERSION: u8 = 0;
103
104#[derive(Debug, Clone)]
105pub struct Service {
106 pub code_hash: CodeHash,
108 pub balance: Balance,
110 pub min_item_gas: UnsignedGas,
113 pub min_memo_gas: UnsignedGas,
116 pub bytes: u64,
118 pub deposit_offset: Balance,
120 pub items: u32,
122 pub creation_slot: Slot,
124 pub last_accumulation_slot: Slot,
126 pub parent_service: ServiceId,
128}
129
130impl From<Service> for ServiceInfo {
131 fn from(service: Service) -> Self {
132 ServiceInfo {
133 code_hash: service.code_hash,
134 balance: service.balance,
135 min_item_gas: service.min_item_gas,
136 min_memo_gas: service.min_memo_gas,
137 bytes: service.bytes,
138 items: service.items,
139 threshold: service.threshold(),
140 deposit_offset: service.deposit_offset,
141 creation_slot: service.creation_slot,
142 last_accumulation_slot: service.last_accumulation_slot,
143 parent_service: service.parent_service,
144 }
145 }
146}
147
148impl Encode for Service {
149 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
150 dest.push_byte(SERVICE_VERSION);
151 self.code_hash.encode_to(dest);
152 self.balance.encode_to(dest);
153 self.min_item_gas.encode_to(dest);
154 self.min_memo_gas.encode_to(dest);
155 self.bytes.encode_to(dest);
156 self.deposit_offset.encode_to(dest);
157 self.items.encode_to(dest);
158 self.creation_slot.encode_to(dest);
159 self.last_accumulation_slot.encode_to(dest);
160 self.parent_service.encode_to(dest);
161 }
162}
163
164impl Decode for Service {
165 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
166 if u8::decode(input)? != SERVICE_VERSION {
167 return Err("Invalid service version".into())
168 }
169 Ok(Self {
170 code_hash: CodeHash::decode(input)?,
171 balance: Balance::decode(input)?,
172 min_item_gas: UnsignedGas::decode(input)?,
173 min_memo_gas: UnsignedGas::decode(input)?,
174 bytes: u64::decode(input)?,
175 deposit_offset: Balance::decode(input)?,
176 items: u32::decode(input)?,
177 creation_slot: Slot::decode(input)?,
178 last_accumulation_slot: Slot::decode(input)?,
179 parent_service: ServiceId::decode(input)?,
180 })
181 }
182}
183
184impl Service {
185 pub fn threshold(&self) -> Balance {
186 Self::deposit_required(self.items, self.bytes, self.deposit_offset)
187 }
188 pub fn free(&self) -> Balance {
189 self.balance.saturating_sub(self.threshold())
190 }
191 pub fn deposit_required(items: u32, bytes: u64, deposit_offset: Balance) -> Balance {
192 let base_deposit =
193 items as u64 * deposit_per_item() + bytes * deposit_per_byte() + deposit_per_account();
194 base_deposit.saturating_sub(deposit_offset)
195 }
196}
197
198pub type AuthPool = BoundedVec<AuthorizerHash, AuthWindow>;
199pub type AuthPools = FixedVec<AuthPool, CoreCount>;
200pub type AuthQueues = FixedVec<AuthQueue, CoreCount>;
201
202#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone)]
203pub struct AvailabilityAssignment {
204 pub report: WorkReport,
206 pub report_slot: Slot,
208}
209
210#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
211pub struct Privileges {
212 pub bless: ServiceId,
215 pub assign: FixedVec<ServiceId, CoreCount>,
217 pub designate: ServiceId,
219 pub register: ServiceId,
221 pub always_acc: VecMap<ServiceId, UnsignedGas>,
223}
224
225#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
226pub struct Disputes {
227 pub good: VecSet<WorkReportHash>,
229 pub bad: VecSet<WorkReportHash>,
231 pub wonky: VecSet<WorkReportHash>,
233 pub offenders: VecSet<super::ed25519::Public>,
236}
237
238#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
239pub struct ValActivityRecord {
240 pub blocks: u32,
242 pub tickets: u32,
244 pub preimages: u32,
246 pub preimages_size: u32,
248 pub guarantees: u32,
250 pub assurances: u32,
252}
253
254#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
255pub struct ServiceActivityRecord {
256 #[codec(compact)]
258 pub provided_count: u16,
259 #[codec(compact)]
261 pub provided_size: u32,
262 #[codec(compact)]
264 pub refinement_count: u32,
265 #[codec(compact)]
267 pub refinement_gas_used: UnsignedGas,
268 #[codec(compact)]
270 pub imports: u32,
271 #[codec(compact)]
273 pub extrinsic_count: u32,
274 #[codec(compact)]
276 pub extrinsic_size: u32,
277 #[codec(compact)]
279 pub exports: u32,
280 #[codec(compact)]
282 pub accumulate_count: u32,
283 #[codec(compact)]
285 pub accumulate_gas_used: UnsignedGas,
286}
287
288#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
289pub struct CoreActivityRecord {
290 #[codec(compact)]
295 pub da_load: u32,
296 #[codec(compact)]
298 pub popularity: u16,
299 #[codec(compact)]
301 pub imports: u16,
302 #[codec(compact)]
304 pub extrinsic_count: u16,
305 #[codec(compact)]
307 pub extrinsic_size: u32,
308 #[codec(compact)]
310 pub exports: u16,
311 #[codec(compact)]
313 pub bundle_size: u32,
314 #[codec(compact)]
317 pub gas_used: UnsignedGas,
318}
319
320pub type ValidatorsStats = FixedVec<ValActivityRecord, jam_types::ValCount>;
321pub type CoresStats = FixedVec<CoreActivityRecord, CoreCount>;
322pub type ServicesStats = VecMap<ServiceId, ServiceActivityRecord>;
323
324#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
325pub struct Statistics {
326 pub vals_curr: ValidatorsStats,
327 pub vals_last: ValidatorsStats,
328 pub cores: CoresStats,
329 pub services: ServicesStats,
330}
331
332impl Statistics {
333 pub fn reset(&mut self) {
335 self.cores = Default::default();
336 self.services = Default::default();
337 }
338}
339
340pub type EntropyBuffer = FixedVec<Entropy, ConstU32<4>>;
345
346#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone)]
348pub struct BlockInfo {
349 pub hash: HeaderHash,
351 pub beefy_root: MmrPeakHash,
353 pub state_root: StateRootHash,
355 pub reported: VecMap<WorkPackageHash, SegmentTreeRoot>,
358}
359
360pub type RecentBlocksHistory = BoundedVec<BlockInfo, RecentBlockCount>;
362
363#[derive(Clone, Encode, Decode, Default, Debug)]
365pub struct RecentBlocks {
366 pub history: RecentBlocksHistory,
367 pub mmr: Mmr,
368}
369
370pub type AvailabilityAssignments = FixedVec<Option<AvailabilityAssignment>, CoreCount>;
371
372#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
373pub struct ReadyRecord {
374 pub report: WorkReport,
375 pub deps: VecSet<WorkPackageHash>,
376}
377pub type ReadyQueue = FixedVec<Vec<ReadyRecord>, EpochPeriod>;
378pub type Accumulated = FixedVec<Vec<WorkPackageHash>, EpochPeriod>;
379
380pub type AccumulationOutput = Vec<(ServiceId, Hash)>;