1use crate::{
2 Entropy, Mmr, ReportGuarantee, ValKeysets, WorkReport,
3 bandersnatch::ring_vrf::RingCommitment,
4 hash_raw_concat,
5 safrole::{EpochTicketsAccumulator, TicketsOrKeys},
6};
7use bounded_collections::ConstU32;
8use codec::{Decode, Encode};
9use jam_types::{
10 AuthQueue, AuthWindow, AuthorizerHash, Balance, BoundedVec, CodeHash, CoreCount, EpochPeriod,
11 FOOTPRINT_PREIMAGE_OVERHEAD, FOOTPRINT_STORAGE_OVERHEAD, FixedVec, Hash, HeaderHash,
12 MmrPeakHash, RecentBlockCount, SegmentTreeRoot, ServiceId, ServiceInfo, Slot, StateRootHash,
13 UnsignedGas, VecMap, VecSet, WorkPackageHash, WorkReportHash, deposit_per_account,
14 deposit_per_byte, deposit_per_item, opaque,
15};
16
17opaque! {
18 pub struct StorageKey(pub [u8; 31]);
19}
20
21#[derive(Debug, Encode, Decode, Copy, Clone, Eq, PartialEq)]
22pub enum SystemKey {
23 Reserved0 = 0,
24 AuthPools = 1,
25 AuthQueues = 2,
26 RecentBlocks = 3,
27 Safrole = 4,
28 Disputes = 5,
29 Entropy = 6,
30 Designates = 7,
31 Validators = 8,
32 PrevValidators = 9,
33 Availability = 10,
34 CurrentTime = 11,
35 Privileges = 12,
36 Statistics = 13,
37 ReadyQueue = 14,
38 Accumulated = 15,
39 AccumulationOutput = 16,
40}
41
42impl From<SystemKey> for StorageKey {
43 fn from(value: SystemKey) -> Self {
44 let k = value.encode();
45 let mut r = [0; StorageKey::LEN];
46 r[..k.len()].copy_from_slice(&k[..]);
47 r.into()
48 }
49}
50
51impl IntoStorageKey for SystemKey {}
52
53impl IntoStorageKey for StorageKey {}
54
55#[derive(Clone)]
56pub enum ServiceKey<'a> {
57 Info { id: ServiceId },
58 Value { id: ServiceId, key: &'a [u8] },
59 Request { id: ServiceId, len: u32, hash: [u8; 32] },
60 Preimage { id: ServiceId, hash: [u8; 32] },
61}
62
63pub trait IntoStorageKey: Into<StorageKey> {
64 fn service_id(&self) -> Option<ServiceId> {
65 None
66 }
67}
68
69impl IntoStorageKey for ServiceKey<'_> {
70 fn service_id(&self) -> Option<ServiceId> {
71 Some(match self {
72 Self::Info { id, .. } |
73 Self::Value { id, .. } |
74 Self::Request { id, .. } |
75 Self::Preimage { id, .. } => *id,
76 })
77 }
78}
79
80impl<'a> From<ServiceKey<'a>> for StorageKey {
81 fn from(k: ServiceKey<'a>) -> Self {
82 use ServiceKey::*;
83 let id = match k {
84 Info { id } | Value { id, .. } | Request { id, .. } | Preimage { id, .. } => id,
85 }
86 .to_le_bytes();
87 let mut r = [0; StorageKey::LEN];
88 let hash = match k {
89 Info { .. } => {
90 r[0] = 255;
91 r[1] = id[0];
92 r[3] = id[1];
93 r[5] = id[2];
94 r[7] = id[3];
95 return r.into();
96 },
97 Value { key, .. } => hash_raw_concat([&[0xff, 0xff, 0xff, 0xff], key]),
98 Preimage { hash, .. } => hash_raw_concat([&[0xfe, 0xff, 0xff, 0xff], &hash[..]]),
99 Request { len, hash, .. } => hash_raw_concat([&len.to_le_bytes(), &hash[..]]),
100 };
101 r[..8].copy_from_slice(&[id[0], hash[0], id[1], hash[1], id[2], hash[2], id[3], hash[3]]);
102 r[8..].copy_from_slice(&hash[4..27]);
103 r.into()
104 }
105}
106
107pub fn service_id_from_info_key(key: &[u8]) -> Option<ServiceId> {
111 if key.len() == StorageKey::LEN &&
112 key[0] == 255 &&
113 key[2] == 0 &&
114 key[4] == 0 &&
115 key[6] == 0 &&
116 key[8..] == [0; 23]
117 {
118 Some(ServiceId::from_le_bytes([key[1], key[3], key[5], key[7]]))
119 } else {
120 None
121 }
122}
123
124const SERVICE_VERSION: u8 = 0;
126
127#[derive(Debug, Clone)]
128pub struct Service {
129 pub code_hash: CodeHash,
131 pub balance: Balance,
133 pub min_item_gas: UnsignedGas,
136 pub min_memo_gas: UnsignedGas,
139 pub bytes: u64,
141 pub deposit_offset: Balance,
143 pub items: u32,
145 pub creation_slot: Slot,
147 pub last_accumulation_slot: Slot,
149 pub parent_service: ServiceId,
151}
152
153impl From<Service> for ServiceInfo {
154 fn from(service: Service) -> Self {
155 ServiceInfo {
156 code_hash: service.code_hash,
157 balance: service.balance,
158 min_item_gas: service.min_item_gas,
159 min_memo_gas: service.min_memo_gas,
160 bytes: service.bytes,
161 items: service.items,
162 threshold: service.threshold(),
163 deposit_offset: service.deposit_offset,
164 creation_slot: service.creation_slot,
165 last_accumulation_slot: service.last_accumulation_slot,
166 parent_service: service.parent_service,
167 }
168 }
169}
170
171impl Encode for Service {
172 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
173 dest.push_byte(SERVICE_VERSION);
174 self.code_hash.encode_to(dest);
175 self.balance.encode_to(dest);
176 self.min_item_gas.encode_to(dest);
177 self.min_memo_gas.encode_to(dest);
178 self.bytes.encode_to(dest);
179 self.deposit_offset.encode_to(dest);
180 self.items.encode_to(dest);
181 self.creation_slot.encode_to(dest);
182 self.last_accumulation_slot.encode_to(dest);
183 self.parent_service.encode_to(dest);
184 }
185}
186
187impl Decode for Service {
188 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
189 if u8::decode(input)? != SERVICE_VERSION {
190 return Err("Invalid service version".into())
191 }
192 Ok(Self {
193 code_hash: CodeHash::decode(input)?,
194 balance: Balance::decode(input)?,
195 min_item_gas: UnsignedGas::decode(input)?,
196 min_memo_gas: UnsignedGas::decode(input)?,
197 bytes: u64::decode(input)?,
198 deposit_offset: Balance::decode(input)?,
199 items: u32::decode(input)?,
200 creation_slot: Slot::decode(input)?,
201 last_accumulation_slot: Slot::decode(input)?,
202 parent_service: ServiceId::decode(input)?,
203 })
204 }
205}
206
207impl Service {
208 pub fn threshold(&self) -> Balance {
209 Self::deposit_required(self.items, self.bytes, self.deposit_offset)
210 }
211 pub fn free(&self) -> Balance {
212 self.balance.saturating_sub(self.threshold())
213 }
214 pub fn deposit_required(items: u32, bytes: u64, deposit_offset: Balance) -> Balance {
215 let base_deposit =
216 items as u64 * deposit_per_item() + bytes * deposit_per_byte() + deposit_per_account();
217 base_deposit.saturating_sub(deposit_offset)
218 }
219}
220
221#[derive(Debug, Clone, Copy, Eq, PartialEq)]
223pub enum FootprintItem {
224 None,
226 Storage(u64),
228 Lookup(u32),
230}
231
232impl From<Option<FootprintItem>> for FootprintItem {
233 fn from(item: Option<FootprintItem>) -> Self {
234 item.unwrap_or(Self::None)
235 }
236}
237
238impl FootprintItem {
239 pub fn implication(&self) -> (u32, u64) {
241 match self {
242 Self::None => (0, 0),
243 Self::Storage(size) => (1, *size + FOOTPRINT_STORAGE_OVERHEAD),
244 Self::Lookup(len) => (2, *len as u64 + FOOTPRINT_PREIMAGE_OVERHEAD),
245 }
246 }
247}
248
249#[derive(Encode, Decode, Debug, Clone)]
251pub struct SafroleState {
252 pub waiting_validators: ValKeysets,
254 pub ring_commitment: RingCommitment,
256 pub tickets_or_keys: TicketsOrKeys,
258 pub ticket_accumulator: EpochTicketsAccumulator,
260}
261
262pub type AuthPool = BoundedVec<AuthorizerHash, AuthWindow>;
263pub type AuthPools = FixedVec<AuthPool, CoreCount>;
264pub type AuthQueues = FixedVec<AuthQueue, CoreCount>;
265
266#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone)]
267pub struct AvailabilityAssignment {
268 pub guarantee: ReportGuarantee,
270 pub registered_slot: Slot,
273}
274
275impl AvailabilityAssignment {
276 pub fn report(&self) -> &WorkReport {
278 &self.guarantee.report
279 }
280}
281
282#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
283pub struct Privileges {
284 pub bless: ServiceId,
287 pub assign: FixedVec<ServiceId, CoreCount>,
289 pub designate: ServiceId,
291 pub register: ServiceId,
293 pub always_acc: VecMap<ServiceId, UnsignedGas>,
295}
296
297#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
298pub struct Disputes {
299 pub good: VecSet<WorkReportHash>,
301 pub bad: VecSet<WorkReportHash>,
303 pub wonky: VecSet<WorkReportHash>,
305 pub offenders: VecSet<super::ed25519::Public>,
308}
309
310#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
311pub struct ValActivityRecord {
312 pub blocks: u32,
314 pub tickets: u32,
316 pub preimages: u32,
318 pub preimages_size: u32,
320 pub guarantees: u32,
322 pub assurances: u32,
324}
325
326#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
327pub struct ServiceActivityRecord {
328 #[codec(compact)]
330 pub provided_count: u16,
331 #[codec(compact)]
333 pub provided_size: u32,
334 #[codec(compact)]
336 pub refinement_count: u32,
337 #[codec(compact)]
339 pub refinement_gas_used: UnsignedGas,
340 #[codec(compact)]
342 pub imports: u32,
343 #[codec(compact)]
345 pub extrinsic_count: u32,
346 #[codec(compact)]
348 pub extrinsic_size: u32,
349 #[codec(compact)]
351 pub exports: u32,
352 #[codec(compact)]
354 pub accumulate_count: u32,
355 #[codec(compact)]
357 pub accumulate_transfer_count: u32,
358 #[codec(compact)]
360 pub accumulate_gas_used: UnsignedGas,
361}
362
363#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
364pub struct CoreActivityRecord {
365 #[codec(compact)]
370 pub da_load: u32,
371 #[codec(compact)]
373 pub popularity: u16,
374 #[codec(compact)]
376 pub imports: u16,
377 #[codec(compact)]
379 pub extrinsic_count: u16,
380 #[codec(compact)]
382 pub extrinsic_size: u32,
383 #[codec(compact)]
385 pub exports: u16,
386 #[codec(compact)]
388 pub bundle_size: u32,
389 #[codec(compact)]
392 pub gas_used: UnsignedGas,
393}
394
395pub type ValidatorsStats = BoundedVec<ValActivityRecord, jam_types::MaxValCount>;
396pub type CoresStats = FixedVec<CoreActivityRecord, CoreCount>;
397pub type ServicesStats = VecMap<ServiceId, ServiceActivityRecord>;
398
399#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
400pub struct Statistics {
401 pub vals_curr: ValidatorsStats,
402 pub vals_last: ValidatorsStats,
403 pub cores: CoresStats,
404 pub services: ServicesStats,
405}
406
407impl Statistics {
408 pub fn reset(&mut self) {
410 self.cores = Default::default();
411 self.services = Default::default();
412 }
413}
414
415pub type EntropyBuffer = FixedVec<Entropy, ConstU32<4>>;
420
421#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone)]
423pub struct BlockInfo {
424 pub hash: HeaderHash,
426 pub beefy_root: MmrPeakHash,
428 pub state_root: StateRootHash,
430 pub slot: Slot,
432 pub reported: VecMap<WorkPackageHash, SegmentTreeRoot>,
435}
436
437pub type RecentBlocksHistory = BoundedVec<BlockInfo, RecentBlockCount>;
439
440#[derive(Clone, Encode, Decode, Default, Debug)]
442pub struct RecentBlocks {
443 pub history: RecentBlocksHistory,
444 pub mmr: Mmr,
445}
446
447pub type AvailabilityAssignments = FixedVec<Option<AvailabilityAssignment>, CoreCount>;
448
449#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq)]
450pub struct ReadyRecord {
451 pub report: WorkReport,
452 pub deps: VecSet<WorkPackageHash>,
453}
454pub type ReadyQueue = FixedVec<Vec<ReadyRecord>, EpochPeriod>;
455pub type Accumulated = FixedVec<Vec<WorkPackageHash>, EpochPeriod>;
456
457pub type AccumulationOutput = Vec<(ServiceId, Hash)>;