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 {0} is more than {1} blocks ahead of best chain height {2}")]
31 ChainError(u32, u32, u32),
32 #[error(
34 "birthday {0} below sapling activation height {1}. pre-sapling wallets are not supported!"
35 )]
36 BirthdayBelowSapling(u32, u32),
37 #[error("shard tree error. {0}")]
39 ShardTreeError(#[from] ShardTreeError<Infallible>),
40 #[error(
42 "critical non-recoverable truncation error at height {0} due to missing {1} shard tree checkpoints. wallet data cleared. rescan required."
43 )]
44 TruncationError(BlockHeight, PoolType),
45 #[error("transparent address derivation error. {0}")]
47 TransparentAddressDerivationError(bip32::Error),
48 #[error("wallet error. {0}")]
50 WalletError(E),
51}
52
53#[derive(Debug, thiserror::Error)]
55pub enum SyncStatusError<E>
56where
57 E: std::fmt::Debug + std::fmt::Display,
58{
59 #[error("No sync data. Wallet has never been synced with the block chain.")]
61 NoSyncData,
62 #[error("wallet error. {0}")]
64 WalletError(E),
65}
66
67#[derive(Debug, thiserror::Error)]
69pub enum MempoolError {
70 #[error("server error. {0}")]
72 ServerError(#[from] ServerError),
73 #[error(
75 "timed out fetching mempool stream during shutdown.\nNON-CRITICAL: sync completed successfully but may not have scanned transactions in the mempool."
76 )]
77 ShutdownWithoutStream,
78}
79
80#[derive(Debug, thiserror::Error)]
82pub enum ScanError {
83 #[error("server error. {0}")]
85 ServerError(#[from] ServerError),
86 #[error("continuity error. {0}")]
88 ContinuityError(#[from] ContinuityError),
89 #[error("{0}")]
91 ZcbScanError(zcash_client_backend::scanning::ScanError),
92 #[error("invalid sapling nullifier. {0}")]
94 InvalidSaplingNullifier(#[from] TryFromSliceError),
95 #[error("invalid orchard nullifier length. should be 32 bytes, found {0}")]
97 InvalidOrchardNullifierLength(usize),
98 #[error("invalid orchard nullifier")]
100 InvalidOrchardNullifier,
101 #[error("invalid sapling output")]
104 InvalidSaplingOutput,
105 #[error("invalid orchard action")]
108 InvalidOrchardAction,
109 #[error(
111 "incorrect tree size. {shielded_protocol} tree size recorded in block metadata {block_metadata_size} does not match calculated size {calculated_size}"
112 )]
113 IncorrectTreeSize {
114 shielded_protocol: PoolType,
116 block_metadata_size: u32,
118 calculated_size: u32,
120 },
121 #[error(
123 "txid of transaction returned by the server does not match requested txid.\ntxid requested: {txid_requested}\ntxid returned: {txid_returned}"
124 )]
125 IncorrectTxid {
126 txid_requested: TxId,
128 txid_returned: TxId,
130 },
131 #[error("decrypted note nullifier and position data not found. output id: {0:?}")]
133 DecryptedNoteDataNotFound(OutputId),
134 #[error("invalid memo bytes. {0}")]
136 InvalidMemoBytes(#[from] zcash_protocol::memo::Error),
137 #[error("failed to parse encoded address. {0}")]
139 AddressParseError(#[from] zcash_address::unified::ParseError),
140}
141
142#[derive(Debug, thiserror::Error)]
144pub enum ContinuityError {
145 #[error(
147 "height discontinuity. block with height {height} is not continuous with previous block height {previous_block_height}"
148 )]
149 HeightDiscontinuity {
150 height: BlockHeight,
152 previous_block_height: BlockHeight,
154 },
155 #[error(
157 "hash discontinuity. block prev_hash {prev_hash} with height {height} does not match previous block hash {previous_block_hash}"
158 )]
159 HashDiscontinuity {
160 height: BlockHeight,
162 prev_hash: BlockHash,
164 previous_block_hash: BlockHash,
166 },
167}
168
169#[derive(Debug, thiserror::Error)]
173pub enum ServerError {
174 #[error("server request failed. {0}")]
176 RequestFailed(#[from] tonic::Status),
177 #[error("server returned invalid frontier. {0}")]
179 InvalidFrontier(std::io::Error),
180 #[error("server returned invalid transaction. {0}")]
182 InvalidTransaction(std::io::Error),
183 #[error("server returned invalid subtree root.")]
186 InvalidSubtreeRoot,
187 #[error(
189 "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."
190 )]
191 ChainVerificationError,
192 #[error("fetcher task was dropped.")]
194 FetcherDropped,
195 #[error("server reports only the genesis block exists.")]
197 GenesisBlockOnly,
198}
199
200#[derive(Debug, thiserror::Error)]
202pub enum SyncModeError {
203 #[error("invalid sync mode. {0}")]
205 InvalidSyncMode(u8),
206 #[error("sync is already running")]
208 SyncAlreadyRunning,
209 #[error("sync is not running")]
211 SyncNotRunning,
212 #[error("sync is not paused")]
214 SyncNotPaused,
215}