text: // Copyright 2019. The Tari Project
  //
  // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
  // following conditions are met:
  //
  // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
  // disclaimer.
  //
  // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
  // following disclaimer in the documentation and/or other materials provided with the distribution.
  //
  // 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
  // products derived from this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  use crate::{
      chain_storage::{lmdb_db::LMDBVecError, MmrTree},
      validation::ValidationError,
  };
  use tari_mmr::{error::MerkleMountainRangeError, MerkleProofError};
  use tari_storage::lmdb_store::LMDBError;
  use thiserror::Error;
  use tokio::task;
  
  #[derive(Debug, Clone, Error)]
  pub enum ChainStorageError {
      #[error("Access to the underlying storage mechanism failed: {0}")]
      AccessError(String),
      #[error(
          "The database may be corrupted or otherwise be in an inconsistent state. Please check logs to try and \
           identify the issue: {0}"
      )]
      CorruptedDatabase(String),
      #[error("A given input could not be spent because it was not in the UTXO set")]
      UnspendableInput,
      #[error("A problem occurred trying to move a STXO back into the UTXO pool during a reorg.")]
      UnspendError,
      #[error(
          "An unexpected result type was received for the given database request. This suggests that there is an \
           internal error or bug of sorts: {0}"
      )]
      UnexpectedResult(String),
      #[error("You tried to execute an invalid Database operation: {0}")]
      InvalidOperation(String),
      #[error("There appears to be a critical error on the back end: {0}. Check the logs for more information.")]
      CriticalError(String),
      #[error("Cannot return data for requests older than the current pruning horizon")]
      BeyondPruningHorizon,
      #[error("An invalid query was attempted: {0}")]
      InvalidQuery(String),
      #[error("The requested {entity} was not found via {field}:{value} in the database")]
      ValueNotFound {
          entity: String,
          field: String,
          value: String,
      },
      #[error("MMR error: {source}")]
      MerkleMountainRangeError {
          #[from]
          source: MerkleMountainRangeError,
      },
      #[error("Merkle proof error: {source}")]
      MerkleProofError {
          #[from]
          source: MerkleProofError,
      },
      #[error("Validation error: {source}")]
      ValidationError {
          #[from]
          source: ValidationError,
      },
      #[error("The MMR root for {0} in the provided block header did not match the MMR root in the database")]
      MismatchedMmrRoot(MmrTree),
      #[error("An invalid block was submitted to the database")]
      InvalidBlock,
      #[error("Blocking task spawn error: {0}")]
      BlockingTaskSpawnError(String),
      #[error("A request was out of range")]
      OutOfRange,
      #[error("Value not found: {0}")]
      LmdbValueNotFound(lmdb_zero::Error),
      #[error("LMDB error: {source}")]
      LmdbError {
          #[from]
          source: LMDBError,
      },
  }
  
  impl From<LMDBVecError> for ChainStorageError {
      fn from(err: LMDBVecError) -> Self {
          Self::AccessError(err.to_string())
      }
  }
  
  impl From<task::JoinError> for ChainStorageError {
      fn from(err: task::JoinError) -> Self {
          Self::BlockingTaskSpawnError(err.to_string())
      }
  }
  
  impl From<lmdb_zero::Error> for ChainStorageError {
      fn from(err: lmdb_zero::Error) -> Self {
          use lmdb_zero::Error::*;
          match err {
              Code(c) if c == lmdb_zero::error::NOTFOUND => ChainStorageError::LmdbValueNotFound(err),
              _ => ChainStorageError::AccessError(err.to_string()),
          }
      }
  }
  