• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tari-project / tari / 23184374285

17 Mar 2026 08:04AM UTC coverage: 60.967% (-0.8%) from 61.722%
23184374285

push

github

SWvheerden
chore: new release v5.3.0-pre.3

69750 of 114406 relevant lines covered (60.97%)

227024.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.64
/base_layer/core/src/test_helpers/block_spec.rs
1
//  Copyright 2021, The Tari Project
2
//
3
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
4
//  following conditions are met:
5
//
6
//  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7
//  disclaimer.
8
//
9
//  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
10
//  following disclaimer in the documentation and/or other materials provided with the distribution.
11
//
12
//  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
13
//  products derived from this software without specific prior written permission.
14
//
15
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
//  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
//  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20
//  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
21
//  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22

23
use tari_transaction_components::{MicroMinotari, transaction_components::Transaction};
24

25
pub struct BlockSpecs {
26
    specs: Vec<BlockSpec>,
27
}
28

29
use tari_transaction_components::tari_proof_of_work::Difficulty;
30
impl BlockSpecs {
31
    pub fn len(&self) -> usize {
18✔
32
        self.specs.len()
18✔
33
    }
18✔
34

35
    pub fn is_empty(&self) -> bool {
×
36
        self.len() == 0
×
37
    }
×
38

39
    pub fn into_vec(self) -> Vec<BlockSpec> {
×
40
        self.specs
×
41
    }
×
42
}
43

44
impl From<Vec<BlockSpec>> for BlockSpecs {
45
    fn from(specs: Vec<BlockSpec>) -> Self {
9✔
46
        Self { specs }
9✔
47
    }
9✔
48
}
49

50
impl<'a, const N: usize> From<&'a [(&'static str, u64, u64); N]> for BlockSpecs {
51
    fn from(arr: &'a [(&'static str, u64, u64); N]) -> Self {
9✔
52
        BlockSpecs::from(&arr[..])
9✔
53
    }
9✔
54
}
55

56
impl<'a> From<&'a [(&'static str, u64, u64)]> for BlockSpecs {
57
    fn from(arr: &'a [(&'static str, u64, u64)]) -> Self {
9✔
58
        Self {
59
            specs: arr
9✔
60
                .iter()
9✔
61
                .map(|(name, diff, time)| {
25✔
62
                    BlockSpec::builder()
25✔
63
                        .with_name(name)
25✔
64
                        .with_block_time(*time)
25✔
65
                        .with_difficulty(Difficulty::from_u64(*diff).unwrap())
25✔
66
                        .finish()
25✔
67
                })
25✔
68
                .collect(),
9✔
69
        }
70
    }
9✔
71
}
72

73
impl IntoIterator for BlockSpecs {
74
    type IntoIter = std::vec::IntoIter<BlockSpec>;
75
    type Item = BlockSpec;
76

77
    fn into_iter(self) -> Self::IntoIter {
18✔
78
        self.specs.into_iter()
18✔
79
    }
18✔
80
}
81

82
#[macro_export]
83
macro_rules! block_spec {
84
    (@ { $spec:ident }) => {};
85

86
    (@ { $spec: ident } height: $height:expr, $($tail:tt)*) => {
87
        $spec = $spec.with_height($height);
88
        $crate::block_spec!(@ { $spec } $($tail)*)
89
    };
90
    (@ { $spec: ident } difficulty: $difficulty:expr, $($tail:tt)*) => {
91
        $spec = $spec.with_difficulty($difficulty.into());
92
        $crate::block_spec!(@ { $spec } $($tail)*)
93
    };
94
    (@ { $spec: ident } reward: $reward:expr, $($tail:tt)*) => {
95
        $spec = $spec.with_reward($reward.into());
96
        $crate::block_spec!(@ { $spec } $($tail)*)
97
    };
98
    (@ { $spec: ident } parent: $parent:expr, $($tail:tt)*) => {
99
        $spec = $spec.with_parent_block($parent);
100
        $crate::block_spec!(@ { $spec } $($tail)*)
101
    };
102
    (@ { $spec: ident } transactions: $transactions:expr, $($tail:tt)*) => {
103
        $spec = $spec.with_transactions($transactions);
104
        $crate::block_spec!(@ { $spec } $($tail)*)
105
    };
106
    (@ { $spec: ident } skip_coinbase: true, $($tail:tt)*) => {
107
        $spec = $spec.skip_coinbase();
108
        $crate::block_spec!(@ { $spec } $($tail)*)
109
    };
110

111
    (@ { $spec: ident } $k:ident: $v:expr) => { $crate::block_spec!(@ { $spec } $k: $v,) };
112

113
    ($name:expr, $($tail:tt)+) => {{
114
        let mut spec = $crate::block_spec!($name);
115
        $crate::block_spec!(@ { spec } $($tail)+);
116
        spec.finish()
117
    }};
118
    ($name:expr $(,)?) => {
119
        $crate::test_helpers::BlockSpec::builder().with_name($name).finish()
120
    };
121
}
122

