Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increment timestamp on refreshed votes #31908

Merged
merged 1 commit into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions core/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,39 @@ impl Tower {
self.last_vote_tx_blockhash
}

pub fn refresh_last_vote_timestamp(&mut self, heaviest_slot_on_same_fork: Slot) {
let timestamp = if let Some(last_vote_timestamp) = self.last_vote.timestamp() {
// To avoid a refreshed vote tx getting caught in deduplication filters,
// we need to update timestamp. Increment by smallest amount to avoid skewing
// the Timestamp Oracle.
last_vote_timestamp.saturating_add(1)
} else {
// If the previous vote did not send a timestamp due to clock error,
// use the last good timestamp + 1
self.last_timestamp.timestamp.saturating_add(1)
};

if let Some(last_voted_slot) = self.last_vote.last_voted_slot() {
if heaviest_slot_on_same_fork <= last_voted_slot {
warn!(
"Trying to refresh timestamp for vote on {last_voted_slot}
using smaller heaviest bank {heaviest_slot_on_same_fork}"
);
return;
}
self.last_timestamp = BlockTimestamp {
slot: last_voted_slot,
timestamp,
};
self.last_vote.set_timestamp(Some(timestamp));
} else {
warn!(
"Trying to refresh timestamp for last vote on heaviest bank on same fork
{heaviest_slot_on_same_fork}, but there is no vote to refresh"
);
}
}

pub fn refresh_last_vote_tx_blockhash(&mut self, new_vote_tx_blockhash: Hash) {
self.last_vote_tx_blockhash = new_vote_tx_blockhash;
}
Expand Down Expand Up @@ -2634,6 +2667,44 @@ pub mod test {
assert!(tower.maybe_timestamp(3).is_none()); // slot 3 gets no timestamp
}

#[test]
fn test_refresh_last_vote_timestamp() {
let mut tower = Tower::default();

// Tower has no vote or timestamp
tower.last_vote.set_timestamp(None);
tower.refresh_last_vote_timestamp(5);
assert_eq!(tower.last_vote.timestamp(), None);
assert_eq!(tower.last_timestamp.slot, 0);
assert_eq!(tower.last_timestamp.timestamp, 0);

// Tower has vote no timestamp, but is greater than heaviest_bank
tower.last_vote =
VoteTransaction::from(VoteStateUpdate::from(vec![(0, 3), (1, 2), (6, 1)]));
assert_eq!(tower.last_vote.timestamp(), None);
tower.refresh_last_vote_timestamp(5);
assert_eq!(tower.last_vote.timestamp(), None);
assert_eq!(tower.last_timestamp.slot, 0);
assert_eq!(tower.last_timestamp.timestamp, 0);

// Tower has vote with no timestamp
tower.last_vote =
VoteTransaction::from(VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]));
assert_eq!(tower.last_vote.timestamp(), None);
tower.refresh_last_vote_timestamp(5);
assert_eq!(tower.last_vote.timestamp(), Some(1));
assert_eq!(tower.last_timestamp.slot, 2);
assert_eq!(tower.last_timestamp.timestamp, 1);

// Vote has timestamp
tower.last_vote =
VoteTransaction::from(VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]));
tower.refresh_last_vote_timestamp(5);
assert_eq!(tower.last_vote.timestamp(), Some(2));
assert_eq!(tower.last_timestamp.slot, 2);
assert_eq!(tower.last_timestamp.timestamp, 2);
}

fn run_test_load_tower_snapshot<F, G>(
modify_original: F,
modify_serialized: G,
Expand Down
5 changes: 3 additions & 2 deletions core/src/replay_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2366,8 +2366,9 @@ impl ReplayStage {
return;
}

// TODO: check the timestamp in this vote is correct, i.e. it shouldn't
// have changed from the original timestamp of the vote.
// Update timestamp for refreshed vote
tower.refresh_last_vote_timestamp(heaviest_bank_on_same_fork.slot());

let vote_tx = Self::generate_vote_tx(
identity_keypair,
heaviest_bank_on_same_fork,
Expand Down