pepper_sync/
error.rs

1//! Pepper sync error module
2
3use 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/// Top level error enumerating any error that may occur during sync
12#[derive(Debug, thiserror::Error)]
13pub enum SyncError<E>
14where
15    E: std::fmt::Debug + std::fmt::Display,
16{
17    /// Mempool error.
18    #[error("mempool error. {0}")]
19    MempoolError(#[from] MempoolError),
20    /// Scan error.
21    #[error("scan error. {0}")]
22    ScanError(#[from] ScanError),
23    /// Server error.
24    #[error("server error. {0}")]
25    ServerError(#[from] ServerError),
26    /// Sync mode error.
27    #[error("sync mode error. {0}")]
28    SyncModeError(#[from] SyncModeError),
29    /// Chain error.
30    #[error("wallet height is more than {0} blocks ahead of best chain height")]
31    ChainError(u32),
32    /// Shard tree error.
33    #[error("shard tree error. {0}")]
34    ShardTreeError(#[from] ShardTreeError<Infallible>),
35    /// Critical non-recoverable truncation error due to missing shard tree checkpoints.
36    #[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    /// Transparent address derivation error.
41    #[error("transparent address derivation error. {0}")]
42    TransparentAddressDerivationError(bip32::Error),
43    /// Wallet error.
44    #[error("wallet error. {0}")]
45    WalletError(E),
46}
47
48/// Sync status errors.
49#[derive(Debug, thiserror::Error)]
50pub enum SyncStatusError<E>
51where
52    E: std::fmt::Debug + std::fmt::Display,
53{
54    /// No sync data. Wallet has never been synced with the block chain.
55    #[error("No sync data. Wallet has never been synced with the block chain.")]
56    NoSyncData,
57    /// Wallet error.
58    #[error("wallet error. {0}")]
59    WalletError(E),
60}
61
62/// Mempool errors.
63#[derive(Debug, thiserror::Error)]
64pub enum MempoolError {
65    /// Server error.
66    #[error("server error. {0}")]
67    ServerError(#[from] ServerError),
68    /// Timed out fetching mempool stream during shutdown.
69    #[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/// Scan errors.
76#[derive(Debug, thiserror::Error)]
77pub enum ScanError {
78    /// Server error.
79    #[error("server error. {0}")]
80    ServerError(#[from] ServerError),
81    /// Continuity error.
82    #[error("continuity error. {0}")]
83    ContinuityError(#[from] ContinuityError),
84    /// Zcash client backend scan error
85    #[error("{0}")]
86    ZcbScanError(zcash_client_backend::scanning::ScanError),
87    /// Invalid sapling nullifier
88    #[error("invalid sapling nullifier. {0}")]
89    InvalidSaplingNullifier(#[from] TryFromSliceError),
90    /// Invalid orchard nullifier length
91    #[error("invalid orchard nullifier length. should be 32 bytes, found {0}")]
92    InvalidOrchardNullifierLength(usize),
93    /// Invalid orchard nullifier
94    #[error("invalid orchard nullifier")]
95    InvalidOrchardNullifier,
96    /// Invalid sapling output
97    // TODO: add output data
98    #[error("invalid sapling output")]
99    InvalidSaplingOutput,
100    /// Invalid orchard action
101    // TODO: add output data
102    #[error("invalid orchard action")]
103    InvalidOrchardAction,
104    /// Incorrect tree size
105    #[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
110        shielded_protocol: PoolType,
111        /// Block metadata size
112        block_metadata_size: u32,
113        /// Calculated size
114        calculated_size: u32,
115    },
116    /// Txid of transaction returned by the server does not match requested txid.
117    #[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
122        txid_requested: TxId,
123        /// Txid returned
124        txid_returned: TxId,
125    },
126    /// Decrypted note nullifier and position data not found.
127    #[error("decrypted note nullifier and position data not found. output id: {0:?}")]
128    DecryptedNoteDataNotFound(OutputId),
129    /// Invalid memo bytes..
130    #[error("invalid memo bytes. {0}")]
131    InvalidMemoBytes(#[from] zcash_primitives::memo::Error),
132    /// Failed to parse encoded address.
133    #[error("failed to parse encoded address. {0}")]
134    AddressParseError(#[from] zcash_address::unified::ParseError),
135}
136
137/// Block continuity errors.
138#[derive(Debug, thiserror::Error)]
139pub enum ContinuityError {
140    /// Height discontinuity.
141    #[error(
142        "height discontinuity. block with height {height} is not continuous with previous block height {previous_block_height}"
143    )]
144    HeightDiscontinuity {
145        /// Block height
146        height: BlockHeight,
147        /// Previous block height
148        previous_block_height: BlockHeight,
149    },
150    /// Hash discontinuity.
151    #[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        /// Block height
156        height: BlockHeight,
157        /// Block's previous block hash data
158        prev_hash: BlockHash,
159        /// Actual previous block hash
160        previous_block_hash: BlockHash,
161    },
162}
163
164/// Server errors.
165///
166/// Errors associated with connecting to the server and receiving invalid data.
167#[derive(Debug, thiserror::Error)]
168pub enum ServerError {
169    /// Server request failed.
170    #[error("server request failed. {0}")]
171    RequestFailed(#[from] tonic::Status),
172    /// Server returned invalid frontier.
173    #[error("server returned invalid frontier. {0}")]
174    InvalidFrontier(std::io::Error),
175    /// Server returned invalid transaction.
176    #[error("server returned invalid transaction. {0}")]
177    InvalidTransaction(std::io::Error),
178    /// Server returned invalid subtree root.
179    // TODO: add more info
180    #[error("server returned invalid subtree root.")]
181    InvalidSubtreeRoot,
182    /// Server returned blocks that could not be verified against wallet block data. Exceeded max verification window.
183    #[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    /// Fetcher task was dropped.
188    #[error("fetcher task was dropped.")]
189    FetcherDropped,
190    /// Server reports only the genesis block exists.
191    #[error("server reports only the genesis block exists.")]
192    GenesisBlockOnly,
193}
194
195/// Sync mode error.
196#[derive(Debug, thiserror::Error)]
197pub enum SyncModeError {
198    /// Invalid sync mode.
199    #[error("invalid sync mode. {0}")]
200    InvalidSyncMode(u8),
201    /// Sync is already running.
202    #[error("sync is already running")]
203    SyncAlreadyRunning,
204    /// Sync is not running.
205    #[error("sync is not running")]
206    SyncNotRunning,
207    /// Sync is not paused.
208    #[error("sync is not paused")]
209    SyncNotPaused,
210}