Skip to main content

jam_std_common/
simple.rs

1use super::{
2	extrinsic::{AssurancesXt, DisputesXt, GuaranteesXt, TicketsXt},
3	Extrinsic, Header,
4};
5use codec::{Compact, Decode, Encode, MaxEncodedLen};
6use jam_types::{
7	max_export_segments, max_imports, opaque, segment_len, segment_slice_len, slot_period_sec,
8	Slot, WorkPackage, MAX_PREIMAGE_LEN, PROVEN_PER_SEGMENT, VALS_PER_CORE,
9};
10use std::{sync::Arc, time::Duration};
11
12/// Duration of a time slot, as a Rust-native `Duration`.
13pub fn slot_duration() -> Duration {
14	Duration::from_secs(slot_period_sec())
15}
16
17pub fn max_import_proof_size() -> usize {
18	// 6 hashes of page proof path + 6 hashes or segment tree path + 1 byte for size encoding
19	(PROVEN_PER_SEGMENT.next_power_of_two().ilog2() +
20		(max_imports() as usize)
21			.div_ceil(PROVEN_PER_SEGMENT)
22			.next_power_of_two()
23			.ilog2()) as usize *
24		32 + 1
25}
26
27/// Availability store data expiration in slots (28 days)
28pub fn availability_data_expiration() -> Slot {
29	28 * 24 * 60 * 60 / slot_period_sec() as Slot
30}
31
32/// The conservative maximum size of a Work Package Bundle.
33pub fn max_bundle_size() -> usize {
34	// Note that WorkPackage::max_encoded_len() includes max_input() so we don't need to explicitly
35	// include it here. This assumes a somewhat naive WorkPackage::max_encoded_len implementation,
36	// that doesn't eg account for the fact that if there are many import specs, some of the
37	// max_input() allowance will be used up by the imported segments. If
38	// WorkPackage::max_encoded_len is made less conservative, this function may need to be
39	// updated.
40	WorkPackage::max_encoded_len() + max_import_proof_size() * max_imports() as usize
41}
42
43/// Conservative upper bound on the encoded size of a `Block`.
44///
45/// Sum of `MaxEncodedLen` of each bounded `Extrinsic` field plus a fixed cap on the total
46/// preimage data per block (`MAX_PREIMAGE_LEN`).
47pub fn max_block_size() -> usize {
48	Header::max_encoded_len() +
49		TicketsXt::max_encoded_len() +
50		AssurancesXt::max_encoded_len() +
51		GuaranteesXt::max_encoded_len() +
52		DisputesXt::max_encoded_len() +
53		MAX_PREIMAGE_LEN +
54		Compact::<u32>::max_encoded_len() // Length prefix for Vec<Preimage>
55}
56
57/// Maximum basic size of a Work Package that we accept.
58/// This should be at least ImportSpec::encoded_fixed_size() * max_imports()
59pub const SANE_MAX_PACKAGE_SIZE: usize = 200 * 1024;
60
61/// The min. no. of signatures required for a guarantee to be valid.
62///
63/// Equals 2/3 of guarantors assigned to a core.
64pub const GUARANTEE_MIN_SIGNATURES: usize = (VALS_PER_CORE * 2).div_ceil(3);
65
66// Entropy required by some protocol's operations.
67opaque! { pub struct Entropy(pub [u8; 32]); }
68
69#[derive(Clone, Debug, Encode, Decode)]
70pub struct Block {
71	pub header: Arc<Header>,
72	pub extrinsic: Arc<Extrinsic>,
73}
74
75/// Type to represent the index of a tranche.
76pub type TrancheIndex = u8;
77
78/// Maximum size in bytes for a work package segments shard
79pub fn max_segment_slice_vec_bytes() -> u32 {
80	segment_slice_len() as u32 * max_export_segments()
81}
82
83/// Maximum size in bytes for a work package exported segments
84pub fn max_segment_vec_bytes() -> u32 {
85	segment_len() as u32 * max_export_segments()
86}
87
88/// Segment shard vector. Size is bound by the maximum number of segments a work package may
89/// export.
90#[derive(Clone, Debug, Default, Eq, PartialEq)]
91pub struct SegmentSliceVec(Vec<u8>);
92
93impl SegmentSliceVec {
94	/// Get raw byte buffer that contains all segments.
95	pub fn raw(&self) -> &[u8] {
96		&self.0
97	}
98
99	/// Get the underlying `Vec`.
100	pub fn into_inner(self) -> Vec<u8> {
101		self.0
102	}
103
104	/// Creates a slice vec from serialized bytes. Returns `None` if the size is incorrect.
105	pub fn from_bytes(data: Vec<u8>) -> Option<Self> {
106		if data.len() > segment_slice_len() * max_export_segments() as usize {
107			return None
108		}
109		if !data.len().is_multiple_of(segment_slice_len()) {
110			return None
111		}
112		Some(Self(data))
113	}
114
115	/// Preallocates a vec for the given number of slices
116	pub fn with_capacity(capacity: usize) -> Self {
117		Self(Vec::with_capacity(capacity * segment_slice_len()))
118	}
119
120	/// Returns the number of slices.
121	pub fn len(&self) -> usize {
122		self.0.len() / segment_slice_len()
123	}
124
125	/// Check if the vec is empty.
126	pub fn is_empty(&self) -> bool {
127		self.0.is_empty()
128	}
129
130	/// Appends a slice to this vec. Returns an error is the slice size is incorrect or if the vec
131	/// overflows
132	pub fn push(&mut self, slice: &[u8]) -> Result<(), &'static str> {
133		if slice.len() != segment_slice_len() {
134			return Err("Slice length does not match segment slice length")
135		}
136		if slice.len() + self.0.len() > max_segment_slice_vec_bytes() as usize {
137			return Err("Exceeded maximum segment slice vector size")
138		}
139		self.0.extend_from_slice(slice);
140		Ok(())
141	}
142
143	/// Adds a new empty slice to the vec and returns a reference to it. Produces an error if the
144	/// vec overflows.
145	pub fn push_default(&mut self) -> Result<&mut [u8], &'static str> {
146		if segment_slice_len() + self.0.len() > max_segment_slice_vec_bytes() as usize {
147			return Err("Exceeded maximum segment slice vector size")
148		}
149		let len = self.0.len();
150		self.0.resize(len + segment_slice_len(), 0u8);
151		Ok(&mut self.0[len..])
152	}
153}
154
155impl std::ops::Index<usize> for SegmentSliceVec {
156	type Output = [u8];
157	fn index(&self, index: usize) -> &Self::Output {
158		&self.0[index * segment_slice_len()..(index + 1) * segment_slice_len()]
159	}
160}