clone_solana_vote_interface/
error.rs

1//! Vote program errors
2
3use {
4    clone_solana_decode_error::DecodeError,
5    core::fmt,
6    num_derive::{FromPrimitive, ToPrimitive},
7};
8
9/// Reasons the vote might have had an error
10#[derive(Debug, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
11pub enum VoteError {
12    VoteTooOld,
13    SlotsMismatch,
14    SlotHashMismatch,
15    EmptySlots,
16    TimestampTooOld,
17    TooSoonToReauthorize,
18    // TODO: figure out how to migrate these new errors
19    LockoutConflict,
20    NewVoteStateLockoutMismatch,
21    SlotsNotOrdered,
22    ConfirmationsNotOrdered,
23    ZeroConfirmations,
24    ConfirmationTooLarge,
25    RootRollBack,
26    ConfirmationRollBack,
27    SlotSmallerThanRoot,
28    TooManyVotes,
29    VotesTooOldAllFiltered,
30    RootOnDifferentFork,
31    ActiveVoteAccountClose,
32    CommissionUpdateTooLate,
33    AssertionFailed,
34}
35
36impl std::error::Error for VoteError {}
37
38impl fmt::Display for VoteError {
39    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40        f.write_str(match self {
41            Self::VoteTooOld => "vote already recorded or not in slot hashes history",
42            Self::SlotsMismatch => "vote slots do not match bank history",
43            Self::SlotHashMismatch => "vote hash does not match bank hash",
44            Self::EmptySlots => "vote has no slots, invalid",
45            Self::TimestampTooOld => "vote timestamp not recent",
46            Self::TooSoonToReauthorize => "authorized voter has already been changed this epoch",
47            Self::LockoutConflict => {
48                "Old state had vote which should not have been popped off by vote in new state"
49            }
50            Self::NewVoteStateLockoutMismatch => {
51                "Proposed state had earlier slot which should have been popped off by later vote"
52            }
53            Self::SlotsNotOrdered => "Vote slots are not ordered",
54            Self::ConfirmationsNotOrdered => "Confirmations are not ordered",
55            Self::ZeroConfirmations => "Zero confirmations",
56            Self::ConfirmationTooLarge => "Confirmation exceeds limit",
57            Self::RootRollBack => "Root rolled back",
58            Self::ConfirmationRollBack => {
59                "Confirmations for same vote were smaller in new proposed state"
60            }
61            Self::SlotSmallerThanRoot => "New state contained a vote slot smaller than the root",
62            Self::TooManyVotes => "New state contained too many votes",
63            Self::VotesTooOldAllFiltered => {
64                "every slot in the vote was older than the SlotHashes history"
65            }
66            Self::RootOnDifferentFork => "Proposed root is not in slot hashes",
67            Self::ActiveVoteAccountClose => {
68                "Cannot close vote account unless it stopped voting at least one full epoch ago"
69            }
70            Self::CommissionUpdateTooLate => "Cannot update commission at this point in the epoch",
71            Self::AssertionFailed => "Assertion failed",
72        })
73    }
74}
75
76impl<E> DecodeError<E> for VoteError {
77    fn type_of() -> &'static str {
78        "VoteError"
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use {super::*, clone_solana_instruction::error::InstructionError};
85
86    #[test]
87    fn test_custom_error_decode() {
88        use num_traits::FromPrimitive;
89        fn pretty_err<T>(err: InstructionError) -> String
90        where
91            T: 'static + std::error::Error + DecodeError<T> + FromPrimitive,
92        {
93            if let InstructionError::Custom(code) = err {
94                let specific_error: T = T::decode_custom_error_to_enum(code).unwrap();
95                format!(
96                    "{:?}: {}::{:?} - {}",
97                    err,
98                    T::type_of(),
99                    specific_error,
100                    specific_error,
101                )
102            } else {
103                "".to_string()
104            }
105        }
106        assert_eq!(
107            "Custom(0): VoteError::VoteTooOld - vote already recorded or not in slot hashes history",
108            pretty_err::<VoteError>(VoteError::VoteTooOld.into())
109        )
110    }
111}