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

tari-project / tari / 18402812670

10 Oct 2025 09:44AM UTC coverage: 59.552% (+1.0%) from 58.589%
18402812670

push

github

web-flow
chore(ci): remove bitnami docker images for debian slim images and minor updates (#7543)

Description
remove bitnami docker images for debian slim images
minor updates and tor version bump

Motivation and Context
Move away from bitnami docker images as they going pay for use

How Has This Been Tested?
Builds in local fork, runnings in local container


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- New Features
  - None
- Bug Fixes
  - None
- Chores
- Switched build and runtime base images to Debian slim variants for
improved consistency.
- Updated Rust toolchain to 1.90.0 and moved OS base to Debian “trixie.”
  - Bumped Tor package to 0.4.8.19-r0.
- Documentation
- Refreshed inline comments to reflect new base image sources and Tor
branch reference.
- Tests
  - None

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

67582 of 113484 relevant lines covered (59.55%)

304718.09 hits per line

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

95.64
/base_layer/core/src/validation/block_body/test.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
#![allow(clippy::indexing_slicing)]
24
use std::sync::Arc;
25

26
use tari_common::configuration::Network;
27
use tari_common_types::{key_branches::TransactionKeyManagerBranch, tari_address::TariAddress};
28
use tari_node_components::blocks::BlockValidationError;
29
use tari_script::{push_pubkey_script, script};
30
use tari_test_utils::unpack_enum;
31
use tari_transaction_components::{
32
    aggregated_body::AggregateBody,
33
    consensus::ConsensusConstantsBuilder,
34
    crypto_factories::CryptoFactories,
35
    key_manager::TariKeyId,
36
    tari_amount::{uT, T},
37
    tari_proof_of_work::Difficulty,
38
    test_helpers::schema_to_transaction,
39
    transaction_components::{
40
        encrypted_data::STATIC_ENCRYPTED_DATA_SIZE_TOTAL,
41
        EncryptedData,
42
        MemoField,
43
        RangeProofType,
44
        TransactionError,
45
    },
46
    txn_schema,
47
    validation::AggregatedBodyValidationError,
48
    CoinbaseBuilder,
49
};
50
use tokio::time::Instant;
51

52
use super::BlockBodyFullValidator;
53
use crate::{
54
    block_spec,
55
    consensus::BaseNodeConsensusManager,
56
    test_helpers::{blockchain::TestBlockchain, BlockSpec},
57
    validation::{BlockBodyValidator, ValidationError},
58
};
59
async fn setup_with_rules(
14✔
60
    rules: BaseNodeConsensusManager,
14✔
61
    check_rangeproof: bool,
14✔
62
) -> (TestBlockchain, BlockBodyFullValidator) {
14✔
63
    let blockchain = TestBlockchain::create(rules.clone()).await;
14✔
64
    let validator = BlockBodyFullValidator::new(rules, check_rangeproof);
14✔
65
    (blockchain, validator)
14✔
66
}
14✔
67

68
async fn setup(check_rangeproof: bool) -> (TestBlockchain, BlockBodyFullValidator) {
11✔
69
    let rules = BaseNodeConsensusManager::builder(Network::LocalNet)
11✔
70
        .add_consensus_constants(
11✔
71
            ConsensusConstantsBuilder::new(Network::LocalNet)
11✔
72
                .with_coinbase_lockheight(0)
11✔
73
                .with_max_block_transaction_weight(127_795)
11✔
74
                .build(),
11✔
75
        )
76
        .build()
11✔
77
        .unwrap();
11✔
78
    setup_with_rules(rules, check_rangeproof).await
11✔
79
}
11✔
80

81
#[tokio::test]
82
async fn it_passes_if_large_output_block_is_valid() {
1✔
83
    // we use this test to benchmark a block with multiple outputs
84
    let (mut blockchain, validator) = setup(false).await;
1✔
85
    let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
86
    let mut outs = Vec::new();
1✔
87
    // create 498 outputs, so we have a block with 500 outputs, 498 + change + coinbase
88
    for _ in 0..498 {
499✔
89
        outs.push(9000 * uT);
498✔
90
    }
498✔
91

92
    let schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: outs);
1✔
93
    let (txs, _outputs) = schema_to_transaction(&[schema1], &mut blockchain.km).await;
1✔
94

95
    let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::<Vec<_>>();
1✔
96
    let (chain_block, _coinbase_b) = blockchain
1✔
97
        .create_next_tip(block_spec!("B",parent: "A", transactions: txs))
1✔
98
        .await;
1✔
99
    let (mut block, mmr_roots) = blockchain
1✔
100
        .db()
1✔
101
        .calculate_mmr_roots(chain_block.block().clone())
1✔
102
        .unwrap();
1✔
103
    block.header.input_mr = mmr_roots.input_mr;
1✔
104
    block.header.block_output_mr = mmr_roots.block_output_mr;
1✔
105
    block.header.output_mr = mmr_roots.output_mr;
1✔
106
    block.header.output_smt_size = mmr_roots.output_smt_size;
1✔
107
    block.header.kernel_mr = mmr_roots.kernel_mr;
1✔
108
    block.header.kernel_mmr_size = mmr_roots.kernel_mmr_size;
1✔
109
    block.header.validator_node_mr = mmr_roots.validator_node_mr;
1✔
110
    block.header.validator_node_size = mmr_roots.validator_node_size;
1✔
111

112
    let txn = blockchain.db().db_read_access().unwrap();
1✔
113
    let start = Instant::now();
1✔
114
    assert!(validator.validate_body(&*txn, &block).is_ok());
1✔
115
    let finished = start.elapsed();
×
116
    // this here here for benchmarking purposes.
117
    // we can extrapolate full block validation by multiplying the time by 4.6, this we get from the max_weight /weight
118
    // of the block
119
    println!("finished validating in: {}", finished.as_millis());
×
120
}
1✔
121

