jam-std-common 0.1.26

Common datatypes and utilities for the JAM nodes and tooling
Documentation
use super::{Extrinsic, Header};
use codec::{Decode, Encode, MaxEncodedLen};
use jam_types::{
	max_export_segments, max_imports, opaque, segment_len, segment_slice_len, slot_period_sec,
	Segment, WorkPackage, PROVEN_PER_SEGMENT, VALS_PER_CORE,
};
use std::time::Duration;

/// Duration of a time slot, as a Rust-native `Duration`.
pub fn slot_duration() -> Duration {
	Duration::from_secs(slot_period_sec())
}

pub fn max_import_proof_size() -> usize {
	// 6 hashes of page proof path + 6 hashes or segment tree path + 1 byte for size encoding
	(PROVEN_PER_SEGMENT.next_power_of_two().ilog2() +
		(max_imports() as usize)
			.div_ceil(PROVEN_PER_SEGMENT)
			.next_power_of_two()
			.ilog2()) as usize *
		32 + 1
}

/// The conservative maximum size of a Work Package Bundle.
pub fn max_bundle_size() -> usize {
	// Note that WorkPackage::max_encoded_len() includes max_input() so we don't need to explicitly
	// include it here. This assumes a somewhat naive WorkPackage::max_encoded_len implementation,
	// that doesn't eg account for the fact that if there are many import specs, some of the
	// max_input() allowance will be used up by the imported segments. If
	// WorkPackage::max_encoded_len is made less conservative, this function may need to be
	// updated.
	WorkPackage::max_encoded_len() + max_import_proof_size() * max_imports() as usize
}

/// Maximum basic size of a Work Package that we accept.
/// This should be at least ImportSpec::encoded_fixed_size() * max_imports()
pub const SANE_MAX_PACKAGE_SIZE: usize = 200 * 1024;

/// The min. no. of signatures required for a guarantee to be valid.
///
/// Equals 2/3 of guarantors assigned to a core.
pub const GUARANTEE_MIN_SIGNATURES: usize = (VALS_PER_CORE * 2).div_ceil(3);

// Entropy required by some protocol's operations.
opaque! { pub struct Entropy(pub [u8; 32]); }

#[derive(Clone, Encode, Decode, Debug)]
pub struct Block {
	pub header: Header,
	pub extrinsic: Extrinsic,
}

/// Type to represent the index of a tranche.
pub type TrancheIndex = u8;

/// Maximum size in bytes for a work package segments shard
pub fn max_segment_slice_vec_bytes() -> u32 {
	segment_slice_len() as u32 * max_export_segments()
}

/// Maximum size in bytes for a work package exported segments
pub fn max_segment_vec_bytes() -> u32 {
	segment_len() as u32 * max_export_segments()
}

/// Segment shard vector. Size is bound by the maximum number of segments a work package may
/// export.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct SegmentSliceVec(Vec<u8>);

impl SegmentSliceVec {
	/// Get raw byte buffer that contains all segments.
	pub fn raw(&self) -> &[u8] {
		&self.0
	}

	/// Get the underlying `Vec`.
	pub fn into_inner(self) -> Vec<u8> {
		self.0
	}

	/// Creates a slice vec from serialized bytes. Returns `None` if the size is incorrect.
	pub fn from_bytes(data: Vec<u8>) -> Option<Self> {
		if data.len() > segment_slice_len() * max_export_segments() as usize {
			return None
		}
		if !data.len().is_multiple_of(segment_slice_len()) {
			return None
		}
		Some(Self(data))
	}

	/// Preallocates a vec for the given number of slices
	pub fn with_capacity(capacity: usize) -> Self {
		Self(Vec::with_capacity(capacity * segment_slice_len()))
	}

	/// Returns the number of slices.
	pub fn len(&self) -> usize {
		self.0.len() / segment_slice_len()
	}

	/// Check if the vec is empty.
	pub fn is_empty(&self) -> bool {
		self.0.is_empty()
	}

	/// Appends a slice to this vec. Returns an error is the slice size is incorrect or if the vec
	/// overflows
	pub fn push(&mut self, slice: &[u8]) -> Result<(), &'static str> {
		if slice.len() != segment_slice_len() {
			return Err("Slice length does not match segment slice length")
		}
		if slice.len() + self.0.len() > max_segment_slice_vec_bytes() as usize {
			return Err("Exceeded maximum segment slice vector size")
		}
		self.0.extend_from_slice(slice);
		Ok(())
	}

	/// Adds a new empty slice to the vec and returns a reference to it. Produces an error if the
	/// vec overflows.
	pub fn push_default(&mut self) -> Result<&mut [u8], &'static str> {
		if segment_slice_len() + self.0.len() > max_segment_slice_vec_bytes() as usize {
			return Err("Exceeded maximum segment slice vector size")
		}
		let len = self.0.len();
		self.0.resize(len + segment_slice_len(), 0u8);
		Ok(&mut self.0[len..])
	}
}

impl std::ops::Index<usize> for SegmentSliceVec {
	type Output = [u8];
	fn index(&self, index: usize) -> &Self::Output {
		&self.0[index * segment_slice_len()..(index + 1) * segment_slice_len()]
	}
}

pub type SegmentVec = Vec<Segment>;