use tari_transaction_components::{MicroMinotari, transaction_components::Transaction};
pub struct BlockSpecs {
specs: Vec<BlockSpec>,
}
use tari_transaction_components::tari_proof_of_work::Difficulty;
impl BlockSpecs {
pub fn len(&self) -> usize {
self.specs.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn into_vec(self) -> Vec<BlockSpec> {
self.specs
}
}
impl From<Vec<BlockSpec>> for BlockSpecs {
fn from(specs: Vec<BlockSpec>) -> Self {
Self { specs }
}
}
impl<'a, const N: usize> From<&'a [(&'static str, u64, u64); N]> for BlockSpecs {
fn from(arr: &'a [(&'static str, u64, u64); N]) -> Self {
BlockSpecs::from(&arr[..])
}
}
impl<'a> From<&'a [(&'static str, u64, u64)]> for BlockSpecs {
fn from(arr: &'a [(&'static str, u64, u64)]) -> Self {
Self {
specs: arr
.iter()
.map(|(name, diff, time)| {
BlockSpec::builder()
.with_name(name)
.with_block_time(*time)
.with_difficulty(Difficulty::from_u64(*diff).unwrap())
.finish()
})
.collect(),
}
}
}
impl IntoIterator for BlockSpecs {
type IntoIter = std::vec::IntoIter<BlockSpec>;
type Item = BlockSpec;
fn into_iter(self) -> Self::IntoIter {
self.specs.into_iter()
}
}
#[macro_export]
macro_rules! block_spec {
(@ { $spec:ident }) => {};
(@ { $spec: ident } height: $height:expr, $($tail:tt)*) => {
$spec = $spec.with_height($height);
$crate::block_spec!(@ { $spec } $($tail)*)
};
(@ { $spec: ident } difficulty: $difficulty:expr, $($tail:tt)*) => {
$spec = $spec.with_difficulty($difficulty.into());
$crate::block_spec!(@ { $spec } $($tail)*)
};
(@ { $spec: ident } reward: $reward:expr, $($tail:tt)*) => {
$spec = $spec.with_reward($reward.into());
$crate::block_spec!(@ { $spec } $($tail)*)
};
(@ { $spec: ident } parent: $parent:expr, $($tail:tt)*) => {
$spec = $spec.with_parent_block($parent);
$crate::block_spec!(@ { $spec } $($tail)*)
};
(@ { $spec: ident } transactions: $transactions:expr, $($tail:tt)*) => {
$spec = $spec.with_transactions($transactions);
$crate::block_spec!(@ { $spec } $($tail)*)
};
(@ { $spec: ident } skip_coinbase: true, $($tail:tt)*) => {
$spec = $spec.skip_coinbase();
$crate::block_spec!(@ { $spec } $($tail)*)
};
(@ { $spec: ident } $k:ident: $v:expr) => { $crate::block_spec!(@ { $spec } $k: $v,) };
($name:expr, $($tail:tt)+) => {{
let mut spec = $crate::block_spec!($name);
$crate::block_spec!(@ { spec } $($tail)+);
spec.finish()
}};
($name:expr $(,)?) => {
$crate::test_helpers::BlockSpec::builder().with_name($name).finish()
};
}
#[macro_export]
macro_rules! block_specs {
(@ { $specs:ident }) => {};
(@ { $specs:ident } [$name:expr, $($k:ident: $v:expr),*], $($tail:tt)*) => {
$specs.push($crate::block_spec!($name, $($k: $v),*));
block_specs!(@ { $specs } $($tail)*)
};
(@ { $specs:ident } [$name:expr $(,)?], $($tail:tt)*) => { block_specs!(@ { $specs } [$name,], $($tail)*) };
(@ { $specs:ident } [$name:expr $(,)?]$(,)?) => { block_specs!(@ { $specs } [$name,],) };
(@ { $specs:ident } [$name:expr, $($k:ident: $v:expr),* $(,)?] $(,)?) => { block_specs!(@ { $specs } [$name, $($k: $v),*],) };
([$name:expr, $($k:ident: $v:expr),*], $($tail:tt)*) => {
#[allow(clippy::vec_init_then_push)]
{
let mut specs = Vec::new();
$crate::block_specs!(@ { specs } [$name, $($k: $v),*], $($tail)*);
$crate::test_helpers::BlockSpecs::from(specs)
}
};
([$name:expr, $($k:ident: $v:expr),* $(,)?] $(,)*) => {{
$crate::block_specs!([$name, $($k: $v),*],)
}};
([$name:expr], $($tail:tt)*) => {{ $crate::block_specs!([$name,], $($tail)*) }};
([$name:expr]) => {{ $crate::block_specs!([$name,],) }};
() => { BlockSpecs::from(Vec::new()) };
}
#[derive(Debug, Clone)]
pub struct BlockSpec {
pub name: &'static str,
pub parent: &'static str,
pub difficulty: Difficulty,
pub block_time: u64,
pub reward_override: Option<MicroMinotari>,
pub height_override: Option<u64>,
pub transactions: Vec<Transaction>,
pub skip_coinbase: bool,
}
impl BlockSpec {
pub fn new() -> Self {
Default::default()
}
pub fn builder() -> Self {
Default::default()
}
pub fn with_name(mut self, name: &'static str) -> Self {
let mut split = name.splitn(2, "->");
let name = split.next().unwrap_or("<noname>");
self.name = name;
if let Some(prev_block) = split.next() {
self.parent = prev_block;
}
self
}
pub fn with_parent_block(mut self, prev_block_name: &'static str) -> Self {
self.parent = prev_block_name;
self
}
pub fn with_height(mut self, height: u64) -> Self {
self.height_override = Some(height);
self
}
pub fn with_difficulty(mut self, difficulty: Difficulty) -> Self {
self.difficulty = difficulty;
self
}
pub fn with_block_time(mut self, block_time: u64) -> Self {
self.block_time = block_time;
self
}
pub fn with_reward(mut self, reward: MicroMinotari) -> Self {
self.reward_override = Some(reward);
self
}
pub fn skip_coinbase(mut self) -> Self {
self.skip_coinbase = true;
self
}
pub fn with_transactions(mut self, transactions: Vec<Transaction>) -> Self {
self.transactions = transactions;
self
}
pub fn finish(self) -> Self {
self
}
}
impl Default for BlockSpec {
fn default() -> Self {
Self {
name: "<unnamed>",
parent: "",
difficulty: Difficulty::min(),
block_time: 120,
height_override: None,
reward_override: None,
transactions: vec![],
skip_coinbase: false,
}
}
}