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

tari-project / tari / 19673252153

25 Nov 2025 02:37PM UTC coverage: 60.373% (-1.0%) from 61.332%
19673252153

push

github

web-flow
feat: improve base node check-db command (#7576)

Description
---
1. Improved the 'check-db' command to perform:
  - accumulated difficulty, with or without autocorrect;
- blockchain consistency light mode - block and header readability in
the database, with or without autocorrect;
- blockchain consistency full mode - block and header readability in the
database with block contents validation, with or without autocorrect;
- accumulated difficulty + blockchain consistency (light/full), with or
without autocorrect.

2. Added a low-level function to the lmdb_db to report on and verify
metadata keys. Corrupt non-essential keys will be auto-deleted.

The 'check-db' command runs and reports in the background, check status
persists across base node restarts and consecutive 'check-db' runs, and
'check-db' runs can be stopped at any time or restarted from the genesis
block.

```
>> check-db -h

USAGE:
    check-db [OPTIONS] --mode <MODE>

OPTIONS:
    -b, --breathing-time-ms <BREATHING_TIME_MS>
            Milli-seconds 'breathing time' between consecutive checks - very short breathing time
            may starve other critical tasks (minimum 1 ms, maximum 1000ms, default 10ms) [default:
            10]

        --do-not-clear-counters-on-error-or-stop
            Option to not clear counters when error detected or user requested a stop (Default:
            false). Note: This is a long-winded-option-to-write intended for expert use

    -h, --help
            Print help information

    -m, --mode <MODE>
            What to check [possible values: light-chain, light-autocorrect, full-chain,
            full-autocorrect, acc-diff, acc-diff-autocorrect, all-light, all-full,
            all-light-autocorrect, all-full-autocorrect, print-status, reset-counters, stop]

    -p, --poll-seconds <POLL_SECONDS>
            Seconds between status polls (default 15s) [default: 15]
```

Fixes #7575.

Motivation and Context
---

The 'check-db' command only verified that al... (continued)

106 of 1034 new or added lines in 9 files covered. (10.25%)

2045 existing lines in 41 files now uncovered.

69949 of 115862 relevant lines covered (60.37%)

689701.92 hits per line

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

17.31
/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
use tari_common_types::{epoch::VnEpoch, types::HashOutput};
23
use tari_node_components::blocks::{BlockHeaderValidationError, BlockValidationError};
24
use tari_sidechain::SidechainProofValidationError;
25
use tari_transaction_components::{
26
    tari_proof_of_work::{DifficultyError, PowError},
27
    transaction_components::{covenants::CovenantError, OutputType, TransactionError},
28
    validation::AggregatedBodyValidationError,
29
    BanPeriod,
30
    BanReason,
31
};
32
use tari_utilities::ByteArrayError;
33
use thiserror::Error;
34

35
use crate::{
36
    chain_storage::ChainStorageError,
37
    proof_of_work::{cuckaroo_pow::CuckarooVerificationError, monero_rx::MergeMineError},
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 an output commitment that already exists")]
68
    ContainsDuplicateUtxoCommitment,
69
    #[error("Final state validation failed: The UTXO set did not balance with the expected emission at height {0}")]
70
    ChainBalanceValidationFailed(u64),
71
    #[error("The total value + fees of the block exceeds the maximum allowance on chain")]
72
    CoinbaseExceedsMaxLimit,
73
    #[error("Proof of work error: {0}")]
74
    ProofOfWorkError(#[from] PowError),
75
    #[error("Attempted to validate genesis block")]
76
    ValidatingGenesis,
77
    #[error("Duplicate or unsorted input found in block body")]
78
    UnsortedOrDuplicateInput,
79
    #[error("Duplicate or unsorted output found in block body")]
80
    UnsortedOrDuplicateOutput,
81
    #[error("Error in merge mine data:{0}")]
82
    MergeMineError(#[from] MergeMineError),
83
    #[error("Maximum transaction weight exceeded")]
84
    MaxTransactionWeightExceeded,
85
    #[error("Expected block height to be {expected}, but was {block_height}")]
86
    IncorrectHeight { expected: u64, block_height: u64 },
87
    #[error("Expected block previous hash to be {expected}, but was {block_hash}")]
88
    IncorrectPreviousHash { expected: String, block_hash: String },
89
    #[error("Bad block with hash '{hash}' and reason '{reason}' found")]
90
    BadBlockFound { hash: String, reason: String },
91
    #[error("Consensus Error: {0}")]
92
    ConsensusError(String),
93
    #[error("Duplicate kernel error: {0}")]
94
    DuplicateKernelError(String),
95
    #[error("Missing kernel error: {0}")]
96
    MissingKernelError(String),
97
    #[error("Header height mismatch error: {0}")]
98
    HeaderHeightMismatch(String),
99
    #[error("Header hash mismatch error: {0}")]
100
    HeaderHashMismatch(String),
101
    #[error("Missing output error: {0}")]
102
    MissingOutputError(String),
103
    #[error("Input spent before mined error: {0}")]
104
    InputSpentBeforeMined(String),
105
    #[error("Covenant failed to validate: {0}")]
106
    CovenantError(#[from] CovenantError),
107
    #[error("Invalid or unsupported blockchain version {version}")]
108
    InvalidBlockchainVersion { version: u16 },
109
    #[error("Contains Invalid Burn: {0}")]
110
    InvalidBurnError(String),
111
    #[error("Validator node registration signature failed verification")]
112
    IncorrectNumberOfTimestampsProvided { expected: u64, actual: u64 },
113
    #[error("Invalid difficulty: {0}")]
114
    DifficultyError(#[from] DifficultyError),
115
    #[error("Invalid Serialized Public key: {0}")]
116
    InvalidSerializedPublicKey(String),
117
    #[error("Sidechain proof invalid: `{0}`")]
118
    SidechainProofInvalid(#[from] SidechainProofValidationError),
119
    #[error("Sidechain eviction proof submitted for unregistered validator {validator_pk}")]
120
    SidechainEvictionProofValidatorNotFound { validator_pk: String },
121
    #[error(
122
        "Sidechain eviction proof invalid: given epoch {epoch} is greater than the epoch at tip height {tip_height}"
123
    )]
124
    SidechainEvictionProofInvalidEpoch { epoch: VnEpoch, tip_height: u64 },
125
    #[error("Validator node already registered: {public_key}")]
126
    ValidatorNodeAlreadyRegistered { public_key: String },
127
    #[error("Validator node {public_key} not registered: {details}")]
128
    ValidatorNodeNotRegistered { public_key: String, details: String },
129
    #[error("Validator registration {public_key} invalid: max epoch {max_epoch} < current epoch {current_epoch}")]
130
    ValidatorNodeRegistrationMaxEpoch {
131
        public_key: String,
132
        current_epoch: VnEpoch,
133
        max_epoch: VnEpoch,
134
    },
135
    #[error("{output_type} output rule disallows the spend: {details}")]
136
    OutputSpendRuleDisallow { output_type: OutputType, details: String },
137
    #[error("Output type '{output_type}' does not match sidechain data")]
138
    OutputTypeNotMatchSidechainData { output_type: OutputType, details: String },
139
    #[error("Validation error: {0}")]
140
    AggregatedBodyValidationError(#[from] AggregatedBodyValidationError),
141
    #[error("Cuckaroo POW error: {0}")]
142
    CuckarooPowError(#[from] CuckarooVerificationError),
143
}
144

145
// ChainStorageError has a ValidationError variant, so to prevent a cyclic dependency we use a string representation in
146
// for storage errors that cause validation failures.
147
impl From<ChainStorageError> for ValidationError {
148
    fn from(err: ChainStorageError) -> Self {
×
149
        Self::FatalStorageError(err.to_string())
×
150
    }
×
151
}
152

153
impl From<ByteArrayError> for ValidationError {
154
    fn from(err: ByteArrayError) -> Self {
×
155
        Self::InvalidSerializedPublicKey(err.to_string())
×
156
    }
×
157
}
158

159
impl ValidationError {
160
    pub fn get_ban_reason(&self) -> Option<BanReason> {
4✔
161
        match self {
4✔
162
            ValidationError::ProofOfWorkError(e) => e.get_ban_reason(),
×
163
            err @ ValidationError::SerializationError(_) |
×
164
            err @ ValidationError::BlockHeaderError(_) |
2✔
165
            err @ ValidationError::BlockError(_) |
×
166
            err @ ValidationError::MaturityError |
×
167
            err @ ValidationError::BlockTooLarge { .. } |
×
168
            err @ ValidationError::UnknownInputs(_) |
×
169
            err @ ValidationError::UnknownInput |
×
170
            err @ ValidationError::TransactionError(_) |
×
171
            err @ ValidationError::InvalidAccountingBalance |
×
172
            err @ ValidationError::ContainsSTxO |
×
173
            err @ ValidationError::ContainsDuplicateUtxoCommitment |
×
174
            err @ ValidationError::ChainBalanceValidationFailed(_) |
×
175
            err @ ValidationError::ValidatingGenesis |
×
176
            err @ ValidationError::UnsortedOrDuplicateInput |
×
177
            err @ ValidationError::UnsortedOrDuplicateOutput |
×
178
            err @ ValidationError::MaxTransactionWeightExceeded |
×
179
            err @ ValidationError::IncorrectHeight { .. } |
×
180
            err @ ValidationError::IncorrectPreviousHash { .. } |
×
181
            err @ ValidationError::BadBlockFound { .. } |
×
182
            err @ ValidationError::ConsensusError(_) |
2✔
183
            err @ ValidationError::DuplicateKernelError(_) |
×
184
            err @ ValidationError::CovenantError(_) |
×
185
            err @ ValidationError::InvalidBlockchainVersion { .. } |
×
186
            err @ ValidationError::InvalidBurnError(_) |
×
187
            err @ ValidationError::DifficultyError(_) |
×
188
            err @ ValidationError::CoinbaseExceedsMaxLimit |
×
189
            err @ ValidationError::InvalidSerializedPublicKey(_) |
×
190
            err @ ValidationError::SidechainEvictionProofValidatorNotFound { .. } |
×
191
            err @ ValidationError::SidechainProofInvalid(_) |
×
192
            err @ ValidationError::SidechainEvictionProofInvalidEpoch { .. } |
×
193
            err @ ValidationError::ValidatorNodeAlreadyRegistered { .. } |
×
194
            err @ ValidationError::ValidatorNodeNotRegistered { .. } |
×
195
            err @ ValidationError::ValidatorNodeRegistrationMaxEpoch { .. } |
×
196
            err @ ValidationError::OutputTypeNotMatchSidechainData { .. } |
×
197
            err @ ValidationError::AggregatedBodyValidationError(_) |
×
198
            err @ ValidationError::CuckarooPowError(_) |
×
199
            err @ ValidationError::OutputSpendRuleDisallow { .. } => Some(BanReason {
4✔
200
                reason: err.to_string(),
4✔
201
                ban_duration: BanPeriod::Long,
4✔
202
            }),
4✔
203
            ValidationError::MergeMineError(e) => e.get_ban_reason(),
×
204
            ValidationError::FatalStorageError(_) |
205
            ValidationError::IncorrectNumberOfTimestampsProvided { .. } |
206
            ValidationError::MissingKernelError(_) |
207
            ValidationError::MissingOutputError(_) |
208
            ValidationError::InputSpentBeforeMined(_) |
209
            ValidationError::HeaderHashMismatch(_) |
NEW
210
            ValidationError::HeaderHeightMismatch(_) => None,
×
211
        }
212
    }
4✔
213
}
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