use std::{array::TryFromSliceError, convert::Infallible};
use shardtree::error::ShardTreeError;
use zcash_primitives::{block::BlockHash, consensus::BlockHeight, transaction::TxId};
use zcash_protocol::PoolType;
use crate::wallet::OutputId;
#[derive(Debug, thiserror::Error)]
pub enum SyncError<E>
where
E: std::fmt::Debug + std::fmt::Display,
{
#[error("mempool error. {0}")]
MempoolError(#[from] MempoolError),
#[error("scan error. {0}")]
ScanError(#[from] ScanError),
#[error("server error. {0}")]
ServerError(#[from] ServerError),
#[error("sync mode error. {0}")]
SyncModeError(#[from] SyncModeError),
#[error("wallet height {0} is more than {1} blocks ahead of best chain height {2}")]
ChainError(u32, u32, u32),
#[error(
"birthday {0} below sapling activation height {1}. pre-sapling wallets are not supported!"
)]
BirthdayBelowSapling(u32, u32),
#[error("shard tree error. {0}")]
ShardTreeError(#[from] ShardTreeError<Infallible>),
#[error(
"critical non-recoverable truncation error at height {0} due to missing {1} shard tree checkpoints. wallet data cleared. rescan required."
)]
TruncationError(BlockHeight, PoolType),
#[error("transparent address derivation error. {0}")]
TransparentAddressDerivationError(bip32::Error),
#[error("wallet error. {0}")]
WalletError(E),
}
#[derive(Debug, thiserror::Error)]
pub enum SyncStatusError<E>
where
E: std::fmt::Debug + std::fmt::Display,
{
#[error("No sync data. Wallet has never been synced with the block chain.")]
NoSyncData,
#[error("wallet error. {0}")]
WalletError(E),
}
#[derive(Debug, thiserror::Error)]
pub enum MempoolError {
#[error("server error. {0}")]
ServerError(#[from] ServerError),
#[error(
"timed out fetching mempool stream during shutdown.\nNON-CRITICAL: sync completed successfully but may not have scanned transactions in the mempool."
)]
ShutdownWithoutStream,
}
#[derive(Debug, thiserror::Error)]
pub enum ScanError {
#[error("server error. {0}")]
ServerError(#[from] ServerError),
#[error("continuity error. {0}")]
ContinuityError(#[from] ContinuityError),
#[error("{0}")]
ZcbScanError(zcash_client_backend::scanning::ScanError),
#[error("invalid sapling nullifier. {0}")]
InvalidSaplingNullifier(#[from] TryFromSliceError),
#[error("invalid orchard nullifier length. should be 32 bytes, found {0}")]
InvalidOrchardNullifierLength(usize),
#[error("invalid orchard nullifier")]
InvalidOrchardNullifier,
#[error("invalid sapling output")]
InvalidSaplingOutput,
#[error("invalid orchard action")]
InvalidOrchardAction,
#[error(
"incorrect tree size. {shielded_protocol} tree size recorded in block metadata {block_metadata_size} does not match calculated size {calculated_size}"
)]
IncorrectTreeSize {
shielded_protocol: PoolType,
block_metadata_size: u32,
calculated_size: u32,
},
#[error(
"txid of transaction returned by the server does not match requested txid.\ntxid requested: {txid_requested}\ntxid returned: {txid_returned}"
)]
IncorrectTxid {
txid_requested: TxId,
txid_returned: TxId,
},
#[error("decrypted note nullifier and position data not found. output id: {0:?}")]
DecryptedNoteDataNotFound(OutputId),
#[error("invalid memo bytes. {0}")]
InvalidMemoBytes(#[from] zcash_protocol::memo::Error),
#[error("failed to parse encoded address. {0}")]
AddressParseError(#[from] zcash_address::unified::ParseError),
}
#[derive(Debug, thiserror::Error)]
pub enum ContinuityError {
#[error(
"height discontinuity. block with height {height} is not continuous with previous block height {previous_block_height}"
)]
HeightDiscontinuity {
height: BlockHeight,
previous_block_height: BlockHeight,
},
#[error(
"hash discontinuity. block prev_hash {prev_hash} with height {height} does not match previous block hash {previous_block_hash}"
)]
HashDiscontinuity {
height: BlockHeight,
prev_hash: BlockHash,
previous_block_hash: BlockHash,
},
}
#[derive(Debug, thiserror::Error)]
pub enum ServerError {
#[error("server request failed. {0}")]
RequestFailed(#[from] tonic::Status),
#[error("server returned invalid frontier. {0}")]
InvalidFrontier(std::io::Error),
#[error("server returned invalid transaction. {0}")]
InvalidTransaction(std::io::Error),
#[error("server returned invalid subtree root.")]
InvalidSubtreeRoot,
#[error(
"server returned blocks that could not be verified against wallet block data. exceeded max verification window. wallet data has been cleared as shard tree data cannot be truncated further. wallet rescan required."
)]
ChainVerificationError,
#[error("fetcher task was dropped.")]
FetcherDropped,
#[error("server reports only the genesis block exists.")]
GenesisBlockOnly,
}
#[derive(Debug, thiserror::Error)]
pub enum SyncModeError {
#[error("invalid sync mode. {0}")]
InvalidSyncMode(u8),
#[error("sync is already running")]
SyncAlreadyRunning,
#[error("sync is not running")]
SyncNotRunning,
#[error("sync is not paused")]
SyncNotPaused,
}