vote: add TowerSync ix (#365)
* vote: add TowerSync ix * fork_id -> block_id
This commit is contained in:
parent
64765bf817
commit
a468ff2999
|
@ -97,6 +97,9 @@ impl SwitchForkDecision {
|
|||
v,
|
||||
))
|
||||
}
|
||||
(SwitchForkDecision::SameFork, VoteTransaction::TowerSync(t)) => Some(
|
||||
vote_instruction::tower_sync(vote_account_pubkey, authorized_voter_pubkey, t),
|
||||
),
|
||||
(SwitchForkDecision::SwitchProof(switch_proof_hash), VoteTransaction::Vote(v)) => {
|
||||
Some(vote_instruction::vote_switch(
|
||||
vote_account_pubkey,
|
||||
|
@ -114,6 +117,14 @@ impl SwitchForkDecision {
|
|||
v,
|
||||
*switch_proof_hash,
|
||||
)),
|
||||
(SwitchForkDecision::SwitchProof(switch_proof_hash), VoteTransaction::TowerSync(t)) => {
|
||||
Some(vote_instruction::tower_sync_switch(
|
||||
vote_account_pubkey,
|
||||
authorized_voter_pubkey,
|
||||
t,
|
||||
*switch_proof_hash,
|
||||
))
|
||||
}
|
||||
(SwitchForkDecision::SameFork, VoteTransaction::CompactVoteStateUpdate(v)) => {
|
||||
Some(vote_instruction::compact_update_vote_state(
|
||||
vote_account_pubkey,
|
||||
|
@ -221,7 +232,7 @@ pub(crate) enum BlockhashStatus {
|
|||
Blockhash(Hash),
|
||||
}
|
||||
|
||||
#[frozen_abi(digest = "iZi6s9BvytU3HbRsibrAD71jwMLvrqHdCjVk6qKcVvd")]
|
||||
#[frozen_abi(digest = "679XkZ4upGc389SwqAsjs5tr2qB4wisqjbwtei7fGhxC")]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, AbiExample)]
|
||||
pub struct Tower {
|
||||
pub node_pubkey: Pubkey,
|
||||
|
|
|
@ -6,7 +6,7 @@ use {
|
|||
},
|
||||
};
|
||||
|
||||
#[frozen_abi(digest = "F83xHQA1wxoFDy25MTKXXmFXTc9Jbp6SXRXEPcehtKbQ")]
|
||||
#[frozen_abi(digest = "4LayQwoKrE2jPhbNtg3TSpKrtEtjcPiwsVPJN7aCavri")]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, AbiExample)]
|
||||
pub struct Tower1_14_11 {
|
||||
pub(crate) node_pubkey: Pubkey,
|
||||
|
|
|
@ -9,6 +9,7 @@ use {
|
|||
sysvar_cache::get_sysvar_with_account_check,
|
||||
},
|
||||
solana_sdk::{
|
||||
feature_set,
|
||||
instruction::InstructionError,
|
||||
program_utils::limited_deserialize,
|
||||
pubkey::Pubkey,
|
||||
|
@ -192,7 +193,17 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
|
|||
&invoke_context.feature_set,
|
||||
)
|
||||
}
|
||||
|
||||
VoteInstruction::TowerSync(_tower_sync)
|
||||
| VoteInstruction::TowerSyncSwitch(_tower_sync, _) => {
|
||||
if !invoke_context
|
||||
.feature_set
|
||||
.is_active(&feature_set::enable_tower_sync_ix::id())
|
||||
{
|
||||
return Err(InstructionError::InvalidInstructionData);
|
||||
}
|
||||
// TODO: will fill in future PR
|
||||
return Err(InstructionError::InvalidInstructionData);
|
||||
}
|
||||
VoteInstruction::Withdraw(lamports) => {
|
||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||
let rent_sysvar = invoke_context.get_sysvar_cache().get_rent()?;
|
||||
|
|
|
@ -28,13 +28,15 @@ use {
|
|||
},
|
||||
};
|
||||
|
||||
#[frozen_abi(digest = "2AuJFjx7SYrJ2ugCfH1jFh3Lr9UHMEPfKwwk1NcjqND1")]
|
||||
#[frozen_abi(digest = "EcS3xgfomytEAQ1eVd8R76ZejwyHp2Ed8dHqQWh6zi5v")]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, AbiEnumVisitor, AbiExample)]
|
||||
pub enum VoteTransaction {
|
||||
Vote(Vote),
|
||||
VoteStateUpdate(VoteStateUpdate),
|
||||
#[serde(with = "serde_compact_vote_state_update")]
|
||||
CompactVoteStateUpdate(VoteStateUpdate),
|
||||
#[serde(with = "serde_tower_sync")]
|
||||
TowerSync(TowerSync),
|
||||
}
|
||||
|
||||
impl VoteTransaction {
|
||||
|
@ -43,6 +45,7 @@ impl VoteTransaction {
|
|||
VoteTransaction::Vote(vote) => vote.slots.clone(),
|
||||
VoteTransaction::VoteStateUpdate(vote_state_update) => vote_state_update.slots(),
|
||||
VoteTransaction::CompactVoteStateUpdate(vote_state_update) => vote_state_update.slots(),
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.slots(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +56,7 @@ impl VoteTransaction {
|
|||
| VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
|
||||
vote_state_update.lockouts[i].slot()
|
||||
}
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.lockouts[i].slot(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,6 +67,7 @@ impl VoteTransaction {
|
|||
| VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
|
||||
vote_state_update.lockouts.len()
|
||||
}
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.lockouts.len(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +78,7 @@ impl VoteTransaction {
|
|||
| VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
|
||||
vote_state_update.lockouts.is_empty()
|
||||
}
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.lockouts.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +87,7 @@ impl VoteTransaction {
|
|||
VoteTransaction::Vote(vote) => vote.hash,
|
||||
VoteTransaction::VoteStateUpdate(vote_state_update) => vote_state_update.hash,
|
||||
VoteTransaction::CompactVoteStateUpdate(vote_state_update) => vote_state_update.hash,
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.hash,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,6 +98,7 @@ impl VoteTransaction {
|
|||
| VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
|
||||
vote_state_update.timestamp
|
||||
}
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +109,7 @@ impl VoteTransaction {
|
|||
| VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
|
||||
vote_state_update.timestamp = ts
|
||||
}
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.timestamp = ts,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,6 +120,7 @@ impl VoteTransaction {
|
|||
| VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
|
||||
vote_state_update.last_voted_slot()
|
||||
}
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.last_voted_slot(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,6 +141,12 @@ impl From<VoteStateUpdate> for VoteTransaction {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<TowerSync> for VoteTransaction {
|
||||
fn from(tower_sync: TowerSync) -> Self {
|
||||
VoteTransaction::TowerSync(tower_sync)
|
||||
}
|
||||
}
|
||||
|
||||
// utility function, used by Stakes, tests
|
||||
pub fn from<T: ReadableAccount>(account: &T) -> Option<VoteState> {
|
||||
VoteState::deserialize(account.data()).ok()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Vote program instructions
|
||||
|
||||
use {
|
||||
super::state::TowerSync,
|
||||
crate::{
|
||||
clock::{Slot, UnixTimestamp},
|
||||
hash::Hash,
|
||||
|
@ -10,7 +11,7 @@ use {
|
|||
vote::{
|
||||
program::id,
|
||||
state::{
|
||||
serde_compact_vote_state_update, Vote, VoteAuthorize,
|
||||
serde_compact_vote_state_update, serde_tower_sync, Vote, VoteAuthorize,
|
||||
VoteAuthorizeCheckedWithSeedArgs, VoteAuthorizeWithSeedArgs, VoteInit,
|
||||
VoteStateUpdate, VoteStateVersions,
|
||||
},
|
||||
|
@ -146,6 +147,21 @@ pub enum VoteInstruction {
|
|||
#[serde(with = "serde_compact_vote_state_update")] VoteStateUpdate,
|
||||
Hash,
|
||||
),
|
||||
|
||||
/// Sync the onchain vote state with local tower
|
||||
///
|
||||
/// # Account references
|
||||
/// 0. `[Write]` Vote account to vote with
|
||||
/// 1. `[SIGNER]` Vote authority
|
||||
#[serde(with = "serde_tower_sync")]
|
||||
TowerSync(TowerSync),
|
||||
|
||||
/// Sync the onchain vote state with local tower along with a switching proof
|
||||
///
|
||||
/// # Account references
|
||||
/// 0. `[Write]` Vote account to vote with
|
||||
/// 1. `[SIGNER]` Vote authority
|
||||
TowerSyncSwitch(#[serde(with = "serde_tower_sync")] TowerSync, Hash),
|
||||
}
|
||||
|
||||
impl VoteInstruction {
|
||||
|
@ -157,7 +173,9 @@ impl VoteInstruction {
|
|||
| Self::UpdateVoteState(_)
|
||||
| Self::UpdateVoteStateSwitch(_, _)
|
||||
| Self::CompactUpdateVoteState(_)
|
||||
| Self::CompactUpdateVoteStateSwitch(_, _),
|
||||
| Self::CompactUpdateVoteStateSwitch(_, _)
|
||||
| Self::TowerSync(_)
|
||||
| Self::TowerSyncSwitch(_, _),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -167,7 +185,9 @@ impl VoteInstruction {
|
|||
Self::UpdateVoteState(_)
|
||||
| Self::UpdateVoteStateSwitch(_, _)
|
||||
| Self::CompactUpdateVoteState(_)
|
||||
| Self::CompactUpdateVoteStateSwitch(_, _),
|
||||
| Self::CompactUpdateVoteStateSwitch(_, _)
|
||||
| Self::TowerSync(_)
|
||||
| Self::TowerSyncSwitch(_, _),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -182,6 +202,9 @@ impl VoteInstruction {
|
|||
| Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
|
||||
vote_state_update.last_voted_slot()
|
||||
}
|
||||
Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => {
|
||||
tower_sync.last_voted_slot()
|
||||
}
|
||||
_ => panic!("Tried to get slot on non simple vote instruction"),
|
||||
}
|
||||
}
|
||||
|
@ -197,6 +220,9 @@ impl VoteInstruction {
|
|||
| Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
|
||||
vote_state_update.timestamp
|
||||
}
|
||||
Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => {
|
||||
tower_sync.timestamp
|
||||
}
|
||||
_ => panic!("Tried to get timestamp on non simple vote instruction"),
|
||||
}
|
||||
}
|
||||
|
@ -514,6 +540,37 @@ pub fn compact_update_vote_state_switch(
|
|||
)
|
||||
}
|
||||
|
||||
pub fn tower_sync(
|
||||
vote_pubkey: &Pubkey,
|
||||
authorized_voter_pubkey: &Pubkey,
|
||||
tower_sync: TowerSync,
|
||||
) -> Instruction {
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*vote_pubkey, false),
|
||||
AccountMeta::new_readonly(*authorized_voter_pubkey, true),
|
||||
];
|
||||
|
||||
Instruction::new_with_bincode(id(), &VoteInstruction::TowerSync(tower_sync), account_metas)
|
||||
}
|
||||
|
||||
pub fn tower_sync_switch(
|
||||
vote_pubkey: &Pubkey,
|
||||
authorized_voter_pubkey: &Pubkey,
|
||||
tower_sync: TowerSync,
|
||||
proof_hash: Hash,
|
||||
) -> Instruction {
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*vote_pubkey, false),
|
||||
AccountMeta::new_readonly(*authorized_voter_pubkey, true),
|
||||
];
|
||||
|
||||
Instruction::new_with_bincode(
|
||||
id(),
|
||||
&VoteInstruction::TowerSyncSwitch(tower_sync, proof_hash),
|
||||
account_metas,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn withdraw(
|
||||
vote_pubkey: &Pubkey,
|
||||
authorized_withdrawer_pubkey: &Pubkey,
|
||||
|
|
|
@ -207,6 +207,66 @@ impl VoteStateUpdate {
|
|||
}
|
||||
}
|
||||
|
||||
#[frozen_abi(digest = "5VUusSTenF9vZ9eHiCprVe9ABJUHCubeDNCCDxykybZY")]
|
||||
#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
|
||||
pub struct TowerSync {
|
||||
/// The proposed tower
|
||||
pub lockouts: VecDeque<Lockout>,
|
||||
/// The proposed root
|
||||
pub root: Option<Slot>,
|
||||
/// signature of the bank's state at the last slot
|
||||
pub hash: Hash,
|
||||
/// processing timestamp of last slot
|
||||
pub timestamp: Option<UnixTimestamp>,
|
||||
/// the unique identifier for the chain up to and
|
||||
/// including this block. Does not require replaying
|
||||
/// in order to compute.
|
||||
pub block_id: Hash,
|
||||
}
|
||||
|
||||
impl From<Vec<(Slot, u32)>> for TowerSync {
|
||||
fn from(recent_slots: Vec<(Slot, u32)>) -> Self {
|
||||
let lockouts: VecDeque<Lockout> = recent_slots
|
||||
.into_iter()
|
||||
.map(|(slot, confirmation_count)| {
|
||||
Lockout::new_with_confirmation_count(slot, confirmation_count)
|
||||
})
|
||||
.collect();
|
||||
Self {
|
||||
lockouts,
|
||||
root: None,
|
||||
hash: Hash::default(),
|
||||
timestamp: None,
|
||||
block_id: Hash::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TowerSync {
|
||||
pub fn new(
|
||||
lockouts: VecDeque<Lockout>,
|
||||
root: Option<Slot>,
|
||||
hash: Hash,
|
||||
block_id: Hash,
|
||||
) -> Self {
|
||||
Self {
|
||||
lockouts,
|
||||
root,
|
||||
hash,
|
||||
timestamp: None,
|
||||
block_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn slots(&self) -> Vec<Slot> {
|
||||
self.lockouts.iter().map(|lockout| lockout.slot()).collect()
|
||||
}
|
||||
|
||||
pub fn last_voted_slot(&self) -> Option<Slot> {
|
||||
self.lockouts.back().map(|l| l.slot())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct VoteInit {
|
||||
pub node_pubkey: Pubkey,
|
||||
|
@ -904,6 +964,103 @@ pub mod serde_compact_vote_state_update {
|
|||
}
|
||||
}
|
||||
|
||||
pub mod serde_tower_sync {
|
||||
use {
|
||||
super::*,
|
||||
crate::{
|
||||
clock::{Slot, UnixTimestamp},
|
||||
serde_varint, short_vec,
|
||||
vote::state::Lockout,
|
||||
},
|
||||
serde::{Deserialize, Deserializer, Serialize, Serializer},
|
||||
};
|
||||
|
||||
#[derive(Deserialize, Serialize, AbiExample)]
|
||||
struct LockoutOffset {
|
||||
#[serde(with = "serde_varint")]
|
||||
offset: Slot,
|
||||
confirmation_count: u8,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct CompactTowerSync {
|
||||
root: Slot,
|
||||
#[serde(with = "short_vec")]
|
||||
lockout_offsets: Vec<LockoutOffset>,
|
||||
hash: Hash,
|
||||
timestamp: Option<UnixTimestamp>,
|
||||
block_id: Hash,
|
||||
}
|
||||
|
||||
pub fn serialize<S>(tower_sync: &TowerSync, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let lockout_offsets = tower_sync.lockouts.iter().scan(
|
||||
tower_sync.root.unwrap_or_default(),
|
||||
|slot, lockout| {
|
||||
let Some(offset) = lockout.slot().checked_sub(*slot) else {
|
||||
return Some(Err(serde::ser::Error::custom("Invalid vote lockout")));
|
||||
};
|
||||
let Ok(confirmation_count) = u8::try_from(lockout.confirmation_count()) else {
|
||||
return Some(Err(serde::ser::Error::custom("Invalid confirmation count")));
|
||||
};
|
||||
let lockout_offset = LockoutOffset {
|
||||
offset,
|
||||
confirmation_count,
|
||||
};
|
||||
*slot = lockout.slot();
|
||||
Some(Ok(lockout_offset))
|
||||
},
|
||||
);
|
||||
let compact_tower_sync = CompactTowerSync {
|
||||
root: tower_sync.root.unwrap_or(Slot::MAX),
|
||||
lockout_offsets: lockout_offsets.collect::<Result<_, _>>()?,
|
||||
hash: tower_sync.hash,
|
||||
timestamp: tower_sync.timestamp,
|
||||
block_id: tower_sync.block_id,
|
||||
};
|
||||
compact_tower_sync.serialize(serializer)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<TowerSync, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let CompactTowerSync {
|
||||
root,
|
||||
lockout_offsets,
|
||||
hash,
|
||||
timestamp,
|
||||
block_id,
|
||||
} = CompactTowerSync::deserialize(deserializer)?;
|
||||
let root = (root != Slot::MAX).then_some(root);
|
||||
let lockouts =
|
||||
lockout_offsets
|
||||
.iter()
|
||||
.scan(root.unwrap_or_default(), |slot, lockout_offset| {
|
||||
*slot = match slot.checked_add(lockout_offset.offset) {
|
||||
None => {
|
||||
return Some(Err(serde::de::Error::custom("Invalid lockout offset")))
|
||||
}
|
||||
Some(slot) => slot,
|
||||
};
|
||||
let lockout = Lockout::new_with_confirmation_count(
|
||||
*slot,
|
||||
u32::from(lockout_offset.confirmation_count),
|
||||
);
|
||||
Some(Ok(lockout))
|
||||
});
|
||||
Ok(TowerSync {
|
||||
root,
|
||||
lockouts: lockouts.collect::<Result<_, _>>()?,
|
||||
hash,
|
||||
timestamp,
|
||||
block_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use {super::*, itertools::Itertools, rand::Rng};
|
||||
|
|
|
@ -781,6 +781,10 @@ pub mod remove_rounding_in_fee_calculation {
|
|||
solana_sdk::declare_id!("BtVN7YjDzNE6Dk7kTT7YTDgMNUZTNgiSJgsdzAeTg2jF");
|
||||
}
|
||||
|
||||
pub mod enable_tower_sync_ix {
|
||||
solana_sdk::declare_id!("tSynMCspg4xFiCj1v3TDb4c7crMR5tSBhLz4sF7rrNA");
|
||||
}
|
||||
|
||||
pub mod deprecate_unused_legacy_vote_plumbing {
|
||||
solana_sdk::declare_id!("6Uf8S75PVh91MYgPQSHnjRAPQq6an5BDv9vomrCwDqLe");
|
||||
}
|
||||
|
@ -976,6 +980,7 @@ lazy_static! {
|
|||
(enable_chained_merkle_shreds::id(), "Enable chained Merkle shreds #34916"),
|
||||
(remove_rounding_in_fee_calculation::id(), "Removing unwanted rounding in fee calculation #34982"),
|
||||
(deprecate_unused_legacy_vote_plumbing::id(), "Deprecate unused legacy vote tx plumbing"),
|
||||
(enable_tower_sync_ix::id(), "Enable tower sync vote instruction"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
|
|
@ -171,6 +171,43 @@ pub fn parse_vote(
|
|||
}),
|
||||
})
|
||||
}
|
||||
VoteInstruction::TowerSync(tower_sync) => {
|
||||
check_num_vote_accounts(&instruction.accounts, 2)?;
|
||||
let tower_sync = json!({
|
||||
"lockouts": tower_sync.lockouts,
|
||||
"root": tower_sync.root,
|
||||
"hash": tower_sync.hash.to_string(),
|
||||
"timestamp": tower_sync.timestamp,
|
||||
"blockId": tower_sync.block_id,
|
||||
});
|
||||
Ok(ParsedInstructionEnum {
|
||||
instruction_type: "towersync".to_string(),
|
||||
info: json!({
|
||||
"voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||
"voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||
"towerSync": tower_sync,
|
||||
}),
|
||||
})
|
||||
}
|
||||
VoteInstruction::TowerSyncSwitch(tower_sync, hash) => {
|
||||
check_num_vote_accounts(&instruction.accounts, 2)?;
|
||||
let tower_sync = json!({
|
||||
"lockouts": tower_sync.lockouts,
|
||||
"root": tower_sync.root,
|
||||
"hash": tower_sync.hash.to_string(),
|
||||
"timestamp": tower_sync.timestamp,
|
||||
"blockId": tower_sync.block_id,
|
||||
});
|
||||
Ok(ParsedInstructionEnum {
|
||||
instruction_type: "towersyncswitch".to_string(),
|
||||
info: json!({
|
||||
"voteAccount": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||
"voteAuthority": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||
"towerSync": tower_sync,
|
||||
"hash": hash.to_string(),
|
||||
}),
|
||||
})
|
||||
}
|
||||
VoteInstruction::Withdraw(lamports) => {
|
||||
check_num_vote_accounts(&instruction.accounts, 3)?;
|
||||
Ok(ParsedInstructionEnum {
|
||||
|
|
|
@ -62,6 +62,10 @@ fn parse_vote_instruction_data(
|
|||
VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, hash) => {
|
||||
Some((VoteTransaction::from(vote_state_update), Some(hash)))
|
||||
}
|
||||
VoteInstruction::TowerSync(tower_sync) => Some((VoteTransaction::from(tower_sync), None)),
|
||||
VoteInstruction::TowerSyncSwitch(tower_sync, hash) => {
|
||||
Some((VoteTransaction::from(tower_sync), Some(hash)))
|
||||
}
|
||||
VoteInstruction::Authorize(_, _)
|
||||
| VoteInstruction::AuthorizeChecked(_)
|
||||
| VoteInstruction::AuthorizeWithSeed(_)
|
||||
|
|
|
@ -3,13 +3,14 @@ use {
|
|||
clock::{Slot, UnixTimestamp},
|
||||
hash::Hash,
|
||||
},
|
||||
solana_vote_program::vote_state::{Vote, VoteStateUpdate},
|
||||
solana_vote_program::vote_state::{TowerSync, Vote, VoteStateUpdate},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum VoteTransaction {
|
||||
Vote(Vote),
|
||||
VoteStateUpdate(VoteStateUpdate),
|
||||
TowerSync(TowerSync),
|
||||
}
|
||||
|
||||
impl VoteTransaction {
|
||||
|
@ -21,6 +22,7 @@ impl VoteTransaction {
|
|||
.iter()
|
||||
.map(|lockout| lockout.slot())
|
||||
.collect(),
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.slots(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +32,7 @@ impl VoteTransaction {
|
|||
VoteTransaction::VoteStateUpdate(vote_state_update) => {
|
||||
vote_state_update.lockouts.is_empty()
|
||||
}
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.lockouts.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,6 +40,7 @@ impl VoteTransaction {
|
|||
match self {
|
||||
VoteTransaction::Vote(vote) => vote.hash,
|
||||
VoteTransaction::VoteStateUpdate(vote_state_update) => vote_state_update.hash,
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.hash,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +48,7 @@ impl VoteTransaction {
|
|||
match self {
|
||||
VoteTransaction::Vote(vote) => vote.timestamp,
|
||||
VoteTransaction::VoteStateUpdate(vote_state_update) => vote_state_update.timestamp,
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +58,7 @@ impl VoteTransaction {
|
|||
VoteTransaction::VoteStateUpdate(vote_state_update) => {
|
||||
Some(vote_state_update.lockouts.back()?.slot())
|
||||
}
|
||||
VoteTransaction::TowerSync(tower_sync) => tower_sync.last_voted_slot(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,3 +78,9 @@ impl From<VoteStateUpdate> for VoteTransaction {
|
|||
VoteTransaction::VoteStateUpdate(vote_state_update)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TowerSync> for VoteTransaction {
|
||||
fn from(tower_sync: TowerSync) -> Self {
|
||||
VoteTransaction::TowerSync(tower_sync)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue