Submit a vote timestamp every vote (#10630)
* Submit a timestamp for every vote * Submit at most one vote timestamp per second * Submit a timestamp for every new vote Co-authored-by: Tyera Eulberg <tyera@solana.com>
This commit is contained in:
parent
41868f8adb
commit
247f27af37
|
@ -13,9 +13,7 @@ use solana_sdk::{
|
|||
};
|
||||
use solana_vote_program::{
|
||||
vote_instruction,
|
||||
vote_state::{
|
||||
BlockTimestamp, Lockout, Vote, VoteState, MAX_LOCKOUT_HISTORY, TIMESTAMP_SLOT_INTERVAL,
|
||||
},
|
||||
vote_state::{BlockTimestamp, Lockout, Vote, VoteState, MAX_LOCKOUT_HISTORY},
|
||||
};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
|
@ -345,6 +343,20 @@ impl Tower {
|
|||
last_vote
|
||||
}
|
||||
|
||||
fn maybe_timestamp(&mut self, current_slot: Slot) -> Option<UnixTimestamp> {
|
||||
if current_slot > self.last_timestamp.slot {
|
||||
let timestamp = Utc::now().timestamp();
|
||||
if timestamp >= self.last_timestamp.timestamp {
|
||||
self.last_timestamp = BlockTimestamp {
|
||||
slot: current_slot,
|
||||
timestamp,
|
||||
};
|
||||
return Some(timestamp);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn root(&self) -> Option<Slot> {
|
||||
self.lockouts.root_slot
|
||||
}
|
||||
|
@ -650,21 +662,6 @@ impl Tower {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_timestamp(&mut self, current_slot: Slot) -> Option<UnixTimestamp> {
|
||||
if self.last_timestamp.slot == 0
|
||||
|| self.last_timestamp.slot < (current_slot - (current_slot % TIMESTAMP_SLOT_INTERVAL))
|
||||
{
|
||||
let timestamp = Utc::now().timestamp();
|
||||
self.last_timestamp = BlockTimestamp {
|
||||
slot: current_slot,
|
||||
timestamp,
|
||||
};
|
||||
Some(timestamp)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -691,12 +688,7 @@ pub mod test {
|
|||
vote_state::{Vote, VoteStateVersions, MAX_LOCKOUT_HISTORY},
|
||||
vote_transaction,
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
rc::Rc,
|
||||
sync::RwLock,
|
||||
{thread::sleep, time::Duration},
|
||||
};
|
||||
use std::{collections::HashMap, rc::Rc, sync::RwLock};
|
||||
use trees::{tr, Tree, TreeWalk};
|
||||
|
||||
pub(crate) struct VoteSimulator {
|
||||
|
@ -1829,17 +1821,15 @@ pub mod test {
|
|||
#[test]
|
||||
fn test_maybe_timestamp() {
|
||||
let mut tower = Tower::default();
|
||||
assert!(tower.maybe_timestamp(TIMESTAMP_SLOT_INTERVAL).is_some());
|
||||
let BlockTimestamp { slot, timestamp } = tower.last_timestamp;
|
||||
assert!(tower.maybe_timestamp(0).is_none());
|
||||
assert!(tower.maybe_timestamp(1).is_some());
|
||||
assert!(tower.maybe_timestamp(0).is_none()); // Refuse to timestamp an older slot
|
||||
assert!(tower.maybe_timestamp(1).is_none()); // Refuse to timestamp the same slot twice
|
||||
|
||||
assert_eq!(tower.maybe_timestamp(1), None);
|
||||
assert_eq!(tower.maybe_timestamp(slot), None);
|
||||
assert_eq!(tower.maybe_timestamp(slot + 1), None);
|
||||
tower.last_timestamp.timestamp -= 1; // Move last_timestamp into the past
|
||||
assert!(tower.maybe_timestamp(2).is_some()); // slot 2 gets a timestamp
|
||||
|
||||
sleep(Duration::from_secs(1));
|
||||
assert!(tower
|
||||
.maybe_timestamp(slot + TIMESTAMP_SLOT_INTERVAL + 1)
|
||||
.is_some());
|
||||
assert!(tower.last_timestamp.timestamp > timestamp);
|
||||
tower.last_timestamp.timestamp += 1_000_000; // Move last_timestamp well into the future
|
||||
assert!(tower.maybe_timestamp(3).is_none()); // slot 3 gets no timestamp
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ impl From<RpcCustomError> for Error {
|
|||
},
|
||||
RpcCustomError::BlockNotAvailable { slot } => Self {
|
||||
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_4),
|
||||
message: format!("Block not available for slot {}", slot,),
|
||||
message: format!("Block not available for slot {}", slot),
|
||||
data: None,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ use solana_transaction_status::{
|
|||
EncodedTransaction, Rewards, TransactionStatusMeta, TransactionWithStatusMeta,
|
||||
UiTransactionEncoding, UiTransactionStatusMeta,
|
||||
};
|
||||
use solana_vote_program::{vote_instruction::VoteInstruction, vote_state::TIMESTAMP_SLOT_INTERVAL};
|
||||
use solana_vote_program::vote_instruction::VoteInstruction;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
cmp,
|
||||
|
@ -78,6 +78,7 @@ thread_local!(static PAR_THREAD_POOL_ALL_CPUS: RefCell<ThreadPool> = RefCell::ne
|
|||
pub const MAX_COMPLETED_SLOTS_IN_CHANNEL: usize = 100_000;
|
||||
pub const MAX_TURBINE_PROPAGATION_IN_MS: u64 = 100;
|
||||
pub const MAX_TURBINE_DELAY_IN_TICKS: u64 = MAX_TURBINE_PROPAGATION_IN_MS / MS_PER_TICK;
|
||||
const TIMESTAMP_SLOT_INTERVAL: u64 = 4500;
|
||||
const TIMESTAMP_SLOT_RANGE: usize = 16;
|
||||
|
||||
// An upper bound on maximum number of data shreds we can handle in a slot
|
||||
|
|
|
@ -32,10 +32,6 @@ pub const INITIAL_LOCKOUT: usize = 2;
|
|||
// smaller numbers makes
|
||||
pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64;
|
||||
|
||||
// Frequency of timestamp Votes. In v0.22.0, this is approximately 30min with cluster clock
|
||||
// defaults, intended to limit block time drift to < 1hr
|
||||
pub const TIMESTAMP_SLOT_INTERVAL: u64 = 4500;
|
||||
|
||||
#[frozen_abi(digest = "69hYtmmcuqPbhpc64ZaNJDidaUcg66CW6wzPFiuYZ3To")]
|
||||
#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
|
||||
pub struct Vote {
|
||||
|
|
Loading…
Reference in New Issue