make voter_pubkey a function of epoch (#5830)
* make voter_pubkey a function of epoch * fixups
This commit is contained in:
		| @@ -6,32 +6,34 @@ use log::*; | |||||||
| use num_traits::FromPrimitive; | use num_traits::FromPrimitive; | ||||||
| use serde_json; | use serde_json; | ||||||
| use serde_json::{json, Value}; | use serde_json::{json, Value}; | ||||||
| use solana_budget_api; | use solana_budget_api::budget_instruction::{self, BudgetError}; | ||||||
| use solana_budget_api::budget_instruction; |  | ||||||
| use solana_budget_api::budget_state::BudgetError; |  | ||||||
| use solana_client::client_error::ClientError; | use solana_client::client_error::ClientError; | ||||||
| use solana_client::rpc_client::RpcClient; | use solana_client::rpc_client::RpcClient; | ||||||
| #[cfg(not(test))] | #[cfg(not(test))] | ||||||
| use solana_drone::drone::request_airdrop_transaction; | use solana_drone::drone::request_airdrop_transaction; | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| use solana_drone::drone_mock::request_airdrop_transaction; | use solana_drone::drone_mock::request_airdrop_transaction; | ||||||
| use solana_sdk::account_utils::State; | use solana_sdk::{ | ||||||
| use solana_sdk::bpf_loader; |     account_utils::State, | ||||||
| use solana_sdk::fee_calculator::FeeCalculator; |     bpf_loader, | ||||||
| use solana_sdk::hash::Hash; |     fee_calculator::FeeCalculator, | ||||||
| use solana_sdk::instruction::InstructionError; |     hash::Hash, | ||||||
| use solana_sdk::instruction_processor_utils::DecodeError; |     instruction::InstructionError, | ||||||
| use solana_sdk::loader_instruction; |     instruction_processor_utils::DecodeError, | ||||||
| use solana_sdk::message::Message; |     loader_instruction, | ||||||
| use solana_sdk::pubkey::Pubkey; |     message::Message, | ||||||
| use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil, Signature}; |     pubkey::Pubkey, | ||||||
| use solana_sdk::system_instruction::SystemError; |     signature::{read_keypair, Keypair, KeypairUtil, Signature}, | ||||||
| use solana_sdk::system_transaction; |     system_instruction::SystemError, | ||||||
| use solana_sdk::transaction::{Transaction, TransactionError}; |     system_transaction, | ||||||
| use solana_stake_api::{stake_instruction, stake_state::StakeError}; |     transaction::{Transaction, TransactionError}, | ||||||
|  | }; | ||||||
|  | use solana_stake_api::stake_instruction::{self, StakeError}; | ||||||
| use solana_storage_api::storage_instruction; | use solana_storage_api::storage_instruction; | ||||||
| use solana_vote_api::vote_instruction; | use solana_vote_api::{ | ||||||
| use solana_vote_api::vote_state::VoteState; |     vote_instruction::{self, VoteError}, | ||||||
|  |     vote_state::VoteState, | ||||||
|  | }; | ||||||
| use std::collections::VecDeque; | use std::collections::VecDeque; | ||||||
| use std::fs::File; | use std::fs::File; | ||||||
| use std::io::{Read, Write}; | use std::io::{Read, Write}; | ||||||
| @@ -617,9 +619,9 @@ fn process_authorize_voter( | |||||||
|         recent_blockhash, |         recent_blockhash, | ||||||
|     ); |     ); | ||||||
|     check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?; |     check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?; | ||||||
|     let signature_str = rpc_client |     let result = rpc_client | ||||||
|         .send_and_confirm_transaction(&mut tx, &[&config.keypair, &authorized_voter_keypair])?; |         .send_and_confirm_transaction(&mut tx, &[&config.keypair, &authorized_voter_keypair]); | ||||||
|     Ok(signature_str.to_string()) |     log_instruction_custom_error::<VoteError>(result) | ||||||
| } | } | ||||||
|  |  | ||||||
| fn process_show_account( | fn process_show_account( | ||||||
|   | |||||||
| @@ -1,13 +1,39 @@ | |||||||
| use crate::budget_expr::BudgetExpr; | use crate::{budget_expr::BudgetExpr, budget_state::BudgetState, id}; | ||||||
| use crate::budget_state::BudgetState; |  | ||||||
| use crate::id; |  | ||||||
| use bincode::serialized_size; | use bincode::serialized_size; | ||||||
| use chrono::prelude::{DateTime, Utc}; | use chrono::prelude::{DateTime, Utc}; | ||||||
|  | use num_derive::FromPrimitive; | ||||||
| use serde_derive::{Deserialize, Serialize}; | use serde_derive::{Deserialize, Serialize}; | ||||||
| use solana_sdk::hash::Hash; | use solana_sdk::{ | ||||||
| use solana_sdk::instruction::{AccountMeta, Instruction}; |     hash::Hash, | ||||||
| use solana_sdk::pubkey::Pubkey; |     instruction::{AccountMeta, Instruction}, | ||||||
| use solana_sdk::system_instruction; |     instruction_processor_utils::DecodeError, | ||||||
|  |     pubkey::Pubkey, | ||||||
|  |     system_instruction, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, FromPrimitive)] | ||||||
|  | pub enum BudgetError { | ||||||
|  |     DestinationMissing, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T> DecodeError<T> for BudgetError { | ||||||
|  |     fn type_of() -> &'static str { | ||||||
|  |         "BudgetError" | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl std::fmt::Display for BudgetError { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|  |         write!( | ||||||
|  |             f, | ||||||
|  |             "{}", | ||||||
|  |             match self { | ||||||
|  |                 BudgetError::DestinationMissing => "destination missing", | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl std::error::Error for BudgetError {} | ||||||
|  |  | ||||||
| /// A smart contract. | /// A smart contract. | ||||||
| #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | ||||||
|   | |||||||
| @@ -1,14 +1,15 @@ | |||||||
| //! budget program | //! budget program | ||||||
| use crate::budget_expr::Witness; | use crate::{ | ||||||
| use crate::budget_instruction::BudgetInstruction; |     budget_expr::Witness, | ||||||
| use crate::budget_state::{BudgetError, BudgetState}; |     budget_instruction::{BudgetError, BudgetInstruction}, | ||||||
|  |     budget_state::BudgetState, | ||||||
|  | }; | ||||||
| use bincode::deserialize; | use bincode::deserialize; | ||||||
| use chrono::prelude::{DateTime, Utc}; | use chrono::prelude::{DateTime, Utc}; | ||||||
| use log::*; | use log::*; | ||||||
| use solana_sdk::account::KeyedAccount; | use solana_sdk::{ | ||||||
| use solana_sdk::hash::hash; |     account::KeyedAccount, hash::hash, instruction::InstructionError, pubkey::Pubkey, | ||||||
| use solana_sdk::instruction::InstructionError; | }; | ||||||
| use solana_sdk::pubkey::Pubkey; |  | ||||||
|  |  | ||||||
| /// Process a Witness Signature. Any payment plans waiting on this signature | /// Process a Witness Signature. Any payment plans waiting on this signature | ||||||
| /// will progress one step. | /// will progress one step. | ||||||
|   | |||||||
| @@ -1,28 +1,8 @@ | |||||||
| //! budget state | //! budget state | ||||||
| use crate::budget_expr::BudgetExpr; | use crate::budget_expr::BudgetExpr; | ||||||
| use bincode::{self, deserialize, serialize_into}; | use bincode::{self, deserialize, serialize_into}; | ||||||
| use num_derive::FromPrimitive; |  | ||||||
| use serde_derive::{Deserialize, Serialize}; | use serde_derive::{Deserialize, Serialize}; | ||||||
| use solana_sdk::instruction::InstructionError; | use solana_sdk::instruction::InstructionError; | ||||||
| use solana_sdk::instruction_processor_utils::DecodeError; |  | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, FromPrimitive)] |  | ||||||
| pub enum BudgetError { |  | ||||||
|     DestinationMissing, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<T> DecodeError<T> for BudgetError { |  | ||||||
|     fn type_of() -> &'static str { |  | ||||||
|         "BudgetError" |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl std::fmt::Display for BudgetError { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |  | ||||||
|         write!(f, "error") |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| impl std::error::Error for BudgetError {} |  | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] | #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)] | ||||||
| pub struct BudgetState { | pub struct BudgetState { | ||||||
|   | |||||||
| @@ -4,15 +4,36 @@ use crate::{ | |||||||
| }; | }; | ||||||
| use bincode::deserialize; | use bincode::deserialize; | ||||||
| use log::*; | use log::*; | ||||||
|  | use num_derive::{FromPrimitive, ToPrimitive}; | ||||||
| use serde_derive::{Deserialize, Serialize}; | use serde_derive::{Deserialize, Serialize}; | ||||||
| use solana_sdk::{ | use solana_sdk::{ | ||||||
|     account::KeyedAccount, |     account::KeyedAccount, | ||||||
|     clock::Slot, |     clock::Slot, | ||||||
|     instruction::{AccountMeta, Instruction, InstructionError}, |     instruction::{AccountMeta, Instruction, InstructionError}, | ||||||
|  |     instruction_processor_utils::DecodeError, | ||||||
|     pubkey::Pubkey, |     pubkey::Pubkey, | ||||||
|     system_instruction, sysvar, |     system_instruction, sysvar, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | /// Reasons the stake might have had an error | ||||||
|  | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] | ||||||
|  | pub enum StakeError { | ||||||
|  |     NoCreditsToRedeem, | ||||||
|  | } | ||||||
|  | impl<E> DecodeError<E> for StakeError { | ||||||
|  |     fn type_of() -> &'static str { | ||||||
|  |         "StakeError" | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl std::fmt::Display for StakeError { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|  |         match self { | ||||||
|  |             StakeError::NoCreditsToRedeem => write!(f, "not enough credits to redeem"), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl std::error::Error for StakeError {} | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | ||||||
| pub enum StakeInstruction { | pub enum StakeInstruction { | ||||||
|     /// `Lockup` a stake until the specified slot |     /// `Lockup` a stake until the specified slot | ||||||
| @@ -454,4 +475,30 @@ mod tests { | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     #[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::CustomError(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!( | ||||||
|  |             "CustomError(0): StakeError::NoCreditsToRedeem - not enough credits to redeem", | ||||||
|  |             pretty_err::<StakeError>(StakeError::NoCreditsToRedeem.into()) | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,15 +3,13 @@ | |||||||
| //! * keep track of rewards | //! * keep track of rewards | ||||||
| //! * own mining pools | //! * own mining pools | ||||||
|  |  | ||||||
| use crate::{config::Config, id}; | use crate::{config::Config, id, stake_instruction::StakeError}; | ||||||
| use num_derive::{FromPrimitive, ToPrimitive}; |  | ||||||
| use serde_derive::{Deserialize, Serialize}; | use serde_derive::{Deserialize, Serialize}; | ||||||
| use solana_sdk::{ | use solana_sdk::{ | ||||||
|     account::{Account, KeyedAccount}, |     account::{Account, KeyedAccount}, | ||||||
|     account_utils::State, |     account_utils::State, | ||||||
|     clock::{Epoch, Slot}, |     clock::{Epoch, Slot}, | ||||||
|     instruction::InstructionError, |     instruction::InstructionError, | ||||||
|     instruction_processor_utils::DecodeError, |  | ||||||
|     pubkey::Pubkey, |     pubkey::Pubkey, | ||||||
|     sysvar::{ |     sysvar::{ | ||||||
|         self, |         self, | ||||||
| @@ -21,6 +19,7 @@ use solana_sdk::{ | |||||||
| use solana_vote_api::vote_state::VoteState; | use solana_vote_api::vote_state::VoteState; | ||||||
|  |  | ||||||
| #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] | #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] | ||||||
|  | #[allow(clippy::large_enum_variant)] | ||||||
| pub enum StakeState { | pub enum StakeState { | ||||||
|     Uninitialized, |     Uninitialized, | ||||||
|     Lockup(Slot), |     Lockup(Slot), | ||||||
| @@ -52,46 +51,46 @@ impl StakeState { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Reasons the stake might have had an error |  | ||||||
| #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] |  | ||||||
| pub enum StakeError { |  | ||||||
|     NoCreditsToRedeem, |  | ||||||
| } |  | ||||||
| impl<E> DecodeError<E> for StakeError { |  | ||||||
|     fn type_of() -> &'static str { |  | ||||||
|         "StakeError" |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| impl std::fmt::Display for StakeError { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |  | ||||||
|         match self { |  | ||||||
|             StakeError::NoCreditsToRedeem => write!(f, "not enough credits to redeem"), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| impl std::error::Error for StakeError {} |  | ||||||
|  |  | ||||||
| #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] | #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] | ||||||
| pub struct Stake { | pub struct Stake { | ||||||
|  |     /// most recently delegated vote account pubkey | ||||||
|     pub voter_pubkey: Pubkey, |     pub voter_pubkey: Pubkey, | ||||||
|  |     /// the epoch when voter_pubkey was most recently set | ||||||
|  |     pub voter_pubkey_epoch: Epoch, | ||||||
|  |     /// credits observed is credits from vote account state when delegated or redeemed | ||||||
|     pub credits_observed: u64, |     pub credits_observed: u64, | ||||||
|     pub stake: u64,                // stake amount activated |     /// activated stake amount, set at delegate_stake() time | ||||||
|     pub activation_epoch: Epoch, // epoch the stake was activated, std::Epoch::MAX if is a bootstrap stake |     pub stake: u64, | ||||||
|     pub deactivation_epoch: Epoch, // epoch the stake was deactivated, std::Epoch::MAX if not deactivated |     /// epoch at which this stake was activated, std::Epoch::MAX if is a bootstrap stake | ||||||
|  |     pub activation_epoch: Epoch, | ||||||
|  |     /// epoch the stake was deactivated, std::Epoch::MAX if not deactivated | ||||||
|  |     pub deactivation_epoch: Epoch, | ||||||
|  |     /// stake config (warmup, etc.) | ||||||
|     pub config: Config, |     pub config: Config, | ||||||
|  |     /// the Slot at which this stake becomes available for withdrawal | ||||||
|     pub lockup: Slot, |     pub lockup: Slot, | ||||||
|  |     /// history of prior delegates and the epoch ranges for which | ||||||
|  |     ///  they were set, circular buffer | ||||||
|  |     pub prior_delegates: [(Pubkey, Epoch, Epoch); MAX_PRIOR_DELEGATES], | ||||||
|  |     /// next pointer | ||||||
|  |     pub prior_delegates_idx: usize, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const MAX_PRIOR_DELEGATES: usize = 32; | ||||||
|  |  | ||||||
| impl Default for Stake { | impl Default for Stake { | ||||||
|     fn default() -> Self { |     fn default() -> Self { | ||||||
|         Self { |         Self { | ||||||
|             voter_pubkey: Pubkey::default(), |             voter_pubkey: Pubkey::default(), | ||||||
|  |             voter_pubkey_epoch: 0, | ||||||
|             credits_observed: 0, |             credits_observed: 0, | ||||||
|             stake: 0, |             stake: 0, | ||||||
|             activation_epoch: 0, |             activation_epoch: 0, | ||||||
|             deactivation_epoch: std::u64::MAX, |             deactivation_epoch: std::u64::MAX, | ||||||
|             config: Config::default(), |             config: Config::default(), | ||||||
|             lockup: 0, |             lockup: 0, | ||||||
|  |             prior_delegates: <[(Pubkey, Epoch, Epoch); MAX_PRIOR_DELEGATES]>::default(), | ||||||
|  |             prior_delegates_idx: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -105,6 +104,10 @@ impl Stake { | |||||||
|         self.stake_activating_and_deactivating(epoch, history).0 |         self.stake_activating_and_deactivating(epoch, history).0 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn voter_pubkey(&self, _epoch: Epoch) -> &Pubkey { | ||||||
|  |         &self.voter_pubkey | ||||||
|  |     } | ||||||
|  |  | ||||||
|     fn stake_activating_and_deactivating( |     fn stake_activating_and_deactivating( | ||||||
|         &self, |         &self, | ||||||
|         epoch: Epoch, |         epoch: Epoch, | ||||||
| @@ -405,6 +408,8 @@ impl<'a> StakeAccount for KeyedAccount<'a> { | |||||||
|         { |         { | ||||||
|             let vote_state: VoteState = vote_account.state()?; |             let vote_state: VoteState = vote_account.state()?; | ||||||
|  |  | ||||||
|  |             // the only valid use of current voter_pubkey, redelegation breaks | ||||||
|  |             //  rewards redemption for previous voter_pubkey | ||||||
|             if stake.voter_pubkey != *vote_account.unsigned_key() { |             if stake.voter_pubkey != *vote_account.unsigned_key() { | ||||||
|                 return Err(InstructionError::InvalidArgument); |                 return Err(InstructionError::InvalidArgument); | ||||||
|             } |             } | ||||||
| @@ -633,8 +638,7 @@ mod tests { | |||||||
|                 stake: stake_lamports, |                 stake: stake_lamports, | ||||||
|                 activation_epoch: clock.epoch, |                 activation_epoch: clock.epoch, | ||||||
|                 deactivation_epoch: std::u64::MAX, |                 deactivation_epoch: std::u64::MAX, | ||||||
|                 config: Config::default(), |                 ..Stake::default() | ||||||
|                 lockup: 0 |  | ||||||
|             }) |             }) | ||||||
|         ); |         ); | ||||||
|         // verify that delegate_stake can't be called twice StakeState::default() |         // verify that delegate_stake can't be called twice StakeState::default() | ||||||
| @@ -1257,32 +1261,6 @@ mod tests { | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[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::CustomError(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!( |  | ||||||
|             "CustomError(0): StakeError::NoCreditsToRedeem - not enough credits to redeem", |  | ||||||
|             pretty_err::<StakeError>(StakeError::NoCreditsToRedeem.into()) |  | ||||||
|         ) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_stake_state_calculate_rewards() { |     fn test_stake_state_calculate_rewards() { | ||||||
|         let mut vote_state = VoteState::default(); |         let mut vote_state = VoteState::default(); | ||||||
|   | |||||||
| @@ -1,17 +1,52 @@ | |||||||
| //! Vote program | //! Vote program | ||||||
| //! Receive and processes votes from validators | //! Receive and processes votes from validators | ||||||
|  |  | ||||||
| use crate::id; | use crate::{ | ||||||
| use crate::vote_state::{self, Vote, VoteState}; |     id, | ||||||
|  |     vote_state::{self, Vote, VoteState}, | ||||||
|  | }; | ||||||
| use bincode::deserialize; | use bincode::deserialize; | ||||||
| use log::*; | use log::*; | ||||||
|  | use num_derive::{FromPrimitive, ToPrimitive}; | ||||||
| use serde_derive::{Deserialize, Serialize}; | use serde_derive::{Deserialize, Serialize}; | ||||||
| use solana_metrics::datapoint_warn; | use solana_metrics::datapoint_warn; | ||||||
| use solana_sdk::account::KeyedAccount; | use solana_sdk::{ | ||||||
| use solana_sdk::instruction::{AccountMeta, Instruction, InstructionError}; |     account::KeyedAccount, | ||||||
| use solana_sdk::pubkey::Pubkey; |     instruction::{AccountMeta, Instruction, InstructionError}, | ||||||
| use solana_sdk::system_instruction; |     instruction_processor_utils::DecodeError, | ||||||
| use solana_sdk::sysvar; |     pubkey::Pubkey, | ||||||
|  |     system_instruction, sysvar, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// Reasons the stake might have had an error | ||||||
|  | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] | ||||||
|  | pub enum VoteError { | ||||||
|  |     VoteTooOld, | ||||||
|  |     SlotsMismatch, | ||||||
|  |     SlotHashMismatch, | ||||||
|  |     EmptySlots, | ||||||
|  | } | ||||||
|  | impl<E> DecodeError<E> for VoteError { | ||||||
|  |     fn type_of() -> &'static str { | ||||||
|  |         "VoteError" | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl std::fmt::Display for VoteError { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|  |         write!( | ||||||
|  |             f, | ||||||
|  |             "{}", | ||||||
|  |             match self { | ||||||
|  |                 VoteError::VoteTooOld => "vote already recorded or not in slot hashes history", | ||||||
|  |                 VoteError::SlotsMismatch => "vote slots do not match bank history", | ||||||
|  |                 VoteError::SlotHashMismatch => "vote hash does not match bank hash", | ||||||
|  |                 VoteError::EmptySlots => "vote has no slots, invalid", | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | impl std::error::Error for VoteError {} | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | ||||||
| pub enum VoteInstruction { | pub enum VoteInstruction { | ||||||
|   | |||||||
| @@ -1,9 +1,8 @@ | |||||||
| //! Vote state, vote program | //! Vote state, vote program | ||||||
| //! Receive and processes votes from validators | //! Receive and processes votes from validators | ||||||
| use crate::id; | use crate::{id, vote_instruction::VoteError}; | ||||||
| use bincode::{deserialize, serialize_into, serialized_size, ErrorKind}; | use bincode::{deserialize, serialize_into, serialized_size, ErrorKind}; | ||||||
| use log::*; | use log::*; | ||||||
| use num_derive::{FromPrimitive, ToPrimitive}; |  | ||||||
| use serde_derive::{Deserialize, Serialize}; | use serde_derive::{Deserialize, Serialize}; | ||||||
| use solana_sdk::sysvar::slot_hashes::SlotHash; | use solana_sdk::sysvar::slot_hashes::SlotHash; | ||||||
| use solana_sdk::{ | use solana_sdk::{ | ||||||
| @@ -12,7 +11,6 @@ use solana_sdk::{ | |||||||
|     clock::{Epoch, Slot}, |     clock::{Epoch, Slot}, | ||||||
|     hash::Hash, |     hash::Hash, | ||||||
|     instruction::InstructionError, |     instruction::InstructionError, | ||||||
|     instruction_processor_utils::DecodeError, |  | ||||||
|     pubkey::Pubkey, |     pubkey::Pubkey, | ||||||
|     sysvar::clock::Clock, |     sysvar::clock::Clock, | ||||||
| }; | }; | ||||||
| @@ -26,36 +24,6 @@ pub const INITIAL_LOCKOUT: usize = 2; | |||||||
| //  smaller numbers makes | //  smaller numbers makes | ||||||
| pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64; | pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64; | ||||||
|  |  | ||||||
| /// Reasons the stake might have had an error |  | ||||||
| #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] |  | ||||||
| pub enum VoteError { |  | ||||||
|     VoteTooOld, |  | ||||||
|     SlotsMismatch, |  | ||||||
|     SlotHashMismatch, |  | ||||||
|     EmptySlots, |  | ||||||
| } |  | ||||||
| impl<E> DecodeError<E> for VoteError { |  | ||||||
|     fn type_of() -> &'static str { |  | ||||||
|         "VoteError" |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl std::fmt::Display for VoteError { |  | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |  | ||||||
|         write!( |  | ||||||
|             f, |  | ||||||
|             "{}", |  | ||||||
|             match self { |  | ||||||
|                 VoteError::VoteTooOld => "vote already recorded or not in slot hashes history", |  | ||||||
|                 VoteError::SlotsMismatch => "vote slots do not match bank history", |  | ||||||
|                 VoteError::SlotHashMismatch => "vote hash does not match bank hash", |  | ||||||
|                 VoteError::EmptySlots => "vote has no slots, invalid", |  | ||||||
|             } |  | ||||||
|         ) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| impl std::error::Error for VoteError {} |  | ||||||
|  |  | ||||||
| #[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)] | #[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)] | ||||||
| pub struct Vote { | pub struct Vote { | ||||||
|     /// A stack of votes starting with the oldest vote |     /// A stack of votes starting with the oldest vote | ||||||
|   | |||||||
| @@ -85,7 +85,7 @@ impl Stakes { | |||||||
|             .iter() |             .iter() | ||||||
|             .map(|(_, stake_account)| { |             .map(|(_, stake_account)| { | ||||||
|                 StakeState::stake_from(stake_account).map_or(0, |stake| { |                 StakeState::stake_from(stake_account).map_or(0, |stake| { | ||||||
|                     if stake.voter_pubkey == *voter_pubkey { |                     if stake.voter_pubkey(epoch) == voter_pubkey { | ||||||
|                         stake.stake(epoch, stake_history) |                         stake.stake(epoch, stake_history) | ||||||
|                     } else { |                     } else { | ||||||
|                         0 |                         0 | ||||||
| @@ -129,7 +129,7 @@ impl Stakes { | |||||||
|             let old_stake = self.stake_accounts.get(pubkey).and_then(|old_account| { |             let old_stake = self.stake_accounts.get(pubkey).and_then(|old_account| { | ||||||
|                 StakeState::stake_from(old_account).map(|stake| { |                 StakeState::stake_from(old_account).map(|stake| { | ||||||
|                     ( |                     ( | ||||||
|                         stake.voter_pubkey, |                         *stake.voter_pubkey(self.epoch), | ||||||
|                         stake.stake(self.epoch, Some(&self.stake_history)), |                         stake.stake(self.epoch, Some(&self.stake_history)), | ||||||
|                     ) |                     ) | ||||||
|                 }) |                 }) | ||||||
| @@ -137,7 +137,7 @@ impl Stakes { | |||||||
|  |  | ||||||
|             let stake = StakeState::stake_from(account).map(|stake| { |             let stake = StakeState::stake_from(account).map(|stake| { | ||||||
|                 ( |                 ( | ||||||
|                     stake.voter_pubkey, |                     *stake.voter_pubkey(self.epoch), | ||||||
|                     if account.lamports != 0 { |                     if account.lamports != 0 { | ||||||
|                         stake.stake(self.epoch, Some(&self.stake_history)) |                         stake.stake(self.epoch, Some(&self.stake_history)) | ||||||
|                     } else { |                     } else { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user