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

tari-project / tari / 19929707289

04 Dec 2025 12:55PM UTC coverage: 60.418% (-0.1%) from 60.517%
19929707289

push

github

SWvheerden
chore: new release v5.2.0-pre.7

70282 of 116327 relevant lines covered (60.42%)

225067.75 hits per line

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

75.0
/base_layer/node_components/src/blocks/block.rs
1
// Copyright 2018 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
// Portions of this file were originally copyrighted (c) 2018 The Grin Developers, issued under the Apache License,
24
// Version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0.
25

26
use std::{
27
    fmt,
28
    fmt::{Display, Formatter},
29
};
30

31
use borsh::{BorshDeserialize, BorshSerialize};
32
use log::*;
33
use serde::{Deserialize, Serialize};
34
use tari_common_types::types::{FixedHash, PrivateKey};
35
use tari_transaction_components::{
36
    aggregated_body::AggregateBody,
37
    consensus::ConsensusConstants,
38
    crypto_factories::CryptoFactories,
39
    tari_proof_of_work::ProofOfWork,
40
    transaction_components::{
41
        KernelFeatures,
42
        OutputType,
43
        Transaction,
44
        TransactionError,
45
        TransactionInput,
46
        TransactionKernel,
47
        TransactionOutput,
48
    },
49
    MicroMinotari,
50
};
51
use thiserror::Error;
52

53
use crate::blocks::BlockHeader;
54

55
#[derive(Clone, Debug, Error)]
56
pub enum BlockValidationError {
57
    #[error("A transaction in the block failed to validate: `{0}`")]
58
    TransactionError(#[from] TransactionError),
59
    #[error("Mismatched {kind} MMR roots")]
60
    MismatchedMmrRoots { kind: &'static str },
61
    #[error("MMR size for {mmr_tree} does not match. Expected: {expected}, received: {actual}")]
62
    MismatchedMmrSize {
63
        mmr_tree: String,
64
        expected: u64,
65
        actual: u64,
66
    },
67
}
68

69
/// A Minotari block. Blocks are linked together into a blockchain.
70
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
×
71
pub struct Block {
72
    /// The BlockHeader contains all the metadata for the block, including proof of work, a link to the previous block
73
    /// and the transaction kernels.
74
    pub header: BlockHeader,
75
    /// The components of the block or transaction. The same struct can be used for either, since in Mimblewimble,
76
    /// blocks consist of inputs, outputs and kernels, rather than transactions.
77
    pub body: AggregateBody,
78
}
79

80
impl Block {
81
    pub fn new(header: BlockHeader, body: AggregateBody) -> Self {
75✔
82
        Self { header, body }
75✔
83
    }
75✔
84

85
    pub fn version(&self) -> u16 {
822✔
86
        self.header.version
822✔
87
    }
822✔
88

89
    /// This function will calculate the total fees contained in a block
90
    pub fn calculate_fees(&self) -> MicroMinotari {
×
91
        self.body.kernels().iter().fold(0.into(), |sum, x| sum + x.fee)
×
92
    }
×
93

94
    /// Run through the outputs of the block and check that
95
    /// 1. There is exactly ONE coinbase output
96
    /// 2. The output's maturity is correctly set
97
    /// 3. The amount is correct.
98
    pub fn check_coinbase_output(
82✔
99
        &self,
82✔
100
        reward: MicroMinotari,
82✔
101
        consensus_constants: &ConsensusConstants,
82✔
102
        factories: &CryptoFactories,
82✔
103
    ) -> Result<(), BlockValidationError> {
82✔
104
        self.body.check_coinbase_output(
82✔
105
            reward,
82✔
106
            consensus_constants.coinbase_min_maturity(),
82✔
107
            factories,
82✔
108
            self.header.height,
82✔
109
            consensus_constants.max_block_coinbase_count(),
82✔
110
        )?;
7✔
111
        Ok(())
75✔
112
    }
82✔
113

114
    /// Destroys the block and returns the pieces of the block: header, inputs, outputs and kernels
115
    pub fn dissolve(
4✔
116
        self,
4✔
117
    ) -> (
4✔
118
        BlockHeader,
4✔
119
        Vec<TransactionInput>,
4✔
120
        Vec<TransactionOutput>,
4✔
121
        Vec<TransactionKernel>,
4✔
122
    ) {
4✔
123
        let (inputs, outputs, kernels) = self.body.dissolve();
4✔
124
        (self.header, inputs, outputs, kernels)
4✔
125
    }
4✔
126

127
    /// Destroys the block and returns the pieces of the block: header, body
128
    pub fn into_header_body(self) -> (BlockHeader, AggregateBody) {
×
129
        (self.header, self.body)
×
130
    }
×
131

132
    /// Return a cloned version of this block with the TransactionInputs in their compact form
133
    pub fn to_compact(&self) -> Self {
×
134
        Self {
×
135
            header: self.header.clone(),
×
136
            body: self.body.to_compact(),
×
137
        }
×
138
    }
×
139

140
    /// The block hash is just the header hash, since the inputs, outputs and range proofs are captured by their
141
    /// respective MMR roots in the header itself.
142
    pub fn hash(&self) -> FixedHash {
3,609✔
143
        self.header.hash()
3,609✔
144
    }
3,609✔
145
}
146

147
impl Display for Block {
148
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
×
149
        writeln!(f, "----------------- Block -----------------")?;
×
150
        writeln!(f, "--- Header ---")?;
×
151
        writeln!(f, "Hash: {}", self.header.hash())?;
×
152
        writeln!(f, "{}", self.header)?;
×
153
        writeln!(f, "---  Body  ---")?;
×
154
        writeln!(f, "{}", self.body)
×
155
    }
×
156
}
157

158
pub struct BlockBuilder {
159
    header: BlockHeader,
160
    inputs: Vec<TransactionInput>,
161
    outputs: Vec<TransactionOutput>,
162
    kernels: Vec<TransactionKernel>,
163
}
164

165
impl BlockBuilder {
166
    pub fn new(blockchain_version: u16) -> BlockBuilder {
675✔
167
        BlockBuilder {
675✔
168
            header: BlockHeader::new(blockchain_version),
675✔
169
            inputs: Vec::new(),
675✔
170
            outputs: Vec::new(),
675✔
171
            kernels: Vec::new(),
675✔
172
        }
675✔
173
    }
675✔
174

175
    /// This function adds a header to the block
176
    pub fn with_header(mut self, header: BlockHeader) -> Self {
671✔
177
        self.header = header;
671✔
178
        self
671✔
179
    }
671✔
180

181
    /// This function adds the provided transaction inputs to the block
182
    pub fn add_inputs(mut self, mut inputs: Vec<TransactionInput>) -> Self {
610✔
183
        self.inputs.append(&mut inputs);
610✔
184
        self
610✔
185
    }
610✔
186

187
    /// This function adds the provided transaction outputs to the block WITHOUT updating output_mmr_size in the header
188
    pub fn add_outputs(mut self, mut outputs: Vec<TransactionOutput>) -> Self {
631✔
189
        self.outputs.append(&mut outputs);
631✔
190
        self
631✔
191
    }
631✔
192

193
    /// This function adds the provided transaction kernels to the block WITHOUT updating kernel_mmr_size in the header
194
    pub fn add_kernels(mut self, mut kernels: Vec<TransactionKernel>) -> Self {
631✔
195
        self.kernels.append(&mut kernels);
631✔
196
        self
631✔
197
    }
631✔
198

199
    /// This functions adds the provided transactions to the block, modifying the header MMR counts and offsets
200
    pub fn with_transactions(mut self, txs: Vec<Transaction>) -> Self {
414✔
201
        for tx in txs {
827✔
202
            self = self.add_transaction(tx)
413✔
203
        }
204
        self
414✔
205
    }
414✔
206

207
    /// This functions adds the provided transaction to the block, modifying the header MMR counts and offsets
208
    pub fn add_transaction(mut self, tx: Transaction) -> Self {
413✔
209
        let (inputs, outputs, kernels) = tx.body.dissolve();
413✔
210
        self = self.add_inputs(inputs);
413✔
211
        self.header.output_smt_size += outputs.len() as u64;
413✔
212
        self = self.add_outputs(outputs);
413✔
213
        self.header.kernel_mmr_size += kernels.len() as u64;
413✔
214
        self = self.add_kernels(kernels);
413✔
215
        self.header.total_kernel_offset = self.header.total_kernel_offset + tx.offset;
413✔
216
        self.header.total_script_offset = self.header.total_script_offset + tx.script_offset;
413✔
217
        self
413✔
218
    }
413✔
219

220
    /// This will add the given coinbase UTXO to the block
221
    pub fn with_coinbase_utxo(mut self, coinbase_utxo: TransactionOutput, coinbase_kernel: TransactionKernel) -> Self {
223✔
222
        self.kernels.push(coinbase_kernel);
223✔
223
        self.outputs.push(coinbase_utxo);
223✔
224
        self
223✔
225
    }
223✔
226

227
    /// Add the provided ProofOfWork metadata to the block
228
    pub fn with_pow(mut self, pow: ProofOfWork) -> Self {
×
229
        self.header.pow = pow;
×
230
        self
×
231
    }
×
232

233
    /// This will finish construction of the block and create the block
234
    pub fn build(self) -> Block {
671✔
235
        let mut block = Block {
671✔
236
            header: self.header,
671✔
237
            body: AggregateBody::new(self.inputs, self.outputs, self.kernels),
671✔
238
        };
671✔
239
        block.body.sort();
671✔
240
        block
671✔
241
    }
671✔
242
}
243

244
//---------------------------------- NewBlock --------------------------------------------//
245
pub struct NewBlock {
246
    /// The block header.
247
    pub header: BlockHeader,
248
    /// Coinbase kernel of the block
249
    pub coinbase_kernels: Vec<TransactionKernel>,
250
    /// Coinbase output of the block
251
    pub coinbase_outputs: Vec<TransactionOutput>,
252
    /// The scalar `s` component of the kernel excess signatures of the transactions contained in the block.
253
    pub kernel_excess_sigs: Vec<PrivateKey>,
254
}
255

256
impl Display for NewBlock {
257
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
×
258
        writeln!(f, "----------------- New Block -----------------")?;
×
259
        writeln!(f, "--- Header ---")?;
×
260
        writeln!(f, "Hash: {}", self.header.hash())?;
×
261
        writeln!(f, "{}", self.header)?;
×
262
        writeln!(f, "---  Coinbase Kernels  ---")?;
×
263
        for kernel in &self.coinbase_kernels {
×
264
            writeln!(f, "{}", kernel)?;
×
265
        }
266
        writeln!(f, "---  Coinbase Outputs  ---")?;
×
267
        for output in &self.coinbase_outputs {
×
268
            writeln!(f, "{}", output)?;
×
269
        }
270
        Ok(())
×
271
    }
×
272
}
273

274
impl From<&Block> for NewBlock {
275
    fn from(block: &Block) -> Self {
33✔
276
        let coinbase_kernels = block
33✔
277
            .body
33✔
278
            .kernels()
33✔
279
            .clone()
33✔
280
            .into_iter()
33✔
281
            .filter(|k| k.features.contains(KernelFeatures::COINBASE_KERNEL))
39✔
282
            .collect();
33✔
283
        let coinbase_outputs = block
33✔
284
            .body
33✔
285
            .outputs()
33✔
286
            .clone()
33✔
287
            .into_iter()
33✔
288
            .filter(|o| o.features.output_type == OutputType::Coinbase)
46✔
289
            .collect();
33✔
290

291
        Self {
292
            header: block.header.clone(),
33✔
293
            coinbase_kernels,
33✔
294
            coinbase_outputs,
33✔
295
            kernel_excess_sigs: block
33✔
296
                .body
33✔
297
                .kernels()
33✔
298
                .iter()
33✔
299
                .filter(|k| !k.features.contains(KernelFeatures::COINBASE_KERNEL))
39✔
300
                .map(|kernel| kernel.excess_sig.get_signature().clone())
33✔
301
                .collect(),
33✔
302
        }
303
    }
33✔
304
}
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