122
#[tokio::test]
123
async fn it_validates_when_a_coinbase_is_spent() {
1✔
124
    // we use this test to benchmark a block with multiple outputs
125
    let (mut blockchain, validator) = setup(false).await;
1✔
126
    let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
127

128
    let schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![9000 * uT]);
1✔
129
    let (txs, _outputs) = schema_to_transaction(&[schema1], &mut blockchain.km).await;
1✔
130

131
    let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::<Vec<_>>();
1✔
132
    let (chain_block, _coinbase_b) = blockchain
1✔
133
        .create_next_tip(block_spec!("B",parent: "A", transactions: txs))
1✔
134
        .await;
1✔
135
    let (mut block, mmr_roots) = blockchain
1✔
136
        .db()
1✔
137
        .calculate_mmr_roots(chain_block.block().clone())
1✔
138
        .unwrap();
1✔
139
    block.header.input_mr = mmr_roots.input_mr;
1✔
140
    block.header.output_mr = mmr_roots.output_mr;
1✔
141
    block.header.block_output_mr = mmr_roots.block_output_mr;
1✔
142
    block.header.output_smt_size = mmr_roots.output_smt_size;
1✔
143
    block.header.kernel_mr = mmr_roots.kernel_mr;
1✔
144
    block.header.kernel_mmr_size = mmr_roots.kernel_mmr_size;
1✔
145
    block.header.validator_node_mr = mmr_roots.validator_node_mr;
1✔
146
    block.header.validator_node_size = mmr_roots.validator_node_size;
1✔
147

148
    let txn = blockchain.db().db_read_access().unwrap();
1✔
149
    assert!(validator.validate_body(&*txn, &block).is_ok());
1✔
150
}
1✔
151

152
#[tokio::test]
153
async fn it_passes_if_large_block_is_valid() {
1✔
154
    // we use this test to benchmark a block with multiple inputs and outputs
155
    let (mut blockchain, validator) = setup(false).await;
1✔
156
    let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
157
    let schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T, 5 * T]);
1✔
158
    let (txs, outputs) = schema_to_transaction(&[schema1], &mut blockchain.km).await;
1✔
159

160
    let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::<Vec<_>>();
1✔
161
    let (_block, _coinbase_b) = blockchain
1✔
162
        .append(block_spec!("B", parent: "A", transactions: txs))
1✔
163
        .await
1✔
164
        .unwrap();
1✔
165

166
    let mut schemas = Vec::new();
1✔
167
    for output in outputs {
2,147,483,647✔
168
        let new_schema = txn_schema!(from: vec![output.clone()], to: vec![1 * T, 1 * T, 1 * T, 1 * T]);
2,147,483,647✔
169
        schemas.push(new_schema);
2,147,483,647✔
170
    }
2,147,483,647✔
171
    let (txs, _) = schema_to_transaction(&schemas, &mut blockchain.km).await;
1✔
172

173
    let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::<Vec<_>>();
×
174
    let (chain_block, _coinbase_c) = blockchain
×
175
        .create_next_tip(block_spec!("C",parent: "B", transactions: txs))
×
176
        .await;
×
177
    let (mut block, mmr_roots) = blockchain
×
178
        .db()
×
179
        .calculate_mmr_roots(chain_block.block().clone())
×
180
        .unwrap();
×
181
    block.header.input_mr = mmr_roots.input_mr;
×
182
    block.header.output_mr = mmr_roots.output_mr;
×
183
    block.header.block_output_mr = mmr_roots.block_output_mr;
×
184
    block.header.output_smt_size = mmr_roots.output_smt_size;
×
185
    block.header.kernel_mr = mmr_roots.kernel_mr;
×
186
    block.header.kernel_mmr_size = mmr_roots.kernel_mmr_size;
×
187
    block.header.validator_node_mr = mmr_roots.validator_node_mr;
×
188
    block.header.validator_node_size = mmr_roots.validator_node_size;
×
189

190
    let txn = blockchain.db().db_read_access().unwrap();
×
191
    let start = Instant::now();
×
192
    validator.validate_body(&*txn, &block).unwrap();
×
193
    // assert!(validator.validate_body(&*txn, &block).is_ok());
194
    let finished = start.elapsed();
×
195
    // this here here for benchmarking purposes.
196
    // we can extrapolate full block validation by multiplying the time by 32.9, this we get from the max_weight /weight
197
    // of the block
198
    println!("finished validating in: {}", finished.as_millis());
×
199
}
1✔
200

201
#[tokio::test]
202
async fn it_passes_if_block_is_valid() {
1✔
203
    let (mut blockchain, validator) = setup(true).await;
1✔
204

205
    let (chain_block, _) = blockchain.create_next_tip(BlockSpec::default()).await;
1✔
206

207
    let (mut block, mmr_roots) = blockchain
1✔
208
        .db()
1✔
209
        .calculate_mmr_roots(chain_block.block().clone())
1✔
210
        .unwrap();
1✔
211
    block.header.input_mr = mmr_roots.input_mr;
1✔
212
    block.header.output_mr = mmr_roots.output_mr;
1✔
213
    block.header.block_output_mr = mmr_roots.block_output_mr;
1✔
214
    block.header.output_smt_size = mmr_roots.output_smt_size;
1✔
215
    block.header.kernel_mr = mmr_roots.kernel_mr;
1✔
216
    block.header.kernel_mmr_size = mmr_roots.kernel_mmr_size;
1✔
217
    block.header.validator_node_mr = mmr_roots.validator_node_mr;
1✔
218
    block.header.validator_node_size = mmr_roots.validator_node_size;
1✔
219

220
    let txn = blockchain.db().db_read_access().unwrap();
1✔
221
    assert!(validator.validate_body(&*txn, &block).is_ok());
1✔
222
}
1✔
223

224
#[tokio::test]
225
async fn it_checks_the_coinbase_reward() {
1✔
226
    let (mut blockchain, validator) = setup(true).await;
1✔
227

228
    let (block, _) = blockchain
1✔
229
        .create_chained_block(block_spec!("A", parent: "GB", reward: 10 * T, ))
1✔
230
        .await;
1✔
231
    let txn = blockchain.db().db_read_access().unwrap();
1✔
232
    let err = validator.validate_body(&*txn, block.block()).unwrap_err();
1✔
233
    println!("err {err:?}");
1✔
234
    assert!(matches!(
1✔
235
        err,
1✔
236
        ValidationError::BlockError(BlockValidationError::TransactionError(
1✔
237
            TransactionError::InvalidCoinbase
1✔
238
        ))
1✔
239
    ));
1✔
240
}
1✔
241

242
#[tokio::test]
243
async fn it_allows_multiple_coinbases() {
1✔
244
    let (mut blockchain, validator) = setup(true).await;
1✔
245

246
    let (mut block, coinbase) = blockchain.create_unmined_block(block_spec!("A1", parent: "GB")).await;
1✔
247
    let commitment_mask_key = TariKeyId::Managed {
1✔
248
        branch: TransactionKeyManagerBranch::CommitmentMask.get_branch_key(),
1✔
249
        index: 42,
1✔
250
    };
1✔
251
    let wallet_payment_address = TariAddress::default();
1✔
252
    let (_, coinbase_output) = CoinbaseBuilder::new(blockchain.km.clone())
1✔
253
        .with_block_height(1)
1✔
254
        .with_fees(0.into())
1✔
255
        .with_commitment_mask_id(commitment_mask_key.clone())
1✔
256
        .with_encryption_key_id(TariKeyId::default())
1✔
257
        .with_sender_offset_key_id(TariKeyId::default())
1✔
258
        .with_script_key_id(TariKeyId::default())
1✔
259
        .with_script(push_pubkey_script(wallet_payment_address.public_spend_key()))
1✔
260
        .with_range_proof_type(RangeProofType::RevealedValue)
1✔
261
        .build_with_reward(
1✔
262
            blockchain.rules().consensus_constants(1),
1✔
263
            coinbase.value(),
1✔
264
            MemoField::new_empty(),
1✔
265
        )
1✔
266
        .await
1✔
267
        .unwrap();
1✔
268

269
    block.body.add_output(coinbase_output.to_transaction_output().unwrap());
1✔
270
    block.body.sort();
1✔
271

272
    let (block, _) = blockchain
1✔
273
        .create_unmined_block(block_spec!("A2", parent: "GB", skip_coinbase: true,))
1✔
274
        .await;
1✔
275
    let block = blockchain.mine_block("GB", block, Difficulty::min());
1✔
276
    let txn = blockchain.db().db_read_access().unwrap();
1✔
277
    let err = validator.validate_body(&*txn, block.block()).unwrap_err();
1✔
278
    assert!(matches!(
1✔
279
        err,
1✔
280
        ValidationError::BlockError(BlockValidationError::TransactionError(TransactionError::NoCoinbase))
1✔
281
    ));
1✔
282
}
1✔
283

284
#[tokio::test]
285
async fn it_checks_duplicate_kernel() {
1✔
286
    let (mut blockchain, validator) = setup(true).await;
1✔
287

288
    let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
289
    let (txs, _) = schema_to_transaction(
1✔
290
        &[txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T])],
1✔
291
        &mut blockchain.km,
1✔
292
    )
293
    .await;
1✔
294

295
    blockchain
1✔
296
        .add_next_tip(block_spec!("1", transactions: txs.iter().map(|t| (**t).clone()).collect()))
1✔
297
        .await
1✔
298
        .unwrap();
1✔
299
    let (block, _) = blockchain
1✔
300
        .create_next_tip(
1✔
301
            BlockSpec::new()
1✔
302
                .with_transactions(txs.iter().map(|t| (**t).clone()).collect())
1✔
303
                .finish(),
1✔
304
        )
305
        .await;
1✔
306
    let txn = blockchain.db().db_read_access().unwrap();
1✔
307
    let err = validator.validate_body(&*txn, block.block()).unwrap_err();
1✔
308
    assert!(matches!(err, ValidationError::DuplicateKernelError(_)));
1✔
309
}
1✔
310

311
#[tokio::test]
312
async fn it_checks_double_spends() {
1✔
313
    let (mut blockchain, validator) = setup(true).await;
1✔
314

315
    let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
316
    let (txs, _) = schema_to_transaction(
1✔
317
        &[txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T])],
1✔
318
        &mut blockchain.km,
1✔
319
    )
320
    .await;
1✔
321

322
    blockchain
1✔
323
        .add_next_tip(block_spec!("1", transactions: txs.iter().map(|t| (**t).clone()).collect()))
1✔
324
        .await
1✔
325
        .unwrap();
1✔
326
    // lets create a new transction from the same input
327
    let (txs2, _) = schema_to_transaction(
1✔
328
        &[txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T])],
1✔
329
        &mut blockchain.km,
1✔
330
    )
331
    .await;
1✔
332
    let (block, _) = blockchain
1✔
333
        .create_next_tip(
1✔
334
            BlockSpec::new()
1✔
335
                .with_transactions(txs2.iter().map(|t| (**t).clone()).collect())
1✔
336
                .finish(),
1✔
337
        )
338
        .await;
1✔
339
    let txn = blockchain.db().db_read_access().unwrap();
1✔
340
    let err = validator.validate_body(&*txn, block.block()).unwrap_err();
1✔
341
    assert!(matches!(err, ValidationError::ContainsSTxO));
1✔
342
}
1✔
343

344
#[tokio::test]
345
async fn it_checks_input_maturity() {
1✔
346
    let (mut blockchain, validator) = setup(true).await;
1✔
347

348
    let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
349
    let mut schema = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T]);
1✔
350
    let mut features = schema.from[0].features().clone();
1✔
351
    features.maturity = 100;
1✔
352
    schema.from[0].set_features(features);
1✔
353
    let (txs, _) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
354

355
    let (block, _) = blockchain
1✔
356
        .create_next_tip(
1✔
357
            BlockSpec::new()
1✔
358
                .with_transactions(txs.iter().map(|t| (**t).clone()).collect())
1✔
359
                .finish(),
1✔
360
        )
361
        .await;
1✔
362
    let txn = blockchain.db().db_read_access().unwrap();
1✔
363
    let err = validator.validate_body(&*txn, block.block()).unwrap_err();
1✔
364
    assert!(matches!(
1✔
365
        err,
1✔
366
        ValidationError::TransactionError(TransactionError::InputMaturity)
367
    ));
368
    unpack_enum!(ValidationError::TransactionError(TransactionError::InputMaturity) = err);
1✔
369
}
1✔
370

371
#[tokio::test]
372
async fn it_checks_txo_sort_order() {
1✔
373
    let (mut blockchain, validator) = setup(true).await;
1✔
374

375
    let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
376

377
    let schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T, 12 * T]);
1✔
378
    let (txs, _) = schema_to_transaction(&[schema1], &mut blockchain.km).await;
1✔
379
    let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::<Vec<_>>();
1✔
380

381
    let (mut block, _) = blockchain
1✔
382
        .create_unmined_block(block_spec!("B->A", transactions: txs))
1✔
383
        .await;
1✔
384
    let outputs = block.body.outputs().iter().rev().cloned().collect::<Vec<_>>();
1✔
385
    let inputs = block.body.inputs().clone();
1✔
386
    let kernels = block.body.kernels().clone();
1✔
387
    block.body = AggregateBody::new_sorted_unchecked(inputs, outputs, kernels);
1✔
388
    let block = blockchain.mine_block("A", block, Difficulty::min());
1✔
389

390
    let txn = blockchain.db().db_read_access().unwrap();
1✔
391
    let err = validator.validate_body(&*txn, block.block()).unwrap_err();
1✔
392
    assert!(matches!(
1✔
393
        err,
1✔
394
        ValidationError::AggregatedBodyValidationError(AggregatedBodyValidationError::UnsortedOrDuplicateOutput)
1✔
395
    ));
1✔
396
}
1✔
397

398
#[tokio::test]
399
async fn it_limits_the_script_byte_size() {
1✔
400
    let rules = BaseNodeConsensusManager::builder(Network::LocalNet)
1✔
401
        .add_consensus_constants(
1✔
402
            ConsensusConstantsBuilder::new(Network::LocalNet)
1✔
403
                .with_coinbase_lockheight(0)
1✔
404
                .with_max_script_byte_size(2)
1✔
405
                .build(),
1✔
406
        )
407
        .build()
1✔
408
        .unwrap();
1✔
409
    let (mut blockchain, validator) = setup_with_rules(rules, true).await;
1✔
410

411
    let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
412

413
    let mut schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T, 12 * T]);
1✔
414
    schema1.script = script!(Nop Nop Nop).unwrap();
1✔
415
    let (txs, _) = schema_to_transaction(&[schema1], &mut blockchain.km).await;
1✔
416
    let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::<Vec<_>>();
1✔
417
    let (block, _) = blockchain.create_next_tip(block_spec!("B", transactions: txs)).await;
1✔
418

419
    let txn = blockchain.db().db_read_access().unwrap();
1✔
420
    let err = validator.validate_body(&*txn, block.block()).unwrap_err();
1✔
421
    assert!(matches!(
1✔
422
        err,
1✔
423
        ValidationError::AggregatedBodyValidationError(AggregatedBodyValidationError::TariScriptExceedsMaxSize { .. })
1✔
424
    ));
1✔
425
}
1✔
426

427
#[tokio::test]
428
async fn it_limits_the_encrypted_data_byte_size() {
1✔
429
    let rules = BaseNodeConsensusManager::builder(Network::LocalNet)
1✔
430
        .add_consensus_constants(
1✔
431
            ConsensusConstantsBuilder::new(Network::LocalNet)
1✔
432
                .with_coinbase_lockheight(0)
1✔
433
                .build(),
1✔
434
        )
435
        .build()
1✔
436
        .unwrap();
1✔
437
    let (mut blockchain, validator) = setup_with_rules(rules, true).await;
1✔
438

439
    let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
440

441
    let mut schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T, 12 * T]);
1✔
442
    schema1.script = script!(Nop Nop Nop).unwrap();
1✔
443
    let (txs, _) = schema_to_transaction(&[schema1], &mut blockchain.km).await;
1✔
444
    let mut txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::<Vec<_>>();
1✔
445
    let mut outputs = txs[0].body.outputs().clone();
1✔
446
    outputs[0].encrypted_data = EncryptedData::from_bytes(&vec![0; STATIC_ENCRYPTED_DATA_SIZE_TOTAL + 250]).unwrap();
1✔
447
    txs[0].body = AggregateBody::new(txs[0].body.inputs().clone(), outputs, txs[0].body.kernels().clone());
1✔
448
    let (block, _) = blockchain.create_next_tip(block_spec!("B", transactions: txs)).await;
1✔
449

450
    let txn = blockchain.db().db_read_access().unwrap();
1✔
451
    let err = validator.validate_body(&*txn, block.block()).unwrap_err();
1✔
452
    assert!(matches!(
1✔
453
        err,
1✔
454
        ValidationError::AggregatedBodyValidationError(
1✔
455
            AggregatedBodyValidationError::EncryptedDataExceedsMaxSize { .. }
1✔
456
        )
1✔
457
    ));
1✔
458
}
1✔
459

460
#[tokio::test]
461
async fn it_rejects_invalid_input_metadata() {
1✔
462
    let rules = BaseNodeConsensusManager::builder(Network::LocalNet)
1✔
463
        .add_consensus_constants(
1✔
464
            ConsensusConstantsBuilder::new(Network::LocalNet)
1✔
465
                .with_coinbase_lockheight(0)
1✔
466
                .build(),
1✔
467
        )
468
        .build()
1✔
469
        .unwrap();
1✔
470
    let (mut blockchain, validator) = setup_with_rules(rules.clone(), true).await;
1✔
471

472
    let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
473

474
    let mut schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T, 12 * T]);
