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

tari-project / tari / 25922390800

15 May 2026 02:09PM UTC coverage: 61.163% (+0.7%) from 60.448%
25922390800

push

github

SWvheerden
chore: fix script

71338 of 116635 relevant lines covered (61.16%)

222847.95 hits per line

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

21.84
/base_layer/core/src/chain_storage/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 lmdb_zero::error;
24
use tari_common_types::{chain_metadata::ChainMetaDataError, types::FixedHashSizeError};
25
use tari_mmr::{MerkleProofError, error::MerkleMountainRangeError, sparse_merkle_tree::SMTError};
26
use tari_node_components::blocks::BlockError;
27
use tari_storage::lmdb_store::LMDBError;
28
use tari_transaction_components::{
29
    BanPeriod,
30
    BanReason,
31
    tari_proof_of_work::PowError,
32
    transaction_components::TransactionError,
33
};
34
use tari_utilities::ByteArrayError;
35
use thiserror::Error;
36
use tokio::task;
37

38
use crate::{MrHashError, chain_storage::MmrTree, validation::ValidationError};
39
#[derive(Debug, Error)]
40
pub enum ChainStorageError {
41
    #[error("Access to the underlying storage mechanism failed: {0}")]
42
    AccessError(String),
43
    #[error(
44
        "The database may be corrupted or otherwise be in an inconsistent state. Please check logs to try and \
45
         identify the issue: {0}"
46
    )]
47
    CorruptedDatabase(String),
48
    #[error("A given input could not be spent because it was not in the UTXO set")]
49
    UnspendableInput,
50
    #[error("A problem occurred trying to move a STXO back into the UTXO pool during a reorg.")]
51
    UnspendError,
52
    #[error(
53
        "An unexpected result type was received for the given database request. This suggests that there is an \
54
         internal error or bug of sorts: {0}"
55
    )]
56
    UnexpectedResult(String),
57
    #[error("You tried to execute an invalid Database operation: {0}")]
58
    InvalidOperation(String),
59
    #[error("DATABASE INCONSISTENCY DETECTED at {function}: {details}")]
