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

tari-project / tari / 17102421478

20 Aug 2025 03:06PM UTC coverage: 54.344% (-0.8%) from 55.122%
17102421478

push

github

web-flow
chore: new release v5.0.0-pre.4 (#7429)

Description
---
new release

75834 of 139544 relevant lines covered (54.34%)

457214.47 hits per line

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

0.0
/base_layer/core/src/validation/error.rs
1
// Copyright 2019. 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_common_types::{epoch::VnEpoch, types::HashOutput};
24
use tari_sidechain::SidechainProofValidationError;
25
use tari_utilities::ByteArrayError;
26
use thiserror::Error;
27

28
use crate::{
29
    blocks::{BlockHeaderValidationError, BlockValidationError},
30
    chain_storage::ChainStorageError,
31
    common::{BanPeriod, BanReason},
32
    covenants::CovenantError,
33
    proof_of_work::{cuckaroo_pow::CuckarooVerificationError, monero_rx::MergeMineError, DifficultyError, PowError},
34
    transactions::{
35
        tari_amount::MicroMinotari,
36
        transaction_components::{OutputType, RangeProofType, TransactionError},
37
    },
38
};
39

40
#[derive(Debug, Error)]
41
pub enum ValidationError {
42
    #[error("Serialization failed: {0}")]
43
    SerializationError(String),
44
    #[error("Block header validation failed: {0}")]
45
    BlockHeaderError(#[from] BlockHeaderValidationError),
46
    #[error("Block validation error: {0}")]
47
    BlockError(#[from] BlockValidationError),
48
    #[error("Contains kernels or inputs that are not yet spendable")]
49
    MaturityError,
50
    #[error("The block weight ({actual_weight}) is above the maximum ({max_weight})")]
51
    BlockTooLarge { actual_weight: u64, max_weight: u64 },
52
    #[error("Contains {} unknown inputs", .0.len())]
53
    UnknownInputs(Vec<HashOutput>),
54
    #[error("Contains an unknown input")]
55
    UnknownInput,
56
    #[error("The transaction is invalid: {0}")]
57
    TransactionError(#[from] TransactionError),
58
    #[error("Fatal storage error during validation: {0}")]
59
    FatalStorageError(String),
60
    #[error(
61
        "The total expected supply plus the total accumulated (offset) excess does not equal the sum of all UTXO \
62
         commitments."
63
    )]
64
    InvalidAccountingBalance,
65
    #[error("Transaction contains already spent inputs")]
66
    ContainsSTxO,
67
    #[error("Transaction contains outputs that already exist")]
68
    ContainsTxO,
69
    #[error("Transaction contains an output commitment that already exists")]
70
    ContainsDuplicateUtxoCommitment,
71
    #[error("Final state validation failed: The UTXO set did not balance with the expected emission at height {0}")]
72
    ChainBalanceValidationFailed(u64),
73
    #[error("The total value + fees of the block exceeds the maximum allowance on chain")]
74
    CoinbaseExceedsMaxLimit,
75
    #[error("Proof of work error: {0}")]
76
    ProofOfWorkError(#[from] PowError),
77
    #[error("Attempted to validate genesis block")]
78
    ValidatingGenesis,
79
    #[error("Duplicate or unsorted input found in block body")]
80
    UnsortedOrDuplicateInput,
81
    #[error("Duplicate or unsorted output found in block body")]
82
    UnsortedOrDuplicateOutput,
83
    #[error("Duplicate or unsorted kernel found in block body")]
84
    UnsortedOrDuplicateKernel,
85
    #[error("Error in merge mine data:{0}")]
86
    MergeMineError(#[from] MergeMineError),
87
    #[error("Maximum transaction weight exceeded")]
88
    MaxTransactionWeightExceeded,
89
    #[error("Expected block height to be {expected}, but was {block_height}")]
90
    IncorrectHeight { expected: u64, block_height: u64 },
91
    #[error("Expected block previous hash to be {expected}, but was {block_hash}")]
92
    IncorrectPreviousHash { expected: String, block_hash: String },
93
    #[error("Bad block with hash '{hash}' and reason '{reason}' found")]
94
    BadBlockFound { hash: String, reason: String },
95
    #[error("Script exceeded maximum script size, expected less than {max_script_size} but was {actual_script_size}")]
96
    TariScriptExceedsMaxSize {
97
        max_script_size: usize,
98
        actual_script_size: usize,
99
    },
100
    #[error(
101
        "Encrypted data exceeded maximum encrytped data size, expected less than {max_encrypted_data_size} but was \
102
         {actual_encrypted_data_size}"
103
    )]
104
    EncryptedDataExceedsMaxSize {
105
        max_encrypted_data_size: usize,
106
        actual_encrypted_data_size: usize,
107
    },
108
    #[error("Consensus Error: {0}")]
109
    ConsensusError(String),
110
    #[error("Duplicate kernel Error: {0}")]
111
    DuplicateKernelError(String),
112
    #[error("Covenant failed to validate: {0}")]
113
    CovenantError(#[from] CovenantError),
114
    #[error("Invalid or unsupported blockchain version {version}")]
115
    InvalidBlockchainVersion { version: u16 },
116
    #[error("Contains Invalid Burn: {0}")]
117
    InvalidBurnError(String),
118
    #[error("Output type '{output_type}' is not permitted")]
119
    OutputTypeNotPermitted { output_type: OutputType },
120
    #[error("Range proof type '{range_proof_type}' is not permitted")]
121
    RangeProofTypeNotPermitted { range_proof_type: RangeProofType },
122
    #[error("Output type '{output_type}' is not matched to any range proof type")]
123
    OutputTypeNotMatchedToRangeProofType { output_type: OutputType },
124
    #[error("Validator registration has invalid minimum amount {actual}, must be at least {min}")]
125
    ValidatorNodeRegistrationMinDepositAmount { min: MicroMinotari, actual: MicroMinotari },
126
    #[error("Validator registration has invalid maturity {actual}, must be at least {min}")]
127
    ValidatorNodeRegistrationMinLockHeight { min: u64, actual: u64 },
128
    #[error("Sidechain ID knowledge proof not valid for template registration")]
129
    TemplateInvalidSidechainIdKnowledgeProof,
130
    #[error("Author signature not valid for template registration")]
131
    TemplateAuthorSignatureNotValid,
132
    #[error("Sidechain ID knowledge proof not valid for confidential output")]
133
    ConfidentialOutputSidechainIdKnowledgeProofNotValid,
134
    #[error("Validator node registration signature failed verification")]
135
    InvalidValidatorNodeSignature,
136
    #[error("Sidechain ID knowledge proof not valid for validator node registration")]
137
    ValidatorNodeInvalidSidechainIdKnowledgeProof,
138
    #[error(
139
        "An unexpected number of timestamps were provided to the header validator. THIS IS A BUG. Expected \
140
         {expected}, got {actual}"
141
    )]
142
    IncorrectNumberOfTimestampsProvided { expected: u64, actual: u64 },
143
    #[error("Invalid difficulty: {0}")]
144
    DifficultyError(#[from] DifficultyError),
145
    #[error("Covenant too large. Max size: {max_size}, Actual size: {actual_size}")]
146
    CovenantTooLarge { max_size: usize, actual_size: usize },
147
    #[error("Invalid Serialized Public key: {0}")]
148
    InvalidSerializedPublicKey(String),
149
    #[error("Sidechain proof invalid: `{0}`")]
150
    SidechainProofInvalid(#[from] SidechainProofValidationError),
151
    #[error("Sidechain eviction proof submitted for unregistered validator {validator_pk}")]
152
    SidechainEvictionProofValidatorNotFound { validator_pk: String },
153
    #[error(
154
        "Sidechain eviction proof invalid: given epoch {epoch} is greater than the epoch at tip height {tip_height}"
155
    )]
156
    SidechainEvictionProofInvalidEpoch { epoch: VnEpoch, tip_height: u64 },
157
    #[error("Validator node already registered: {public_key}")]
158
    ValidatorNodeAlreadyRegistered { public_key: String },
159
    #[error("Validator node {public_key} not registered: {details}")]
160
    ValidatorNodeNotRegistered { public_key: String, details: String },
161
    #[error("Validator registration {public_key} invalid: max epoch {max_epoch} < current epoch {current_epoch}")]
162
    ValidatorNodeRegistrationMaxEpoch {
163
        public_key: String,
164
        current_epoch: VnEpoch,
165
        max_epoch: VnEpoch,
166
    },
167
    #[error("{output_type} output rule disallows the spend: {details}")]
168
    OutputSpendRuleDisallow { output_type: OutputType, details: String },
169
    #[error("Output type '{output_type}' does not match sidechain data")]
170
    OutputTypeNotMatchSidechainData { output_type: OutputType, details: String },
171
    #[error("Cuckaroo POW error: {0}")]
172
    CuckarooPowError(#[from] CuckarooVerificationError),
173
}
174

175
// ChainStorageError has a ValidationError variant, so to prevent a cyclic dependency we use a string representation in
176
// for storage errors that cause validation failures.
177
impl From<ChainStorageError> for ValidationError {
178
    fn from(err: ChainStorageError) -> Self {
×
179
        Self::FatalStorageError(err.to_string())
×
180
    }
×
181
}
182

183
impl From<ByteArrayError> for ValidationError {
184
    fn from(err: ByteArrayError) -> Self {
×
185
        Self::InvalidSerializedPublicKey(err.to_string())
×
186
    }
×
187
}
188

189
impl ValidationError {
190
    pub fn get_ban_reason(&self) -> Option<BanReason> {
×
191
        match self {
×
192
            ValidationError::ProofOfWorkError(e) => e.get_ban_reason(),
×
193
            err @ ValidationError::SerializationError(_) |
×
194
            err @ ValidationError::BlockHeaderError(_) |
×
195
            err @ ValidationError::BlockError(_) |
×
196
            err @ ValidationError::MaturityError |
×
197
            err @ ValidationError::BlockTooLarge { .. } |
×
198
            err @ ValidationError::UnknownInputs(_) |
×
199
            err @ ValidationError::UnknownInput |
×
200
            err @ ValidationError::TransactionError(_) |
×
201
            err @ ValidationError::InvalidAccountingBalance |
×
202
            err @ ValidationError::ContainsSTxO |
×
203
            err @ ValidationError::ContainsTxO |
×
204
            err @ ValidationError::ContainsDuplicateUtxoCommitment |
×
205
            err @ ValidationError::ChainBalanceValidationFailed(_) |
×
206
            err @ ValidationError::ValidatingGenesis |
×
207
            err @ ValidationError::UnsortedOrDuplicateInput |
×
208
            err @ ValidationError::UnsortedOrDuplicateOutput |
×
209
            err @ ValidationError::UnsortedOrDuplicateKernel |
×
210
            err @ ValidationError::MaxTransactionWeightExceeded |
×
211
            err @ ValidationError::IncorrectHeight { .. } |
×
212
            err @ ValidationError::IncorrectPreviousHash { .. } |
×
213
            err @ ValidationError::BadBlockFound { .. } |
×
214
            err @ ValidationError::TariScriptExceedsMaxSize { .. } |
×
215
            err @ ValidationError::EncryptedDataExceedsMaxSize { .. } |
×
216
            err @ ValidationError::ConsensusError(_) |
×
217
            err @ ValidationError::DuplicateKernelError(_) |
×
218
            err @ ValidationError::CovenantError(_) |
×
219
            err @ ValidationError::InvalidBlockchainVersion { .. } |
×
220
            err @ ValidationError::InvalidBurnError(_) |
×
221
            err @ ValidationError::OutputTypeNotPermitted { .. } |
×
222
            err @ ValidationError::RangeProofTypeNotPermitted { .. } |
×
223
            err @ ValidationError::OutputTypeNotMatchedToRangeProofType { .. } |
×
224
            err @ ValidationError::ValidatorNodeRegistrationMinDepositAmount { .. } |
×
225
            err @ ValidationError::ValidatorNodeRegistrationMinLockHeight { .. } |
×
226
            err @ ValidationError::InvalidValidatorNodeSignature |
×
227
            err @ ValidationError::ValidatorNodeInvalidSidechainIdKnowledgeProof |
×
228
            err @ ValidationError::TemplateInvalidSidechainIdKnowledgeProof |
×
229
            err @ ValidationError::TemplateAuthorSignatureNotValid |
×
230
            err @ ValidationError::ConfidentialOutputSidechainIdKnowledgeProofNotValid |
×
231
            err @ ValidationError::DifficultyError(_) |
×
232
            err @ ValidationError::CoinbaseExceedsMaxLimit |
×
233
            err @ ValidationError::CovenantTooLarge { .. } |
×
234
            err @ ValidationError::InvalidSerializedPublicKey(_) |
×
235
            err @ ValidationError::SidechainEvictionProofValidatorNotFound { .. } |
×
236
            err @ ValidationError::SidechainProofInvalid(_) |
×
237
            err @ ValidationError::SidechainEvictionProofInvalidEpoch { .. } |
×
238
            err @ ValidationError::ValidatorNodeAlreadyRegistered { .. } |
×
239
            err @ ValidationError::ValidatorNodeNotRegistered { .. } |
×
240
            err @ ValidationError::ValidatorNodeRegistrationMaxEpoch { .. } |
×
241
            err @ ValidationError::OutputTypeNotMatchSidechainData { .. } |
×
242
            err @ ValidationError::CuckarooPowError(_) |
×
243
            err @ ValidationError::OutputSpendRuleDisallow { .. } => Some(BanReason {
×
244
                reason: err.to_string(),
×
245
                ban_duration: BanPeriod::Long,
×
246
            }),
×
247
            ValidationError::MergeMineError(e) => e.get_ban_reason(),
×
248
            ValidationError::FatalStorageError(_) | ValidationError::IncorrectNumberOfTimestampsProvided { .. } => None,
×
249
        }
250
    }
×
251
}
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