1✔
475
    schema1.from[0].set_sender_offset_public_key(Default::default());
1✔
476
    let (txs, _) = schema_to_transaction(&[schema1], &mut blockchain.km).await;
1✔
477
    let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::<Vec<_>>();
1✔
478
    let (block, _) = blockchain.create_next_tip(block_spec!("B", transactions: txs)).await;
1✔
479

480
    let txn = blockchain.db().db_read_access().unwrap();
1✔
481
    let err = validator.validate_body(&*txn, block.block()).unwrap_err();
1✔
482
    assert!(matches!(err, ValidationError::UnknownInputs(_)));
1✔
483
}
1✔
484

485
#[tokio::test]
486
async fn it_rejects_zero_conf_double_spends() {
1✔
487
    let (mut blockchain, validator) = setup(true).await;
1✔
488
    let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")).await.unwrap();
1✔
489

490
    let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]);
1✔
491
    let (initial_tx, outputs) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
492

493
    let schema = txn_schema!(from: vec![outputs[0].clone()], to: vec![200 * T]);
1✔
494
    let (first_spend, _) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
495

496
    let schema = txn_schema!(from: vec![outputs[0].clone()], to: vec![150 * T]);
1✔
497
    let (double_spend, _) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
498

499
    let transactions = initial_tx
1✔
500
        .into_iter()
1✔
501
        .chain(first_spend)
1✔
502
        .chain(double_spend)
1✔
503
        .map(|b| Arc::try_unwrap(b).unwrap())
3✔
504
        .collect::<Vec<_>>();
1✔
505

506
    let (unmined, _) = blockchain
1✔
507
        .create_unmined_block(block_spec!("2", parent: "1", transactions: transactions))
1✔
508
        .await;
1✔
509
    let txn = blockchain.db().db_read_access().unwrap();
1✔
510
    let err = validator.validate_body(&*txn, &unmined).unwrap_err();
1✔
511
    assert!(matches!(
1✔
512
        err,
1✔
513
        ValidationError::AggregatedBodyValidationError(AggregatedBodyValidationError::UnsortedOrDuplicateInput)
1✔
514
    ));
1✔
515
}
1✔
516

517
mod body_only {
518
    use super::*;
519

520
    #[tokio::test]
521
    async fn it_rejects_invalid_input_metadata() {
1✔
522
        let rules = BaseNodeConsensusManager::builder(Network::LocalNet)
1✔
523
            .add_consensus_constants(
1✔
524
                ConsensusConstantsBuilder::new(Network::LocalNet)
1✔
525
                    .with_coinbase_lockheight(0)
1✔
526
                    .build(),
1✔
527
            )
528
            .build()
1✔
529
            .unwrap();
1✔
530
        let mut blockchain = TestBlockchain::create(rules.clone()).await;
1✔
531
        let validator = BlockBodyFullValidator::new(rules, true);
1✔
532

533
        let (_, coinbase_a) = blockchain.add_next_tip(block_spec!("A")).await.unwrap();
1✔
534

535
        let mut schema1 = txn_schema!(from: vec![coinbase_a.clone()], to: vec![50 * T, 12 * T]);
1✔
536
        schema1.from[0].set_sender_offset_public_key(Default::default());
1✔
537
        let (txs, _) = schema_to_transaction(&[schema1], &mut blockchain.km).await;
1✔
538
        let txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::<Vec<_>>();
1✔
539
        let (block, _) = blockchain
1✔
540
            .create_next_tip(BlockSpec::new().with_transactions(txs).finish())
1✔
541
            .await;
1✔
542

543
        let metadata = blockchain.db().get_chain_metadata().unwrap();
1✔
544

545
        let db = blockchain.db().db_read_access().unwrap();
1✔
546
        let err = validator.validate(&*db, block.block(), Some(&metadata)).unwrap_err();
1✔
547
        assert!(matches!(err, ValidationError::UnknownInputs(_)));
1✔
548
    }
1✔
549
}
550

551
mod orphan_validator {
552
    use tari_transaction_components::{transaction_components::OutputType, txn_schema};
553

554
    use super::*;
555
    use crate::validation::block_body::BlockBodyInternalConsistencyValidator;
556

557
    #[tokio::test]
558
    async fn it_rejects_zero_conf_double_spends() {
1✔
559
        let rules = BaseNodeConsensusManager::builder(Network::LocalNet)
1✔
560
            .add_consensus_constants(
1✔
561
                ConsensusConstantsBuilder::new(Network::LocalNet)
1✔
562
                    .with_coinbase_lockheight(0)
1✔
563
                    .build(),
1✔
564
            )
565
            .build()
1✔
566
            .unwrap();
1✔
567
        let mut blockchain = TestBlockchain::create(rules.clone()).await;
1✔
568
        let validator = BlockBodyInternalConsistencyValidator::new(rules, false, CryptoFactories::default());
1✔
569
        let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")).await.unwrap();
1✔
570

571
        let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]);
1✔
572
        let (initial_tx, outputs) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
573

574
        let schema = txn_schema!(from: vec![outputs[0].clone()], to: vec![200 * T]);
1✔
575
        let (first_spend, _) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
576

577
        let schema = txn_schema!(from: vec![outputs[0].clone()], to: vec![150 * T]);
1✔
578
        let (double_spend, _) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
579

580
        let transactions = initial_tx
1✔
581
            .into_iter()
1✔
582
            .chain(first_spend)
1✔
583
            .chain(double_spend)
1✔
584
            .map(|b| Arc::try_unwrap(b).unwrap())
3✔
585
            .collect::<Vec<_>>();
1✔
586

587
        let (unmined, _) = blockchain
1✔
588
            .create_unmined_block(block_spec!("2", parent: "1", transactions: transactions))
1✔
589
            .await;
1✔
590
        let err = validator.validate(&unmined).unwrap_err();
1✔
591
        assert!(matches!(
1✔
592
            err,
1✔
593
            ValidationError::AggregatedBodyValidationError(AggregatedBodyValidationError::UnsortedOrDuplicateInput)
1✔
594
        ));
1✔
595
    }
1✔
596

597
    #[tokio::test]
598
    async fn it_rejects_unpermitted_output_types() {
1✔
599
        let rules = BaseNodeConsensusManager::builder(Network::LocalNet)
1✔
600
            .add_consensus_constants(
1✔
601
                ConsensusConstantsBuilder::new(Network::LocalNet)
1✔
602
                    .with_permitted_output_types(vec![OutputType::Coinbase])
1✔
603
                    .with_coinbase_lockheight(0)
1✔
604
                    .build(),
1✔
605
            )
606
            .build()
1✔
607
            .unwrap();
1✔
608
        let mut blockchain = TestBlockchain::create(rules.clone()).await;
1✔
609
        let validator = BlockBodyInternalConsistencyValidator::new(rules, false, CryptoFactories::default());
1✔
610
        let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")).await.unwrap();
1✔
611

612
        let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]);
1✔
613
        let (tx, _) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
614

615
        let transactions = tx.into_iter().map(|b| Arc::try_unwrap(b).unwrap()).collect::<Vec<_>>();
1✔
616

617
        let (unmined, _) = blockchain
1✔
618
            .create_unmined_block(block_spec!("2", parent: "1", transactions: transactions))
1✔
619
            .await;
1✔
620
        let err = validator.validate(&unmined).unwrap_err();
1✔
621
        unpack_enum!(ValidationError::AggregatedBodyValidationError(err) = err);
1✔
622
        unpack_enum!(AggregatedBodyValidationError::OutputTypeNotPermitted { output_type } = err);
1✔
623
        assert_eq!(output_type, OutputType::Standard);
1✔
624
    }
1✔
625

626
    #[tokio::test]
627
    async fn it_rejects_unpermitted_range_proof_types() {
1✔
628
        let rules = BaseNodeConsensusManager::builder(Network::LocalNet)
1✔
629
            .add_consensus_constants(
1✔
630
                ConsensusConstantsBuilder::new(Network::LocalNet)
1✔
631
                    .with_permitted_range_proof_types(vec![
1✔
632
                        (OutputType::Standard, vec![RangeProofType::RevealedValue]),
1✔
633
                        (OutputType::Coinbase, vec![RangeProofType::RevealedValue]),
1✔
634
                        (OutputType::Burn, vec![RangeProofType::RevealedValue]),
1✔
635
                        (OutputType::ValidatorNodeRegistration, vec![
1✔
636
                            RangeProofType::RevealedValue,
1✔
637
                        ]),
1✔
638
                        (OutputType::CodeTemplateRegistration, vec![
1✔
639
                            RangeProofType::RevealedValue,
1✔
640
                        ]),
1✔
641
                    ])
642
                    .with_coinbase_lockheight(0)
1✔
643
                    .build(),
1✔
644
            )
645
            .build()
1✔
646
            .unwrap();
1✔
647
        let mut blockchain = TestBlockchain::create(rules.clone()).await;
1✔
648
        let validator = BlockBodyInternalConsistencyValidator::new(rules, false, CryptoFactories::default());
1✔
649
        let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")).await.unwrap();
1✔
650

651
        let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]);
1✔
652
        let (tx, _) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
653