123
/// Usage:
124
/// ```ignore
125
/// block_specs!(["1a->GB"], ["2a->1a"], ["3a->2a", difficulty: 2], ["4a->3a", reward: 50000]);
126
/// ```
127
#[macro_export]
128
macro_rules! block_specs {
129
    (@ { $specs:ident }) => {};
130

131
    (@ { $specs:ident } [$name:expr, $($k:ident: $v:expr),*], $($tail:tt)*) => {
132
        $specs.push($crate::block_spec!($name, $($k: $v),*));
133
        block_specs!(@ { $specs } $($tail)*)
134
    };
135

136
    (@ { $specs:ident } [$name:expr $(,)?], $($tail:tt)*) => { block_specs!(@ { $specs } [$name,], $($tail)*) };
137

138
    (@ { $specs:ident } [$name:expr $(,)?]$(,)?) => { block_specs!(@ { $specs } [$name,],) };
139

140
    (@ { $specs:ident } [$name:expr, $($k:ident: $v:expr),* $(,)?] $(,)?) => { block_specs!(@ { $specs } [$name, $($k: $v),*],) };
141

142
    // Entrypoints
143
    ([$name:expr, $($k:ident: $v:expr),*], $($tail:tt)*) => {
144
        #[allow(clippy::vec_init_then_push)]
145
        {
146
            let mut specs = Vec::new();
147
            $crate::block_specs!(@ { specs } [$name, $($k: $v),*], $($tail)*);
148
            $crate::test_helpers::BlockSpecs::from(specs)
149
        }
150
    };
151
    ([$name:expr, $($k:ident: $v:expr),* $(,)?] $(,)*) => {{
152
        $crate::block_specs!([$name, $($k: $v),*],)
153
    }};
154

155
    ([$name:expr], $($tail:tt)*) => {{ $crate::block_specs!([$name,], $($tail)*) }};
156

157
    ([$name:expr]) => {{ $crate::block_specs!([$name,],) }};
158

159
    () => { BlockSpecs::from(Vec::new()) };
160
}
161

162
#[derive(Debug, Clone)]
163
pub struct BlockSpec {
164
    pub name: &'static str,
165
    pub parent: &'static str,
166
    pub difficulty: Difficulty,
167
    pub block_time: u64,
168
    pub reward_override: Option<MicroMinotari>,
169
    pub height_override: Option<u64>,
170
    pub transactions: Vec<Transaction>,
171
    pub skip_coinbase: bool,
172
}
173

174
impl BlockSpec {
175
    pub fn new() -> Self {
29✔
176
        Default::default()
29✔
177
    }
29✔
178

179
    pub fn builder() -> Self {
99✔
180
        Default::default()
99✔
181
    }
99✔
182

183
    pub fn with_name(mut self, name: &'static str) -> Self {
99✔
184
        let mut split = name.splitn(2, "->");
99✔
185
        let name = split.next().unwrap_or("<noname>");
99✔
186
        self.name = name;
99✔
187
        if let Some(prev_block) = split.next() {
99✔
188
            self.parent = prev_block;
64✔
189
        }
64✔
190
        self
99✔
191
    }
99✔
192

193
    pub fn with_parent_block(mut self, prev_block_name: &'static str) -> Self {
43✔
194
        self.parent = prev_block_name;
43✔
195
        self
43✔
196
    }
43✔
197

198
    pub fn with_height(mut self, height: u64) -> Self {
×
199
        self.height_override = Some(height);
×
200
        self
×
201
    }
×
202

203
    pub fn with_difficulty(mut self, difficulty: Difficulty) -> Self {
26✔
204
        self.difficulty = difficulty;
26✔
205
        self
26✔
206
    }
26✔
207

208
    pub fn with_block_time(mut self, block_time: u64) -> Self {
25✔
209
        self.block_time = block_time;
25✔
210
        self
25✔
211
    }
25✔
212

213
    pub fn with_reward(mut self, reward: MicroMinotari) -> Self {
1✔
214
        self.reward_override = Some(reward);
1✔
215
        self
1✔
216
    }
1✔
217

218
    pub fn skip_coinbase(mut self) -> Self {
1✔
219
        self.skip_coinbase = true;
1✔
220
        self
1✔
221
    }
1✔
222

223
    pub fn with_transactions(mut self, transactions: Vec<Transaction>) -> Self {
45✔
224
        self.transactions = transactions;
45✔
225
        self
45✔
226
    }
45✔
227

228
    pub fn finish(self) -> Self {
154✔
229
        self
154✔
230
    }
154✔
231
}
232

233
impl Default for BlockSpec {
234
    fn default() -> Self {
129✔
235
        Self {
129✔
236
            name: "<unnamed>",
129✔
237
            parent: "",
129✔
238
            difficulty: Difficulty::min(),
129✔
239
            block_time: 120,
129✔
240
            height_override: None,
129✔
241
            reward_override: None,
129✔
242
            transactions: vec![],
129✔
243
            skip_coinbase: false,
129✔
244
        }
129✔
245
    }
129✔
246
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc