1use crate::{
2 deposit_per_account, deposit_per_byte, deposit_per_item, hash_encoded, hash_raw_concat,
3 simple::AuthWindow, CoreCount, Entropy, EpochPeriod, Mmr, RecentBlockCount, WorkReport,
4};
5use bounded_collections::ConstU32;
6use jam_types::{
7 opaque, AuthQueue, AuthorizerHash, Balance, BoundedVec, CodeHash, FixedVec, HeaderHash,
8 SegmentTreeRoot, ServiceId, ServiceInfo, Slot, StateRootHash, UnsignedGas, VecMap, VecSet,
9 WorkPackageHash, WorkReportHash,
10};
11use scale::{Decode, Encode};
12
13opaque! {
14 pub struct StorageKey(pub [u8; 32]);
15}
16
17#[derive(Debug, Encode, Decode, Copy, Clone, Eq, PartialEq)]
18pub enum SystemKey {
19 Reserved0 = 0,
20 AuthPools = 1,
21 AuthQueues = 2,
22 RecentBlocks = 3,
23 Safrole = 4,
24 Disputes = 5,
25 Entropy = 6,
26 Designates = 7,
27 Validators = 8,
28 PrevValidators = 9,
29 Availability = 10,
30 CurrentTime = 11,
31 Privileges = 12,
32 Statistics = 13,
33 ReadyQueue = 14,
34 Accumulated = 15,
35}
36
37impl From<SystemKey> for StorageKey {
38 fn from(value: SystemKey) -> Self {
39 let k = value.encode();
40 let mut r = [0; 32];
41 r[..k.len()].copy_from_slice(&k[..]);
42 r.into()
43 }
44}
45
46impl IntoStorageKey for SystemKey {
47 fn service_id(&self) -> Option<ServiceId> {
48 None
49 }
50}
51
52#[derive(Clone)]
53pub enum ServiceKey<'a> {
54 Info { id: ServiceId },
55 Value { id: ServiceId, key: &'a [u8] },
56 Request { id: ServiceId, len: u32, hash: [u8; 32] },
57 Preimage { id: ServiceId, hash: [u8; 32] },
58}
59
60pub trait IntoStorageKey: Into<StorageKey> {
61 fn service_id(&self) -> Option<ServiceId>;
62}
63
64impl IntoStorageKey for ServiceKey<'_> {
65 fn service_id(&self) -> Option<ServiceId> {
66 Some(match self {
67 Self::Info { id, .. } |
68 Self::Value { id, .. } |
69 Self::Request { id, .. } |
70 Self::Preimage { id, .. } => *id,
71 })
72 }
73}
74
75impl<'a> From<ServiceKey<'a>> for StorageKey {
76 fn from(k: ServiceKey<'a>) -> Self {
77 use ServiceKey::*;
78 let id = match k {
79 Info { id } | Value { id, .. } | Request { id, .. } | Preimage { id, .. } => id,
80 }
81 .to_le_bytes();
82 let mut r = [0; 32];
83 let hash = match k {
84 Info { .. } => {
85 r[0] = 255;
86 r[1] = id[0];
87 r[3] = id[1];
88 r[5] = id[2];
89 r[7] = id[3];
90 return r.into();
91 },
92 Value { id, key } => {
93 let mut hash = hash_raw_concat([&id.to_le_bytes()[..], key]);
94 hash.copy_within(0..28, 4);
95 hash[..4].copy_from_slice(&[0xff, 0xff, 0xff, 0xff]);
96 hash
97 },
98 Preimage { mut hash, .. } => {
99 hash.copy_within(1..29, 4);
100 hash[..4].copy_from_slice(&[0xfe, 0xff, 0xff, 0xff]);
101 hash
102 },
103 Request { len, hash, .. } => {
104 let mut hash = hash_encoded(&hash);
105 hash.copy_within(2..30, 4);
106 hash[..4].copy_from_slice(&len.to_le_bytes());
107 hash
108 },
109 };
110 r[8..].copy_from_slice(&hash[4..28]);
111 r[..8].copy_from_slice(&[id[0], hash[0], id[1], hash[1], id[2], hash[2], id[3], hash[3]]);
112 r.into()
113 }
114}
115
116#[derive(Debug, Clone, Encode, Decode)]
117pub struct Service {
118 pub code_hash: CodeHash,
120 pub balance: Balance,
122 pub min_item_gas: UnsignedGas,
125 pub min_memo_gas: UnsignedGas,
128 pub bytes: u64,
130 pub items: u32,
132}
133
134impl From<Service> for ServiceInfo {
135 fn from(service: Service) -> Self {
136 ServiceInfo {
137 code_hash: service.code_hash,
138 balance: service.balance,
139 min_item_gas: service.min_item_gas,
140 min_memo_gas: service.min_memo_gas,
141 bytes: service.bytes,
142 items: service.items,
143 threshold: service.threshold(),
144 }
145 }
146}
147
148impl Service {
149 pub fn new(
150 code_hash: CodeHash,
151 code_len: impl Into<u32>,
152 min_item_gas: UnsignedGas,
153 min_memo_gas: UnsignedGas,
154 ) -> Self {
155 let (items, bytes) = FootprintItem::Lookup(code_len.into()).implication();
156 Self {
157 code_hash,
158 min_item_gas,
159 min_memo_gas,
160 balance: deposit_required(items, bytes),
161 items,
162 bytes,
163 }
164 }
165 pub fn balance(&self) -> Balance {
166 self.balance
167 }
168 pub fn lower_balance(&mut self, amount: Balance) -> Result<(), ()> {
169 if self.free() < amount {
170 return Err(())
171 }
172 self.balance = self.balance.checked_sub(amount).ok_or(())?;
173 Ok(())
174 }
175 pub fn raise_balance(&mut self, amount: Balance) {
176 self.balance = self.balance.saturating_add(amount);
177 }
178 pub fn prepare_change_state(
179 &mut self,
180 remove: FootprintItem,
181 add: FootprintItem,
182 ) -> Result<(), ()> {
183 let (aitems, abytes) = add.implication();
184 let (sitems, sbytes) = remove.implication();
185 let new_items = self.items.saturating_sub(sitems).saturating_add(aitems);
186 let new_bytes = self.bytes.saturating_sub(sbytes).saturating_add(abytes);
187 if self.balance < deposit_required(new_items, new_bytes) {
188 return Err(())
189 }
190 self.items = new_items;
191 self.bytes = new_bytes;
192 Ok(())
193 }
194 pub fn prepare_insert_state(&mut self, add: FootprintItem) -> Result<(), ()> {
195 self.prepare_change_state(FootprintItem::None, add)
196 }
197 pub fn prepare_remove_state(&mut self, remove: FootprintItem) {
198 let (items, bytes) = remove.implication();
199 self.items = self.items.saturating_sub(items);
200 self.bytes = self.bytes.saturating_sub(bytes);
201 }
202 pub fn footprint_is_one_preimage(&self) -> Option<u64> {
203 let (items, bytes) = FootprintItem::Lookup(0).implication();
204 if self.items == items && self.bytes >= bytes {
205 Some(self.bytes - bytes)
206 } else {
207 None
208 }
209 }
210
211 pub fn threshold(&self) -> Balance {
212 deposit_required(self.items, self.bytes)
213 }
214 pub fn free(&self) -> Balance {
215 self.balance.saturating_sub(self.threshold())
216 }
217}
218
219fn deposit_required(items: u32, bytes: u64) -> u64 {
220 items as u64 * deposit_per_item() + bytes * deposit_per_byte() + deposit_per_account()
221}
222
223#[derive(Debug, Clone, Copy)]
224pub enum FootprintItem {
225 None,
226 Storage(usize),
227 Lookup(u32),
228}
229impl From<Option<FootprintItem>> for FootprintItem {
230 fn from(i: Option<FootprintItem>) -> Self {
231 i.unwrap_or(Self::None)
232 }
233}
234impl FootprintItem {
235 pub fn implication(&self) -> (u32, u64) {
236 match self {
237 Self::None => (0, 0),
238 Self::Storage(s) => (1, *s as u64 + 32),
239 Self::Lookup(s) => (2, *s as u64 + 81),
240 }
241 }
242}
243
244pub type AuthPool = BoundedVec<AuthorizerHash, AuthWindow>;
245pub type AuthPools = FixedVec<AuthPool, CoreCount>;
246pub type AuthQueues = FixedVec<AuthQueue, CoreCount>;
247
248#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone)]
250pub struct BlockInfo {
251 pub hash: HeaderHash,
253 pub beefy_mmr: Mmr,
255 pub state_root: StateRootHash,
257 pub reported: VecMap<WorkPackageHash, SegmentTreeRoot>,
260}
261
262#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone)]
263pub struct AvailabilityAssignment {
264 pub report: WorkReport,
266 pub report_slot: Slot,
268}
269
270#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
271pub struct Privileges {
272 pub bless: ServiceId,
274 pub assign: ServiceId,
276 pub designate: ServiceId,
278 pub always_acc: VecMap<ServiceId, UnsignedGas>,
280}
281
282#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
283pub struct Disputes {
284 pub good: VecSet<WorkReportHash>,
286 pub bad: VecSet<WorkReportHash>,
288 pub wonky: VecSet<WorkReportHash>,
290 pub offenders: VecSet<super::ed25519::Public>,
293}
294
295#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
296pub struct ValActivityRecord {
297 pub blocks: u32,
299 pub tickets: u32,
301 pub preimages: u32,
303 pub preimages_size: u32,
305 pub guarantees: u32,
307 pub assurances: u32,
309}
310
311#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
312pub struct ServiceActivityRecord {
313 #[codec(compact)]
315 pub provided_count: u16,
316 #[codec(compact)]
318 pub provided_size: u32,
319 #[codec(compact)]
321 pub refinement_count: u32,
322 #[codec(compact)]
324 pub refinement_gas_used: UnsignedGas,
325 #[codec(compact)]
327 pub imports: u32,
328 #[codec(compact)]
330 pub exports: u32,
331 #[codec(compact)]
333 pub extrinsic_size: u32,
334 #[codec(compact)]
336 pub extrinsic_count: u32,
337 #[codec(compact)]
339 pub accumulate_count: u32,
340 #[codec(compact)]
342 pub accumulate_gas_used: UnsignedGas,
343 #[codec(compact)]
345 pub on_transfers_count: u32,
346 #[codec(compact)]
348 pub on_transfers_gas_used: UnsignedGas,
349}
350
351#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
352pub struct CoreActivityRecord {
353 #[codec(compact)]
358 pub da_load: u32,
359 #[codec(compact)]
361 pub popularity: u16,
362 #[codec(compact)]
364 pub imports: u16,
365 #[codec(compact)]
367 pub exports: u16,
368 #[codec(compact)]
370 pub extrinsic_size: u32,
371 #[codec(compact)]
373 pub extrinsic_count: u16,
374 #[codec(compact)]
376 pub bundle_size: u32,
377 #[codec(compact)]
380 pub gas_used: UnsignedGas,
381}
382
383pub type CoresStats = FixedVec<CoreActivityRecord, CoreCount>;
384pub type ServicesStats = VecMap<ServiceId, ServiceActivityRecord>;
385
386#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
387pub struct Statistics {
388 pub vals_current: FixedVec<ValActivityRecord, jam_types::ValCount>,
389 pub vals_last: FixedVec<ValActivityRecord, jam_types::ValCount>,
390 pub cores: CoresStats,
391 pub services: ServicesStats,
392}
393
394impl Statistics {
395 pub fn reset(&mut self) {
397 self.cores = Default::default();
398 self.services = Default::default();
399 }
400}
401
402pub type EntropyBuffer = FixedVec<Entropy, ConstU32<4>>;
407
408pub type RecentBlocks = BoundedVec<BlockInfo, RecentBlockCount>;
409
410pub type AvailabilityAssignments = FixedVec<Option<AvailabilityAssignment>, CoreCount>;
411
412#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
413pub struct ReadyRecord {
414 pub report: WorkReport,
415 pub deps: VecSet<WorkPackageHash>,
416}
417pub type ReadyQueue = FixedVec<Vec<ReadyRecord>, EpochPeriod>;
418pub type Accumulated = FixedVec<Vec<WorkPackageHash>, EpochPeriod>;