654
        let transactions = tx.into_iter().map(|b| Arc::try_unwrap(b).unwrap()).collect::<Vec<_>>();
1✔
655

656
        let (unmined, _) = blockchain
1✔
657
            .create_unmined_block(block_spec!("2", parent: "1", transactions: transactions))
1✔
658
            .await;
1✔
659
        let err = validator.validate(&unmined).unwrap_err();
1✔
660
        unpack_enum!(ValidationError::AggregatedBodyValidationError(err) = err);
1✔
661
        unpack_enum!(AggregatedBodyValidationError::RangeProofTypeNotPermitted { range_proof_type } = err);
1✔
662
        assert_eq!(range_proof_type, RangeProofType::BulletProofPlus);
1✔
663
    }
1✔
664

665
    #[tokio::test]
666
    async fn it_accepts_permitted_range_proof_types() {
1✔
667
        let rules = BaseNodeConsensusManager::builder(Network::LocalNet)
1✔
668
            .add_consensus_constants(
1✔
669
                ConsensusConstantsBuilder::new(Network::LocalNet)
1✔
670
                    .with_permitted_range_proof_types(vec![
1✔
671
                        (OutputType::Standard, vec![RangeProofType::BulletProofPlus]),
1✔
672
                        (OutputType::Coinbase, vec![RangeProofType::BulletProofPlus]),
1✔
673
                        (OutputType::Burn, vec![RangeProofType::BulletProofPlus]),
1✔
674
                        (OutputType::ValidatorNodeRegistration, vec![
1✔
675
                            RangeProofType::BulletProofPlus,
1✔
676
                        ]),
1✔
677
                        (OutputType::CodeTemplateRegistration, vec![
1✔
678
                            RangeProofType::BulletProofPlus,
1✔
679
                        ]),
1✔
680
                    ])
681
                    .with_coinbase_lockheight(0)
1✔
682
                    .build(),
1✔
683
            )
684
            .build()
1✔
685
            .unwrap();
1✔
686
        let mut blockchain = TestBlockchain::create(rules.clone()).await;
1✔
687
        let validator = BlockBodyInternalConsistencyValidator::new(rules, false, CryptoFactories::default());
1✔
688
        let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")).await.unwrap();
1✔
689

690
        let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]);
1✔
691
        let (tx, _) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
692

693
        let transactions = tx.into_iter().map(|b| Arc::try_unwrap(b).unwrap()).collect::<Vec<_>>();
1✔
694

695
        let (unmined, _) = blockchain
1✔
696
            .create_unmined_block(block_spec!("2", parent: "1", transactions: transactions))
1✔
697
            .await;
1✔
698
        assert!(validator.validate(&unmined).is_ok());
1✔
699
    }
1✔
700

701
    #[tokio::test]
702
    async fn it_rejects_when_output_types_are_not_matched() {
1✔
703
        let rules = BaseNodeConsensusManager::builder(Network::LocalNet)
1✔
704
            .add_consensus_constants(
1✔
705
                ConsensusConstantsBuilder::new(Network::LocalNet)
1✔
706
                    .with_permitted_range_proof_types(vec![(OutputType::CodeTemplateRegistration, vec![
1✔
707
                        RangeProofType::BulletProofPlus,
1✔
708
                    ])])
1✔
709
                    .with_coinbase_lockheight(0)
1✔
710
                    .build(),
1✔
711
            )
712
            .build()
1✔
713
            .unwrap();
1✔
714
        let mut blockchain = TestBlockchain::create(rules.clone()).await;
1✔
715
        let validator = BlockBodyInternalConsistencyValidator::new(rules, false, CryptoFactories::default());
1✔
716
        let (_, coinbase) = blockchain.append(block_spec!("1", parent: "GB")).await.unwrap();
1✔
717

718
        let schema = txn_schema!(from: vec![coinbase.clone()], to: vec![201 * T]);
1✔
719
        let (tx, _) = schema_to_transaction(&[schema], &mut blockchain.km).await;
1✔
720

721
        let transactions = tx.into_iter().map(|b| Arc::try_unwrap(b).unwrap()).collect::<Vec<_>>();
1✔
722

723
        let (unmined, _) = blockchain
1✔
724
            .create_unmined_block(block_spec!("2", parent: "1", transactions: transactions))
1✔
725
            .await;
1✔
726
        let err = validator.validate(&unmined).unwrap_err();
1✔
727
        unpack_enum!(ValidationError::AggregatedBodyValidationError(err) = err);
1✔
728
        unpack_enum!(AggregatedBodyValidationError::OutputTypeNotMatchedToRangeProofType { output_type } = err);
1✔
729
        assert!(output_type == OutputType::Standard || output_type == OutputType::Coinbase);
1✔
730
    }
1✔
731
}
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

© 2025 Coveralls, Inc