jam_std_common/
simple.rs

1use super::{Extrinsic, Header};
2use core::fmt;
3use jam_types::{
4	chain_params, max_exports, max_imports, max_input, opaque, val_count, Balance, CoreIndex,
5	FixedVec, SegmentSliceLen, Slot, UnsignedGas, ValIndex,
6};
7use scale::{Decode, Encode};
8use std::{sync::atomic::Ordering::Relaxed, time::Duration};
9
10/// Length of a timeslot in nanoseconds.
11pub const SLOT_PERIOD_IN_NS: u64 = 6_000_000_000;
12
13/// Length of a timeslot.
14pub const SLOT_PERIOD: Duration = Duration::from_nanos(SLOT_PERIOD_IN_NS);
15
16/// Index for an attempt at producing a ticket for the right to produce a block.
17pub type TicketAttempt = u8;
18
19#[cfg(feature = "tiny")]
20mod defaults {
21	use super::{Slot, TicketAttempt};
22	pub(super) const EPOCH_PERIOD: Slot = 12;
23	pub(super) const ROTATION_PERIOD: Slot = 4;
24	pub(super) const MAX_TICKETS_PER_BLOCK: usize = 3;
25	pub(super) const TICKETS_ATTEMPTS_NUMBER: TicketAttempt = 3;
26}
27#[cfg(not(feature = "tiny"))]
28mod defaults {
29	use super::{Slot, TicketAttempt};
30	pub(super) const EPOCH_PERIOD: Slot = 600;
31	pub(super) const ROTATION_PERIOD: Slot = 10;
32	pub(super) const MAX_TICKETS_PER_BLOCK: usize = 16;
33	pub(super) const TICKETS_ATTEMPTS_NUMBER: TicketAttempt = 2;
34}
35
36chain_params! {
37	/// The rotation period, defined in number of slots.
38	static ROTATION_PERIOD: _ = _(defaults::ROTATION_PERIOD);
39	pub fn rotation_period() -> Slot;
40	pub struct RotationPeriod; impl Get<_> for _ {}
41
42	/// The epoch period, defined in number of slots.
43	static EPOCH_PERIOD: _ = _(defaults::EPOCH_PERIOD);
44	pub fn epoch_period() -> Slot;
45	pub struct EpochPeriod; impl Get<_> for _ {}
46
47	/// Max tickets allowed to be embedded in each block extrinsic.
48	static MAX_TICKETS_PER_BLOCK: _ = _(defaults::MAX_TICKETS_PER_BLOCK);
49	pub fn max_tickets_per_block() -> usize;
50	pub struct MaxTicketsPerBlock; impl Get<_> for _ {}
51
52	/// Maximum number of tickets which each validator may create.
53	///
54	/// Influences the anonymity of block producers. As all published tickets have a public
55	/// attempt number less than `attempts_number` if two tickets share an attempt number
56	/// then they must belong to two different validators, which reduces anonymity late as
57	/// we approach the epoch tail.
58	static TICKETS_ATTEMPTS_NUMBER: _ = _(defaults::TICKETS_ATTEMPTS_NUMBER);
59	pub fn tickets_attempts_number() -> TicketAttempt;
60
61	static DEPOSIT_PER_ACCOUNT: _ = _(100);
62	pub fn deposit_per_account() -> Balance;
63
64	static DEPOSIT_PER_ITEM: _ = _(10);
65	pub fn deposit_per_item() -> Balance;
66
67	static DEPOSIT_PER_BYTE: _ = _(1);
68	pub fn deposit_per_byte() -> Balance;
69
70	/// The maximum gas which may be used in a single block. At present this is just the product of
71	/// the maximum gas per work-report and the number of cores. In the future it should probably be
72	/// more to account for the possibility of always-accumulate services.
73	static BLOCK_GAS_LIMIT: _ = _(3_500_000_000);
74	pub fn block_gas_limit() -> UnsignedGas;
75
76	/// Maximum gas which may be used to Authorize a single work-package.
77	static MAX_IS_AUTHORIZED_GAS: _ = _(50_000_000);
78	pub fn max_is_authorized_gas() -> UnsignedGas;
79
80	/// Maximum gas which may be used to Refine a single work-report.
81	static MAX_REFINE_GAS: _ = _(5_000_000_000);
82	pub fn max_refine_gas() -> UnsignedGas;
83
84	/// Maximum gas which may be used to Accumulate a single work-report.
85	static MAX_ACCUMULATE_GAS: _ = _(10_000_000);
86	pub fn max_accumulate_gas() -> UnsignedGas;
87
88	static MAX_REFINE_CODE_SIZE: _ = _(10 * 1024 * 1024);
89	pub fn max_refine_code_size() -> usize;
90
91	static MAX_IS_AUTHORIZED_CODE_SIZE: _ = _(64 * 1024);
92	pub fn max_is_authorized_code_size() -> usize;
93
94	static MAX_REFINE_MEMORY: _ = _(1024 * 1024 * 1024);
95	pub fn max_refine_memory() -> usize;
96
97	static MAX_IS_AUTHORIZED_MEMORY: _ = _(256 * 1024);
98	pub fn max_is_authorized_memory() -> usize;
99
100	/// The number of blocks which are kept in the recent block cache. We use a `u8` to index into
101	/// this and therefore it may be no larger than 255.
102	static RECENT_BLOCK_COUNT: _ = _(8);
103	pub fn recent_block_count() -> Slot;
104	pub struct RecentBlockCount; impl Get<_> for _ {}
105
106	/// The number of validators on each core.
107	pub const VALS_PER_CORE: _ = 3;
108	pub fn vals_per_core() -> usize;
109	pub struct ValsPerCore; impl Get<_> for _ {}
110
111	/// Number of cores in the JAM.
112	pub fn core_count() -> CoreIndex {
113		(val_count() as usize / VALS_PER_CORE) as CoreIndex
114	}
115	pub struct CoreCount; impl Get<_> for _ {}
116
117	/// Maximum number of DA segments that a Work Package can produce.
118	pub fn max_export_segments() -> u32 {
119		max_exports() + max_exports().div_ceil(PROVEN_PER_SEGMENT as u32)
120	}
121	pub struct MaxExportSegments; impl Get<_> for _ {}
122
123	/// Maximum number of DA segments that a Work Package can require as imports. This is twice the
124	/// maximum number of imports because each import may require a proof segment.
125	pub fn max_import_segments() -> u32 { max_imports() * 2 }
126	pub struct MaxImportSegments; impl Get<_> for _ {}
127
128	/// The period in timeslots after which reported but unavailable work may be replaced.
129	static AVAILABILITY_TIMEOUT: _ = _(5);
130	pub fn availability_timeout() -> Slot;
131
132	/// Number of items in the authorization window.
133	static AUTH_WINDOW: _ = _(8);
134	pub fn auth_window() -> usize;
135	pub struct AuthWindow; impl Get<_> for _ {}
136
137	/// Maximum age, in blocks, that the lookup anchor may be, taken from the regular anchor.
138	static MAX_LOOKUP_ANCHOR_AGE: _ = _(24 * 600);
139	pub fn max_lookup_anchor_age() -> Slot;
140}
141
142/// The conservative maximum size of a Work Package Bundle. This is basically `MAX_INPUT` plus sone
143/// extra for the import proofs.
144pub fn max_bundle_size() -> usize {
145	max_input() as usize + 1024 * 1024
146}
147
148/// Parameters for the JAM protocol.
149#[derive(
150	Copy, Clone, Eq, PartialEq, Debug, Encode, Decode, serde::Serialize, serde::Deserialize,
151)]
152pub struct Parameters {
153	/// Total number of validators. Must by divisible by guarantor group size (3).
154	pub val_count: ValIndex,
155	/// Number of octets in a basic piece. Must be even and divide into segment length (4,104).
156	pub basic_piece_len: u32,
157	/// Number of authorizations in a queue allocated to a core.
158	pub auth_queue_len: u32,
159	/// Minimum period in blocks between going from becoming `Available` to `Zombie`, and then
160	/// again from `Zombie` to non-existent.
161	pub min_turnaround_period: Slot,
162	/// Maximum number of Work Items in a Work Package.
163	pub max_work_items: u32,
164	/// Maximum number of imports in a Work Package.
165	pub max_imports: u32,
166	/// Maximum number of exports in a Work Package.
167	pub max_exports: u32,
168	/// Maximum number of extrinsics in a Work Package.
169	pub max_extrinsics: u32,
170	/// Maximum number of dependencies (total of prerequisites and SR lookup entries).
171	pub max_dependencies: u32,
172	/// Maximum size of a Work Package together with all extrinsic data and imported segments.
173	pub max_input: u32,
174
175	/// The epoch period, defined in number of slots.
176	pub epoch_period: Slot,
177	/// The rotation period, defined in number of slots.
178	pub rotation_period: Slot,
179	/// Maximum gas which can be processed in a single block.
180	pub block_gas_limit: UnsignedGas,
181	/// The number of blocks which are kept in the recent block cache.
182	pub recent_block_count: Slot,
183	/// Max tickets allowed to be embedded in each block extrinsic.
184	pub max_tickets_per_block: u32,
185	/// The number of distinct tickets which may be created and submitted by each validator on each
186	/// epoch.
187	pub tickets_attempts_number: TicketAttempt,
188	/// The base deposit required to retain an account.
189	pub deposit_per_account: Balance,
190	/// The additional deposit required for each preimage or storage item in an account.
191	pub deposit_per_item: Balance,
192	/// The additional deposit required for each byte of each storage item in an account and
193	/// preimage of an account.
194	pub deposit_per_byte: Balance,
195	/// Maximum gas which may be used to Authorize a single work-package.
196	pub max_is_authorized_gas: UnsignedGas,
197	/// Maximum gas which may be used to Refine a single work-report.
198	pub max_refine_gas: UnsignedGas,
199	/// Maximum gas which may be used to Accumulate a single work-report.
200	pub max_accumulate_gas: UnsignedGas,
201	/// The maximum size of Refine/Accumulate code.
202	pub max_refine_code_size: u32,
203	/// The maximum size of Is-Authorized code.
204	pub max_is_authorized_code_size: u32,
205	/// The maximum amount of RAM which may be used by Refine/Accumulate code.
206	pub max_refine_memory: u32,
207	/// The maximum amount of RAM which may be used by IsAuthorized code.
208	pub max_is_authorized_memory: u32,
209	/// The period in timeslots after which reported but unavailable work may be replaced.
210	pub availability_timeout: Slot,
211	/// Number of items in the authorization window.
212	pub auth_window: u32,
213	/// Maximum age, in blocks, that the lookup anchor may be, taken from the regular anchor.
214	pub max_lookup_anchor_age: Slot,
215}
216impl fmt::Display for Parameters {
217	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218		write!(
219			f,
220			"\n\
221			val_count: {}\n\
222			basic_piece_len: {}\n\
223			auth_queue_len: {}\n\
224			min_turnaround_period: {}\n\
225			max_work_items: {}\n\
226			max_imports: {}\n\
227			max_exports: {}\n\
228			max_extrinsics: {}\n\
229			max_dependencies: {}\n\
230			max_input: {}\n\
231			epoch_period: {}\n\
232			rotation_period: {}\n\
233			block_gas_limit: {}\n\
234			recent_block_count: {}\n\
235			max_tickets_per_block: {}\n\
236			tickets_attempts_number: {}\n\
237			deposit_per_account: {}\n\
238			deposit_per_item: {}\n\
239			deposit_per_byte: {}\n\
240			max_is_authorized_gas: {}\n\
241			max_refine_gas: {}\n\
242			max_accumulate_gas: {}\n\
243			max_refine_code_size: {}\n\
244			max_is_authorized_code_size: {}\n\
245			max_refine_memory: {}\n\
246			max_is_authorized_memory: {}\n\
247			availability_timeout: {}\n\
248			auth_window: {}\n\
249			max_lookup_anchor_age: {}\n\
250			",
251			self.val_count,
252			self.basic_piece_len,
253			self.auth_queue_len,
254			self.min_turnaround_period,
255			self.max_work_items,
256			self.max_imports,
257			self.max_exports,
258			self.max_extrinsics,
259			self.max_dependencies,
260			self.max_input,
261			self.epoch_period,
262			self.rotation_period,
263			self.block_gas_limit,
264			self.recent_block_count,
265			self.max_tickets_per_block,
266			self.tickets_attempts_number,
267			self.deposit_per_account,
268			self.deposit_per_item,
269			self.deposit_per_byte,
270			self.max_is_authorized_gas,
271			self.max_refine_gas,
272			self.max_accumulate_gas,
273			self.max_refine_code_size,
274			self.max_is_authorized_code_size,
275			self.max_refine_memory,
276			self.max_is_authorized_memory,
277			self.availability_timeout,
278			self.auth_window,
279			self.max_lookup_anchor_age,
280		)
281	}
282}
283
284impl Parameters {
285	pub fn tiny() -> Self {
286		Self {
287			val_count: 6,
288			basic_piece_len: 4,
289			auth_queue_len: 80,
290			min_turnaround_period: 28_800,
291			max_work_items: 16,
292			max_imports: 3072,
293			max_exports: 3072,
294			max_extrinsics: 128,
295			max_dependencies: 8,
296			max_input: 12 * 1024 * 1024,
297			epoch_period: 12,
298			rotation_period: 4,
299			block_gas_limit: 20_000_000,
300			recent_block_count: 8,
301			max_tickets_per_block: 3,
302			tickets_attempts_number: 3,
303			deposit_per_account: 100,
304			deposit_per_item: 10,
305			deposit_per_byte: 1,
306			max_is_authorized_gas: 50_000_000,
307			max_refine_gas: 1_600_000_000,
308			max_accumulate_gas: 10_000_000,
309			max_refine_code_size: 10 * 1024 * 1024,
310			max_is_authorized_code_size: 64 * 1024,
311			max_refine_memory: 1024 * 1024 * 1024,
312			max_is_authorized_memory: 256 * 1024,
313			availability_timeout: 5,
314			auth_window: 8,
315			max_lookup_anchor_age: 24 * 600,
316		}
317	}
318	pub fn full() -> Self {
319		Self {
320			val_count: 1023,
321			basic_piece_len: 684,
322			auth_queue_len: 80,
323			min_turnaround_period: 28_800,
324			max_work_items: 16,
325			max_imports: 3072,
326			max_exports: 3072,
327			max_extrinsics: 128,
328			max_dependencies: 8,
329			max_input: 12 * 1024 * 1024,
330			epoch_period: 600,
331			rotation_period: 10,
332			block_gas_limit: 3_500_000_000,
333			recent_block_count: 8,
334			max_tickets_per_block: 16,
335			tickets_attempts_number: 2,
336			deposit_per_account: 100,
337			deposit_per_item: 10,
338			deposit_per_byte: 1,
339			max_is_authorized_gas: 50_000_000,
340			max_refine_gas: 5_000_000_000,
341			max_accumulate_gas: 10_000_000,
342			max_refine_code_size: 10 * 1024 * 1024,
343			max_is_authorized_code_size: 64 * 1024,
344			max_refine_memory: 1024 * 1024 * 1024,
345			max_is_authorized_memory: 256 * 1024,
346			availability_timeout: 5,
347			auth_window: 8,
348			max_lookup_anchor_age: 24 * 600,
349		}
350	}
351	pub fn get() -> Self {
352		let jam_types::Parameters {
353			val_count,
354			basic_piece_len,
355			auth_queue_len,
356			min_turnaround_period,
357			max_work_items,
358			max_imports,
359			max_exports,
360			max_extrinsics,
361			max_dependencies,
362			max_input,
363		} = jam_types::Parameters::get();
364		Self {
365			val_count,
366			basic_piece_len,
367			auth_queue_len,
368			min_turnaround_period,
369			max_work_items,
370			max_imports,
371			max_exports,
372			max_extrinsics,
373			max_dependencies,
374			max_input,
375			epoch_period: EPOCH_PERIOD.load(Relaxed),
376			rotation_period: ROTATION_PERIOD.load(Relaxed),
377			block_gas_limit: BLOCK_GAS_LIMIT.load(Relaxed),
378			recent_block_count: RECENT_BLOCK_COUNT.load(Relaxed),
379			max_tickets_per_block: MAX_TICKETS_PER_BLOCK.load(Relaxed) as _,
380			tickets_attempts_number: TICKETS_ATTEMPTS_NUMBER.load(Relaxed),
381			deposit_per_account: DEPOSIT_PER_ACCOUNT.load(Relaxed),
382			deposit_per_item: DEPOSIT_PER_ITEM.load(Relaxed),
383			deposit_per_byte: DEPOSIT_PER_BYTE.load(Relaxed),
384			max_is_authorized_gas: MAX_IS_AUTHORIZED_GAS.load(Relaxed),
385			max_refine_gas: MAX_REFINE_GAS.load(Relaxed),
386			max_accumulate_gas: MAX_ACCUMULATE_GAS.load(Relaxed),
387			max_refine_code_size: MAX_REFINE_CODE_SIZE.load(Relaxed) as _,
388			max_is_authorized_code_size: MAX_IS_AUTHORIZED_CODE_SIZE.load(Relaxed) as _,
389			max_refine_memory: MAX_REFINE_MEMORY.load(Relaxed) as _,
390			max_is_authorized_memory: MAX_IS_AUTHORIZED_MEMORY.load(Relaxed) as _,
391			availability_timeout: AVAILABILITY_TIMEOUT.load(Relaxed),
392			auth_window: AUTH_WINDOW.load(Relaxed) as _,
393			max_lookup_anchor_age: MAX_LOOKUP_ANCHOR_AGE.load(Relaxed),
394		}
395	}
396	pub fn validate(self) -> Result<jam_types::Parameters, &'static str> {
397		let r = jam_types::Parameters {
398			val_count: self.val_count,
399			basic_piece_len: self.basic_piece_len,
400			auth_queue_len: self.auth_queue_len,
401			min_turnaround_period: self.min_turnaround_period,
402			max_work_items: self.max_work_items,
403			max_imports: self.max_imports,
404			max_exports: self.max_exports,
405			max_extrinsics: self.max_extrinsics,
406			max_dependencies: self.max_dependencies,
407			max_input: self.max_input,
408		};
409		r.validate()?;
410		if self.epoch_period % self.rotation_period != 0 {
411			return Err("`rotation_period` does not divide into `epoch_period`")
412		}
413		if self.val_count as usize % VALS_PER_CORE != 0 {
414			return Err("`val_count` does not divide by `VALS_PER_CORE` (3)")
415		}
416		if recent_block_count() > 255 {
417			return Err("`recent_block_count` may be no larger than `BlockIndex::MAX` (255)")
418		}
419		Ok(r)
420	}
421	pub fn apply(self) -> Result<(), &'static str> {
422		let base = self.validate()?;
423		base.apply()?;
424		EPOCH_PERIOD.store(self.epoch_period, Relaxed);
425		ROTATION_PERIOD.store(self.rotation_period, Relaxed);
426		BLOCK_GAS_LIMIT.store(self.block_gas_limit, Relaxed);
427		RECENT_BLOCK_COUNT.store(self.recent_block_count, Relaxed);
428		MAX_TICKETS_PER_BLOCK.store(self.max_tickets_per_block as _, Relaxed);
429		TICKETS_ATTEMPTS_NUMBER.store(self.tickets_attempts_number, Relaxed);
430		DEPOSIT_PER_ACCOUNT.store(self.deposit_per_account, Relaxed);
431		DEPOSIT_PER_ITEM.store(self.deposit_per_item, Relaxed);
432		DEPOSIT_PER_BYTE.store(self.deposit_per_byte, Relaxed);
433		MAX_IS_AUTHORIZED_GAS.store(self.max_is_authorized_gas, Relaxed);
434		MAX_REFINE_GAS.store(self.max_refine_gas, Relaxed);
435		MAX_ACCUMULATE_GAS.store(self.max_accumulate_gas, Relaxed);
436		MAX_REFINE_CODE_SIZE.store(self.max_refine_code_size as _, Relaxed);
437		MAX_IS_AUTHORIZED_CODE_SIZE.store(self.max_is_authorized_code_size as _, Relaxed);
438		MAX_REFINE_MEMORY.store(self.max_refine_memory as _, Relaxed);
439		MAX_IS_AUTHORIZED_MEMORY.store(self.max_is_authorized_memory as _, Relaxed);
440		RECENT_BLOCK_COUNT.store(self.recent_block_count, Relaxed);
441		AVAILABILITY_TIMEOUT.store(self.availability_timeout, Relaxed);
442		AUTH_WINDOW.store(self.auth_window as _, Relaxed);
443		MAX_LOOKUP_ANCHOR_AGE.store(self.max_lookup_anchor_age, Relaxed);
444		Ok(())
445	}
446}
447
448/// Maximum basic size of a Work Package that we accept.
449pub const SANE_MAX_PACKAGE_SIZE: usize = 100 * 1024;
450
451/// Maximum total output blobs which can be in a Work Report. The maximum encoded size of a Work
452/// Report is this together with the portions which are constant or based on the (very limited)
453/// number of Work Items.
454pub const MAX_REPORT_ELECTIVE_DATA: usize = 48 * 1024;
455
456/// The min. no. of signatures required for a guarantee to be valid.
457///
458/// Equals 2/3 of guarantors assigned to a core.
459pub const GUARANTEE_MIN_SIGNATURES: usize = (VALS_PER_CORE * 2).div_ceil(3);
460
461// Entropy required by some protocol's operations.
462opaque! { pub struct Entropy(pub [u8; 32]); }
463
464#[derive(Clone, Encode, Decode, Debug)]
465pub struct Block {
466	pub header: Header,
467	pub extrinsic: Extrinsic,
468}
469
470/// The maximum number of levels in the implicit tree derived from the segment hashes in a
471/// proof-page.
472//pub const SUFFIX_SKIP_LEN: usize = (SEGMENT_LEN / 2 / 32).trailing_zeros() as usize;
473pub const SUFFIX_SKIP_LEN: usize = 6;
474
475/// The maximum number of segments whose justification can be included in a single segment-sized
476/// proof-page. Basically just the highest power of 2 which when multiplied by 32 (the size of a
477/// hash) leaves enough room from 4104 (the size of a segment) to fit a partial Merkle proof of
478/// 6 branches (6 * 32 = 192) plus the overhead for storing the actual number of hashes (should be
479/// one byte for `PROVEN_PER_SEGMENT < 128`). It turns out that this is 2^6 = 64.
480///
481/// See `max_prefix_proof_len` for the actual formula.
482pub const PROVEN_PER_SEGMENT: usize = 1 << SUFFIX_SKIP_LEN;
483
484pub type SegmentSlice = FixedVec<u8, SegmentSliceLen>;
485
486/// Type to represent the index of a tranche.
487pub type TrancheIndex = u8;