60
    DataInconsistencyDetected { function: &'static str, details: String },
61
    #[error("There appears to be a critical error on the back end: {0}. Check the logs for more information.")]
62
    CriticalError(String),
63
    #[error("Could not insert {table}: {error}")]
64
    InsertError { table: &'static str, error: String },
65
    #[error("An invalid query was attempted: {0}")]
66
    InvalidQuery(String),
67
    #[error("PayRef index not available: current `{current_height}`, start `{start_height}`, target `{target_height}`")]
68
    PayRefIndexNotAvailable {
69
        current_height: u64,
70
        start_height: u64,
71
        target_height: u64,
72
    },
73
    #[error("Invalid argument `{arg}` in `{func}`: {message}")]
74
    InvalidArguments {
75
        func: &'static str,
76
        arg: &'static str,
77
        message: String,
78
    },
79
    #[error("The requested {entity} was not found via {field}:{value} in the database")]
80
    ValueNotFound {
81
        entity: &'static str,
82
        field: &'static str,
83
        value: String,
84
    },
85
    #[error("MMR error: {source}")]
86
    MerkleMountainRangeError {
87
        #[from]
88
        source: MerkleMountainRangeError,
89
    },
90
    #[error("Merkle proof error: {source}")]
91
    MerkleProofError {
92
        #[from]
93
        source: MerkleProofError,
94
    },
95
    #[error("Validation error: {source}")]
96
    ValidationError {
97
        #[from]
98
        source: ValidationError,
99
    },
100
    #[error("The MMR root for {0} in the provided block header did not match the MMR root in the database")]
101
    MismatchedMmrRoot(MmrTree),
102
    #[error("An invalid block was submitted to the database: {0}")]
103
    InvalidBlock(String),
104
    #[error("Blocking task spawn error: {0}")]
105
    BlockingTaskSpawnError(String),
106
    #[error("A request was out of range")]
107
    OutOfRange,
108
    #[error("LMDB error: {source}")]
109
    LmdbError {
110
        #[from]
111
        source: LMDBError,
112
    },
113
    #[error("Invalid proof of work: {source}")]
114
    ProofOfWorkError {
115
        #[from]
116
        source: PowError,
117
    },
118
    #[error("Cannot acquire exclusive file lock, another instance of the application is already running")]
119
    CannotAcquireFileLock,
120
    #[error("IO Error: `{0}`")]
121
    IoError(#[from] std::io::Error),
122
    #[error("Cannot calculate MMR roots for block that does not form a chain with the current tip. {0}")]
123
    CannotCalculateNonTipMmr(String),
124
    #[error("Key {key} in {table_name} already exists")]
125
    KeyExists { table_name: &'static str, key: String },
126
    #[error("Database resize required")]
127
    DbResizeRequired(Option<usize>),
128
    #[error("DB transaction was too large ({0} operations)")]
129
    DbTransactionTooLarge(usize),
130
    #[error("DB needs to be resynced: {0}")]
131
    DatabaseResyncRequired(&'static str),
132
    #[error("Block error: {0}")]
133
    BlockError(#[from] BlockError),
134
    #[error("Add block is currently locked. No blocks may be added using add_block until the flag is cleared.")]
135
    AddBlockOperationLocked,
136
    #[error("Transaction Error: {0}")]
137
    TransactionError(#[from] TransactionError),
138
    #[error("Could not convert data:{0}")]
139
    ConversionError(String),
140
    #[error("FixedHashSize Error: {0}")]
141
    FixedHashSizeError(#[from] FixedHashSizeError),
142
    #[error("Composite key length was exceeded (THIS SHOULD NEVER HAPPEN)")]
143
    CompositeKeyLengthExceeded,
144
    #[error("Failed to decode key bytes: {0}")]
145
    FromKeyBytesFailed(String),
146
    #[error("Sparse Merkle Tree error: {0}")]
147
    SMTError(#[from] SMTError),
148
    #[error("Invalid ChainMetaData: {0}")]
149
    InvalidChainMetaData(#[from] ChainMetaDataError),
150
    #[error("Block header error: `{0}`")]
151
    MrHashError(#[from] MrHashError),
152
    #[error("Invalid Serialized Public key: {0}")]
153
    InvalidSerializedPublicKey(String),
154
    #[error("JellyfishMerkleTree error: {0}")]
155
    JellyfishMerkleTreeError(anyhow::Error),
156
    #[error("Cannot perform accumulated difficulty check while its migration task is still in progress")]
157
    AccDataMigrationStillInProgress,
158
}
159

160
impl ChainStorageError {
161
    pub fn is_value_not_found(&self) -> bool {
9✔
162
        matches!(self, ChainStorageError::ValueNotFound { .. })
9✔
163
    }
9✔
164

165
    pub fn is_key_exist_error(&self) -> bool {
×
166
        matches!(self, ChainStorageError::KeyExists { .. })
×
167
    }
×
168

169
    pub fn get_ban_reason(&self) -> Option<BanReason> {
2✔
170
        match self {
2✔
171
            ChainStorageError::ProofOfWorkError { source: e } => e.get_ban_reason(),
×
172
            ChainStorageError::ValidationError { source: e } => e.get_ban_reason(),
2✔
173
            err @ ChainStorageError::UnspendableInput |
×
174
            err @ ChainStorageError::MerkleMountainRangeError { .. } |
×
175
            err @ ChainStorageError::MismatchedMmrRoot(_) |
×
176
            err @ ChainStorageError::TransactionError(_) |
×
177
            err @ ChainStorageError::SMTError(_) |
×
178
            err @ ChainStorageError::InvalidSerializedPublicKey(_) => Some(BanReason {
×
179
                reason: err.to_string(),
×
180
                ban_duration: BanPeriod::Long,
×
181
            }),
×
182
            _err @ ChainStorageError::AccessError(_) |
×
183
            _err @ ChainStorageError::CorruptedDatabase(_) |
×
184
            _err @ ChainStorageError::UnexpectedResult(_) |
×
185
            _err @ ChainStorageError::InvalidOperation(_) |
×
186
            _err @ ChainStorageError::UnspendError |
×
187
            _err @ ChainStorageError::DataInconsistencyDetected { .. } |
×
188
            _err @ ChainStorageError::CriticalError(_) |
×
189
            _err @ ChainStorageError::InsertError { .. } |
×
190
            _err @ ChainStorageError::InvalidQuery(_) |
×
191
            _err @ ChainStorageError::InvalidArguments { .. } |
×
192
            _err @ ChainStorageError::ValueNotFound { .. } |
×
193
            _err @ ChainStorageError::MerkleProofError { .. } |
×
194
            _err @ ChainStorageError::InvalidBlock(_) |
×
195
            _err @ ChainStorageError::BlockingTaskSpawnError(_) |
×
196
            _err @ ChainStorageError::LmdbError { .. } |
×
197
            _err @ ChainStorageError::CannotAcquireFileLock |
×
198
            _err @ ChainStorageError::IoError(_) |
×
199
            _err @ ChainStorageError::CannotCalculateNonTipMmr(_) |
×
200
            _err @ ChainStorageError::KeyExists { .. } |
×
201
            _err @ ChainStorageError::DbResizeRequired(_) |
×
202
            _err @ ChainStorageError::DbTransactionTooLarge(_) |
×
203
            _err @ ChainStorageError::DatabaseResyncRequired(_) |
×
204
            _err @ ChainStorageError::BlockError(_) |
×
205
            _err @ ChainStorageError::AddBlockOperationLocked |
×
206
            _err @ ChainStorageError::ConversionError(_) |
×
207
            _err @ ChainStorageError::FixedHashSizeError(_) |
×
208
            _err @ ChainStorageError::CompositeKeyLengthExceeded |
×
209
            _err @ ChainStorageError::FromKeyBytesFailed(_) |
×
210
            _err @ ChainStorageError::InvalidChainMetaData(_) |
×
211
            _err @ ChainStorageError::OutOfRange |
×
212
            _err @ ChainStorageError::MrHashError(_) |
×
213
            _err @ ChainStorageError::JellyfishMerkleTreeError(_) |
×
214
            _err @ ChainStorageError::PayRefIndexNotAvailable { .. } |
×
215
            _err @ ChainStorageError::AccDataMigrationStillInProgress => None,
×
216
        }
217
    }
2✔
218
}
219

220
impl From<ByteArrayError> for ChainStorageError {
221
    fn from(err: ByteArrayError) -> Self {
×
222
        Self::InvalidSerializedPublicKey(err.to_string())
×
223
    }
×
224
}
225

226
impl From<task::JoinError> for ChainStorageError {
227
    fn from(err: task::JoinError) -> Self {
×
228
        Self::BlockingTaskSpawnError(err.to_string())
×
229
    }
×
230
}
231

232
impl From<lmdb_zero::Error> for ChainStorageError {
233
    fn from(err: lmdb_zero::Error) -> Self {
×
234
        use lmdb_zero::Error::Code;
235
        match err {
×
236
            Code(error::NOTFOUND) => ChainStorageError::ValueNotFound {
×
237
                entity: "<unspecified entity>",
×
238
                field: "<unknown>",
×
239
                value: "<unknown>".to_string(),
×
240
            },
×
241
            Code(error::MAP_FULL) => ChainStorageError::DbResizeRequired(None),
×
242
            _ => ChainStorageError::AccessError(err.to_string()),
×
243
        }
244
    }
×
245
}
246

247
pub trait Optional<U> {
248
    fn optional(self) -> Result<Option<U>, ChainStorageError>;
249
}
250

251
impl<U> Optional<U> for Result<U, ChainStorageError> {
252
    fn optional(self) -> Result<Option<U>, ChainStorageError> {
507✔
253
        match self {
7✔
254
            Ok(item) => Ok(Some(item)),
500✔
255
            Err(err) if err.is_value_not_found() => Ok(None),
7✔
256
            Err(err) => Err(err),
×
257
        }
258
    }
507✔
259
}
260

261
pub trait OrNotFound<U> {
262
    fn or_not_found(self, entity: &'static str, field: &'static str, value: String) -> Result<U, ChainStorageError>;
263
}
264

265
impl<U> OrNotFound<U> for Result<Option<U>, ChainStorageError> {
266
    fn or_not_found(self, entity: &'static str, field: &'static str, value: String) -> Result<U, ChainStorageError> {
1,039✔
267
        self.and_then(|inner| inner.ok_or(ChainStorageError::ValueNotFound { entity, field, value }))
1,039✔
268
    }
1,039✔
269
}
270

271
impl<U> OrNotFound<U> for Result<U, lmdb_zero::Error> {
272
    fn or_not_found(self, entity: &'static str, field: &'static str, value: String) -> Result<U, ChainStorageError> {
4,962✔
273
        use lmdb_zero::Error::Code;
274
        match self {
4,962✔
275
            Ok(v) => Ok(v),
4,962✔
276
            Err(err) => match err {
×
277
                Code(c) if c == lmdb_zero::error::NOTFOUND => {
×
278
                    Err(ChainStorageError::ValueNotFound { entity, field, value })
×
279
                },
280
                err => Err(err.into()),
×
281
            },
282
        }
283
    }
4,962✔
284
}
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