1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
//! Vote program errors

use {
    log::*,
    num_derive::{FromPrimitive, ToPrimitive},
    solana_sdk::decode_error::DecodeError,
    thiserror::Error,
};

/// Reasons the vote might have had an error
#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)]
pub enum VoteError {
    #[error("vote already recorded or not in slot hashes history")]
    VoteTooOld,

    #[error("vote slots do not match bank history")]
    SlotsMismatch,

    #[error("vote hash does not match bank hash")]
    SlotHashMismatch,

    #[error("vote has no slots, invalid")]
    EmptySlots,

    #[error("vote timestamp not recent")]
    TimestampTooOld,

    #[error("authorized voter has already been changed this epoch")]
    TooSoonToReauthorize,

    // TODO: figure out how to migrate these new errors
    #[error("Old state had vote which should not have been popped off by vote in new state")]
    LockoutConflict,

    #[error("Proposed state had earlier slot which should have been popped off by later vote")]
    NewVoteStateLockoutMismatch,

    #[error("Vote slots are not ordered")]
    SlotsNotOrdered,

    #[error("Confirmations are not ordered")]
    ConfirmationsNotOrdered,

    #[error("Zero confirmations")]
    ZeroConfirmations,

    #[error("Confirmation exceeds limit")]
    ConfirmationTooLarge,

    #[error("Root rolled back")]
    RootRollBack,

    #[error("Confirmations for same vote were smaller in new proposed state")]
    ConfirmationRollBack,

    #[error("New state contained a vote slot smaller than the root")]
    SlotSmallerThanRoot,

    #[error("New state contained too many votes")]
    TooManyVotes,

    #[error("every slot in the vote was older than the SlotHashes history")]
    VotesTooOldAllFiltered,

    #[error("Proposed root is not in slot hashes")]
    RootOnDifferentFork,
}

impl<E> DecodeError<E> for VoteError {
    fn type_of() -> &'static str {
        "VoteError"
    }
}

#[cfg(test)]
mod tests {
    use {super::*, solana_sdk::instruction::InstructionError};

    #[test]
    fn test_custom_error_decode() {
        use num_traits::FromPrimitive;
        fn pretty_err<T>(err: InstructionError) -> String
        where
            T: 'static + std::error::Error + DecodeError<T> + FromPrimitive,
        {
            if let InstructionError::Custom(code) = err {
                let specific_error: T = T::decode_custom_error_to_enum(code).unwrap();
                format!(
                    "{:?}: {}::{:?} - {}",
                    err,
                    T::type_of(),
                    specific_error,
                    specific_error,
                )
            } else {
                "".to_string()
            }
        }
        assert_eq!(
            "Custom(0): VoteError::VoteTooOld - vote already recorded or not in slot hashes history",
            pretty_err::<VoteError>(VoteError::VoteTooOld.into())
        )
    }
}