Skip to content

Conversation

@carllin
Copy link
Contributor

@carllin carllin commented Mar 17, 2025

Problem

  1. Gossip doesn't properly parse out alpenglow votes to pass to downstream listeners in repair and replay
  2. Push vote services doesn't properly parse alpenglow votes

Summary of Changes

Parse out votes

Fixes #

@carllin carllin requested review from ksn6 and wen-coding March 17, 2025 07:32
@carllin
Copy link
Contributor Author

carllin commented Mar 17, 2025

Hmm for some reason, votes aren't being received by the second node over gossip in #89, even though i see the leader pushing them into gossip...ick

if vote.is_alpenglow_vote() {
return None;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: is this equivalent to
if (slot >= first_alpenglow_slot) ^ vote.is_alpenglow_vote() {
return None;
}
?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it's equivalent, changed

ParsedVoteTransaction::Alpenglow(tx) => match tx {
AlpenglowVote::Notarize(vote) => Some((vote.slot(), *vote.replayed_bank_hash())),
AlpenglowVote::Finalize(vote) => Some((vote.slot(), *vote.replayed_bank_hash())),
AlpenglowVote::Skip(_vote) => None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can give Skip Some((vote.end_slot(), Hash::default())) to make the vote sending work? I don't think we care that much about the start_slot changing

If we do that, then I think this function can return (Slot, Hash), since it will always return Some(...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you want to send skip votes to repair for fork choice weighting, so that logic should probably be handled separately

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, let's add a comment here saying why Skip should return None then.


pub fn is_full_tower_vote(&self) -> bool {
match self {
ParsedVoteTransaction::Tower(tx) => tx.is_full_tower_vote(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we still have anything other than full tower vote in TowerBFT side when Alpenglow launches?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no I think we should be ignoring all alpenglow votes for slots < the first alpenglow slot, hence this check https://github.com/anza-xyz/alpenglow/pulls#discussion_r1999224815

Some((*key, vote, switch_proof_hash, signature))
Some((
*key,
ParsedVoteTransaction::Tower(vote),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm why don't we need this for Alpenglow?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's "this"? this is the equivalent for alpenglow:

ParsedVoteTransaction::Alpenglow(alpenglow_vote),

))
}

pub fn parse_alpenglow_vote_transaction(tx: &Transaction) -> Option<ParsedVote> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can this guy and parse_sanitized_alpenglow_vote_transaction share code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could probably pass some closures to handle custom parsing, but code overlap is small enough where it doesn't seem worth it


fn parse_alpenglow_vote_instruction_data(vote_instruction_data: &[u8]) -> Option<AlpenglowVote> {
alpenglow_vote::vote::Vote::deserialize_simple_vote(vote_instruction_data).ok()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:: add TODO to add test cases.

Also can we use alpenglow_vote::vote::Vote as AlpenglowVote?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

vec![(
validator0_keypairs.vote_keypair.pubkey(),
VoteTransaction::from(Vote::new(vec![voted_slot], Hash::default())),
ParsedVoteTransaction::Tower(VoteTransaction::from(Vote::new(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add TODO for alpenglow test

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah going to need to go through and write some detailed tests, might hand off to @ksn6

@carllin
Copy link
Contributor Author

carllin commented Mar 17, 2025

stats.record_received_packet(packet.deserialize_slice::<Protocol, _>(..))?;
gossip failing to deserialize votes here for some reason

Edit: Figured it out, its the deserialize implementation in CrdsData::Vote, fixed here: 9ee113a

Repair now seems to be working with two local cluster nodes!

@carllin carllin changed the title Parse out alpenglow votes from gossip Parse out alpenglow votes in vote_parser.rs Mar 17, 2025
@carllin carllin merged commit 391639a into anza-xyz:master Mar 18, 2025
7 checks passed
Copy link
Contributor

@AshwinSekar AshwinSekar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Post merge LGTM

Just a couple nits

}
}

fn parse_alpenglow_vote_instruction_data(vote_instruction_data: &[u8]) -> Option<AlpenglowVote> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we could also check AlpenglowVote::is_simple_vote if we want to distinguish between accounting instructions here.
Also fine to keep it as is, accounting instructions and invalid packets will both turn into None


// TODO: add tests
pub fn parse_alpenglow_vote_transaction(tx: &Transaction) -> Option<ParsedVote> {
// Check first instruction for a vote
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are doing this from scratch here, we could formalize the requirement that votes must be a single instruction transaction (fail to parse here and in banking stage).

bw-solana pushed a commit to bw-solana/alpenglow that referenced this pull request Aug 1, 2025
bw-solana pushed a commit to bw-solana/alpenglow that referenced this pull request Aug 1, 2025
bw-solana pushed a commit to bw-solana/alpenglow that referenced this pull request Aug 1, 2025
bw-solana pushed a commit to bw-solana/alpenglow that referenced this pull request Aug 1, 2025
bw-solana pushed a commit to bw-solana/alpenglow that referenced this pull request Aug 1, 2025
bw-solana pushed a commit to bw-solana/alpenglow that referenced this pull request Aug 1, 2025
bw-solana pushed a commit to bw-solana/alpenglow that referenced this pull request Aug 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants