1use std::{array::TryFromSliceError, convert::Infallible};
4
5use shardtree::error::ShardTreeError;
6use zcash_primitives::{block::BlockHash, consensus::BlockHeight, transaction::TxId};
7use zcash_protocol::PoolType;
8
9use crate::wallet::OutputId;
10
11#[derive(Debug, thiserror::Error)]
13pub enum SyncError<E>
14where
15 E: std::fmt::Debug + std::fmt::Display,
16{
17 #[error("mempool error. {0}")]
19 MempoolError(#[from] MempoolError),
20 #[error("scan error. {0}")]
22 ScanError(#[from] ScanError),
23 #[error("server error. {0}")]
25 ServerError(#[from] ServerError),
26 #[error("sync mode error. {0}")]
28 SyncModeError(#[from] SyncModeError),
29 #[error("wallet height is more than {0} blocks ahead of best chain height")]
31 ChainError(u32),
32 #[error("shard tree error. {0}")]
34 ShardTreeError(#[from] ShardTreeError<Infallible>),
35 #[error(
37 "critical non-recoverable truncation error at height {0} due to missing {1} shard tree checkpoints. wallet data cleared. rescan required."
38 )]
39 TruncationError(BlockHeight, PoolType),
40 #[error("transparent address derivation error. {0}")]
42 TransparentAddressDerivationError(bip32::Error),
43 #[error("wallet error. {0}")]
45 WalletError(E),
46}
47
48#[derive(Debug, thiserror::Error)]
50pub enum SyncStatusError<E>
51where
52 E: std::fmt::Debug + std::fmt::Display,
53{
54 #[error("No sync data. Wallet has never been synced with the block chain.")]
56 NoSyncData,
57 #[error("wallet error. {0}")]
59 WalletError(E),
60}
61
62#[derive(Debug, thiserror::Error)]
64pub enum MempoolError {
65 #[error("server error. {0}")]
67 ServerError(#[from] ServerError),
68 #[error(
70 "timed out fetching mempool stream during shutdown.\nNON-CRITICAL: sync completed successfully but may not have scanned transactions in the mempool."
71 )]
72 ShutdownWithoutStream,
73}
74
75#[derive(Debug, thiserror::Error)]
77pub enum ScanError {
78 #[error("server error. {0}")]
80 ServerError(#[from] ServerError),
81 #[error("continuity error. {0}")]
83 ContinuityError(#[from] ContinuityError),
84 #[error("{0}")]
86 ZcbScanError(zcash_client_backend::scanning::ScanError),
87 #[error("invalid sapling nullifier. {0}")]
89 InvalidSaplingNullifier(#[from] TryFromSliceError),
90 #[error("invalid orchard nullifier length. should be 32 bytes, found {0}")]
92 InvalidOrchardNullifierLength(usize),
93 #[error("invalid orchard nullifier")]
95 InvalidOrchardNullifier,
96 #[error("invalid sapling output")]
99 InvalidSaplingOutput,
100 #[error("invalid orchard action")]
103 InvalidOrchardAction,
104 #[error(
106 "incorrect tree size. {shielded_protocol} tree size recorded in block metadata {block_metadata_size} does not match calculated size {calculated_size}"
107 )]
108 IncorrectTreeSize {
109 shielded_protocol: PoolType,
111 block_metadata_size: u32,
113 calculated_size: u32,
115 },
116 #[error(
118 "txid of transaction returned by the server does not match requested txid.\ntxid requested: {txid_requested}\ntxid returned: {txid_returned}"
119 )]
120 IncorrectTxid {
121 txid_requested: TxId,
123 txid_returned: TxId,
125 },
126 #[error("decrypted note nullifier and position data not found. output id: {0:?}")]
128 DecryptedNoteDataNotFound(OutputId),
129 #[error("invalid memo bytes. {0}")]
131 InvalidMemoBytes(#[from] zcash_primitives::memo::Error),
132 #[error("failed to parse encoded address. {0}")]
134 AddressParseError(#[from] zcash_address::unified::ParseError),
135}
136
137#[derive(Debug, thiserror::Error)]
139pub enum ContinuityError {
140 #[error(
142 "height discontinuity. block with height {height} is not continuous with previous block height {previous_block_height}"
143 )]
144 HeightDiscontinuity {
145 height: BlockHeight,
147 previous_block_height: BlockHeight,
149 },
150 #[error(
152 "hash discontinuity. block prev_hash {prev_hash} with height {height} does not match previous block hash {previous_block_hash}"
153 )]
154 HashDiscontinuity {
155 height: BlockHeight,
157 prev_hash: BlockHash,
159 previous_block_hash: BlockHash,
161 },
162}
163
164#[derive(Debug, thiserror::Error)]
168pub enum ServerError {
169 #[error("server request failed. {0}")]
171 RequestFailed(#[from] tonic::Status),
172 #[error("server returned invalid frontier. {0}")]
174 InvalidFrontier(std::io::Error),
175 #[error("server returned invalid transaction. {0}")]
177 InvalidTransaction(std::io::Error),
178 #[error("server returned invalid subtree root.")]
181 InvalidSubtreeRoot,
182 #[error(
184 "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."
185 )]
186 ChainVerificationError,
187 #[error("fetcher task was dropped.")]
189 FetcherDropped,
190 #[error("server reports only the genesis block exists.")]
192 GenesisBlockOnly,
193}
194
195#[derive(Debug, thiserror::Error)]
197pub enum SyncModeError {
198 #[error("invalid sync mode. {0}")]
200 InvalidSyncMode(u8),
201 #[error("sync is already running")]
203 SyncAlreadyRunning,
204 #[error("sync is not running")]
206 SyncNotRunning,
207 #[error("sync is not paused")]
209 SyncNotPaused,
210}