jam_std_common/
state.rs

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
101/// Current service struct version.
102const SERVICE_VERSION: u8 = 0;
103
104#[derive(Debug, Clone)]
105pub struct Service {
106	/// The hash of the code of the service.
107	pub code_hash: CodeHash,
108	/// The existing balance of the service.
109	pub balance: Balance,
110	/// The minimum amount of gas which must be provided to this service's `accumulate` for each
111	/// work item it must process.
112	pub min_item_gas: UnsignedGas,
113	/// The minimum amount of gas which must be provided to this service's `accumulate` for each
114	/// incoming transfer it must process.
115	pub min_memo_gas: UnsignedGas,
116	/// The total number of bytes used for data electively held for this service on-chain.
117	pub bytes: u64,
118	/// Offset of storage footprint only above which a minimum deposit is needed.
119	pub deposit_offset: Balance,
120	/// The total number of items of data electively held for this service on-chain.
121	pub items: u32,
122	/// Creation time slot.
123	pub creation_slot: Slot,
124	/// Most recent accumulation time slot.
125	pub last_accumulation_slot: Slot,
126	/// Parent service identifier.
127	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	/// Work report.
205	pub report: WorkReport,
206	/// Timeslot when `report` has been reported.
207	pub report_slot: Slot,
208}
209
210#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
211pub struct Privileges {
212	/// The service index with the ability to alter the privileges as well as bestow services with
213	/// storage deposit credits.
214	pub bless: ServiceId,
215	/// The service indices with the ability to assign authorizors to cores.
216	pub assign: FixedVec<ServiceId, CoreCount>,
217	/// The service index with the ability to set the staging validator keys.
218	pub designate: ServiceId,
219	/// The service index with the ability to register service ids in the protected range.
220	pub register: ServiceId,
221	/// The services which always accumulate, together with their free gas.
222	pub always_acc: VecMap<ServiceId, UnsignedGas>,
223}
224
225#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
226pub struct Disputes {
227	/// The allow-set of work-reports, these are known to be good.
228	pub good: VecSet<WorkReportHash>,
229	/// The corrupt-set of work-reports, these are known to be bad.
230	pub bad: VecSet<WorkReportHash>,
231	/// The ban-set of work-reports, these have been determined of uncertain validity.
232	pub wonky: VecSet<WorkReportHash>,
233	/// The offenders' Ed25519 keys, these are known to have incorrectly judged a work-report's
234	/// validity.
235	pub offenders: VecSet<super::ed25519::Public>,
236}
237
238#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
239pub struct ValActivityRecord {
240	// The number of blocks produced by the validator.
241	pub blocks: u32,
242	// The number of tickets introduced by the validator.
243	pub tickets: u32,
244	// The number of preimages introduced by the validator.
245	pub preimages: u32,
246	// The total number of octets across all preimages introduced by the validator.
247	pub preimages_size: u32,
248	// The number of reports guaranteed by the validator.
249	pub guarantees: u32,
250	// The number of availability assurances made by the validator.
251	pub assurances: u32,
252}
253
254#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
255pub struct ServiceActivityRecord {
256	/// Number of preimages provided to this service.
257	#[codec(compact)]
258	pub provided_count: u16,
259	/// Total size of preimages provided to this service.
260	#[codec(compact)]
261	pub provided_size: u32,
262	/// Number of work-items refined by service for reported work.
263	#[codec(compact)]
264	pub refinement_count: u32,
265	/// Amount of gas used for refinement by service for reported work.
266	#[codec(compact)]
267	pub refinement_gas_used: UnsignedGas,
268	/// Number of segments imported from the DL by service for reported work.
269	#[codec(compact)]
270	pub imports: u32,
271	/// Total number of extrinsics used by service for reported work.
272	#[codec(compact)]
273	pub extrinsic_count: u32,
274	/// Total size of extrinsics used by service for reported work.
275	#[codec(compact)]
276	pub extrinsic_size: u32,
277	/// Number of segments exported into the DL by service for reported work.
278	#[codec(compact)]
279	pub exports: u32,
280	/// Number of work-items accumulated by service.
281	#[codec(compact)]
282	pub accumulate_count: u32,
283	/// Amount of gas used for accumulation by service.
284	#[codec(compact)]
285	pub accumulate_gas_used: UnsignedGas,
286}
287
288#[derive(Clone, Encode, Decode, Debug, Eq, PartialEq, Default)]
289pub struct CoreActivityRecord {
290	// Assurances coming in from general validators (but ultimately provided by guarantors)
291	/// Amount of bytes which are placed into either Audits or Segments DA.
292	/// This includes the work-bundle (including all extrinsics and imports) as well as all
293	/// (exported) segments.
294	#[codec(compact)]
295	pub da_load: u32,
296	/// Number of validators which formed super-majority for assurance.
297	#[codec(compact)]
298	pub popularity: u16,
299	/// Number of segments imported from DA made by core for reported work.
300	#[codec(compact)]
301	pub imports: u16,
302	/// Total number of extrinsics used by core for reported work.
303	#[codec(compact)]
304	pub extrinsic_count: u16,
305	/// Total size of extrinsics used by core for reported work.
306	#[codec(compact)]
307	pub extrinsic_size: u32,
308	/// Number of segments exported into DA made by core for reported work.
309	#[codec(compact)]
310	pub exports: u16,
311	/// The work-bundle size. This is the size of data being placed into Audits DA by the core.
312	#[codec(compact)]
313	pub bundle_size: u32,
314	// Reports coming in from guarantors
315	/// Total gas consumed by core for reported work. Includes all refinement and authorizations.
316	#[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	/// Reset the two accumulators.
334	pub fn reset(&mut self) {
335		self.cores = Default::default();
336		self.services = Default::default();
337	}
338}
339
340/// Entries relative to epoch `N`
341/// `[0]`: epoch `N` entropy accumulator. Updated on each block with fresh entropy.
342/// `[i]`, for 1 ≤ i ≤ 3: accumulator snapshot at the begin of epoch  `N-i+1`.
343/// If `N-i+1 < 0` then the corresponding entry is set to some fixed default value.
344pub type EntropyBuffer = FixedVec<Entropy, ConstU32<4>>;
345
346/// Block information.
347#[derive(Debug, Encode, Decode, Eq, PartialEq, Clone)]
348pub struct BlockInfo {
349	/// Header hash.
350	pub hash: HeaderHash,
351	/// Accumulation MMR root.
352	pub beefy_root: MmrPeakHash,
353	/// Posterior state root.
354	pub state_root: StateRootHash,
355	/// Hash of each work report made into the block which is no more than the
356	/// number of cores.
357	pub reported: VecMap<WorkPackageHash, SegmentTreeRoot>,
358}
359
360/// Recent blocks history
361pub type RecentBlocksHistory = BoundedVec<BlockInfo, RecentBlockCount>;
362
363/// Imported blocks information
364#[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)>;