voteSubscribe pubsub notification now includes the vote transaction signature (#25291)
This commit is contained in:
parent
97efbdc303
commit
c54e06355f
|
@ -346,6 +346,7 @@ pub struct RpcVote {
|
|||
pub slots: Vec<Slot>,
|
||||
pub hash: String,
|
||||
pub timestamp: Option<UnixTimestamp>,
|
||||
pub signature: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
|
|
|
@ -307,7 +307,7 @@ impl ClusterInfoVoteListener {
|
|||
!packet_batch.packets[0].meta.discard()
|
||||
})
|
||||
.filter_map(|(tx, packet_batch)| {
|
||||
let (vote_account_key, vote, _) = vote_parser::parse_vote_transaction(&tx)?;
|
||||
let (vote_account_key, vote, ..) = vote_parser::parse_vote_transaction(&tx)?;
|
||||
let slot = vote.last_voted_slot()?;
|
||||
let epoch = epoch_schedule.get_epoch(slot);
|
||||
let authorized_voter = root_bank
|
||||
|
@ -570,6 +570,7 @@ impl ClusterInfoVoteListener {
|
|||
fn track_new_votes_and_notify_confirmations(
|
||||
vote: VoteTransaction,
|
||||
vote_pubkey: &Pubkey,
|
||||
vote_transaction_signature: Signature,
|
||||
vote_tracker: &VoteTracker,
|
||||
root_bank: &Bank,
|
||||
subscriptions: &RpcSubscriptions,
|
||||
|
@ -678,7 +679,7 @@ impl ClusterInfoVoteListener {
|
|||
}
|
||||
|
||||
if is_new_vote {
|
||||
subscriptions.notify_vote(*vote_pubkey, vote);
|
||||
subscriptions.notify_vote(*vote_pubkey, vote, vote_transaction_signature);
|
||||
let _ = verified_vote_sender.send((*vote_pubkey, vote_slots));
|
||||
}
|
||||
}
|
||||
|
@ -703,10 +704,11 @@ impl ClusterInfoVoteListener {
|
|||
.filter_map(vote_parser::parse_vote_transaction)
|
||||
.zip(repeat(/*is_gossip:*/ true))
|
||||
.chain(replayed_votes.into_iter().zip(repeat(/*is_gossip:*/ false)));
|
||||
for ((vote_pubkey, vote, _), is_gossip) in votes {
|
||||
for ((vote_pubkey, vote, _switch_proof, signature), is_gossip) in votes {
|
||||
Self::track_new_votes_and_notify_confirmations(
|
||||
vote,
|
||||
&vote_pubkey,
|
||||
signature,
|
||||
vote_tracker,
|
||||
root_bank,
|
||||
subscriptions,
|
||||
|
@ -1018,6 +1020,7 @@ mod tests {
|
|||
vote_keypair.pubkey(),
|
||||
VoteTransaction::from(replay_vote.clone()),
|
||||
switch_proof_hash,
|
||||
Signature::default(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
@ -1306,6 +1309,7 @@ mod tests {
|
|||
vote_keypair.pubkey(),
|
||||
VoteTransaction::from(Vote::new(vec![vote_slot], Hash::default())),
|
||||
switch_proof_hash,
|
||||
Signature::default(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
@ -1401,6 +1405,7 @@ mod tests {
|
|||
validator0_keypairs.vote_keypair.pubkey(),
|
||||
VoteTransaction::from(Vote::new(vec![voted_slot], Hash::default())),
|
||||
None,
|
||||
Signature::default(),
|
||||
)],
|
||||
&bank,
|
||||
&subscriptions,
|
||||
|
@ -1446,6 +1451,7 @@ mod tests {
|
|||
validator_keypairs[1].vote_keypair.pubkey(),
|
||||
VoteTransaction::from(Vote::new(vec![first_slot_in_new_epoch], Hash::default())),
|
||||
None,
|
||||
Signature::default(),
|
||||
)],
|
||||
&new_root_bank,
|
||||
&subscriptions,
|
||||
|
|
|
@ -4573,6 +4573,7 @@ The notification will be an object with the following fields:
|
|||
- `hash: <string>` - The vote hash
|
||||
- `slots: <array>` - The slots covered by the vote, as an array of u64 integers
|
||||
- `timestamp: <i64 | null>` - The timestamp of the vote
|
||||
- `signature: <string>` - The signature of the transaction that contained this vote
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
|
@ -1037,7 +1037,7 @@ impl ClusterInfo {
|
|||
};
|
||||
let vote_index = vote_index.unwrap_or(num_crds_votes);
|
||||
if (vote_index as usize) >= MAX_LOCKOUT_HISTORY {
|
||||
let (_, vote, hash) = vote_parser::parse_vote_transaction(&vote).unwrap();
|
||||
let (_, vote, hash, _) = vote_parser::parse_vote_transaction(&vote).unwrap();
|
||||
panic!(
|
||||
"invalid vote index: {}, switch: {}, vote slots: {:?}, tower: {:?}",
|
||||
vote_index,
|
||||
|
|
|
@ -307,7 +307,7 @@ impl Sanitize for Vote {
|
|||
impl Vote {
|
||||
// Returns None if cannot parse transaction into a vote.
|
||||
pub fn new(from: Pubkey, transaction: Transaction, wallclock: u64) -> Option<Self> {
|
||||
vote_parser::parse_vote_transaction(&transaction).map(|(_, vote, _)| Self {
|
||||
vote_parser::parse_vote_transaction(&transaction).map(|(_, vote, ..)| Self {
|
||||
from,
|
||||
transaction,
|
||||
wallclock,
|
||||
|
|
|
@ -3585,7 +3585,7 @@ pub mod tests {
|
|||
process_entries_for_tests(&bank1, vec![entry], true, None, Some(&replay_vote_sender));
|
||||
let successes: BTreeSet<Pubkey> = replay_vote_receiver
|
||||
.try_iter()
|
||||
.map(|(vote_pubkey, _, _)| vote_pubkey)
|
||||
.map(|(vote_pubkey, ..)| vote_pubkey)
|
||||
.collect();
|
||||
assert_eq!(successes, expected_successful_voter_pubkeys);
|
||||
}
|
||||
|
|
|
@ -490,7 +490,7 @@ fn test_duplicate_shreds_broadcast_leader() {
|
|||
// Filter out votes not from the bad leader
|
||||
if label.pubkey() == bad_leader_id {
|
||||
let vote = vote_parser::parse_vote_transaction(&leader_vote_tx)
|
||||
.map(|(_, vote, _)| vote)
|
||||
.map(|(_, vote, ..)| vote)
|
||||
.unwrap();
|
||||
// Filter out empty votes
|
||||
if !vote.is_empty() {
|
||||
|
|
|
@ -1340,12 +1340,16 @@ mod tests {
|
|||
hash: Hash::default(),
|
||||
timestamp: None,
|
||||
};
|
||||
subscriptions.notify_vote(Pubkey::default(), VoteTransaction::from(vote));
|
||||
subscriptions.notify_vote(
|
||||
Pubkey::default(),
|
||||
VoteTransaction::from(vote),
|
||||
Signature::default(),
|
||||
);
|
||||
|
||||
let response = receiver.recv();
|
||||
assert_eq!(
|
||||
response,
|
||||
r#"{"jsonrpc":"2.0","method":"voteNotification","params":{"result":{"votePubkey":"11111111111111111111111111111111","slots":[1,2],"hash":"11111111111111111111111111111111","timestamp":null},"subscription":0}}"#
|
||||
r#"{"jsonrpc":"2.0","method":"voteNotification","params":{"result":{"votePubkey":"11111111111111111111111111111111","slots":[1,2],"hash":"11111111111111111111111111111111","timestamp":null,"signature":"1111111111111111111111111111111111111111111111111111111111111111"},"subscription":0}}"#
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ impl From<NotificationEntry> for TimestampedNotificationEntry {
|
|||
pub enum NotificationEntry {
|
||||
Slot(SlotInfo),
|
||||
SlotUpdate(SlotUpdate),
|
||||
Vote((Pubkey, VoteTransaction)),
|
||||
Vote((Pubkey, VoteTransaction, Signature)),
|
||||
Root(Slot),
|
||||
Bank(CommitmentSlots),
|
||||
Gossip(Slot),
|
||||
|
@ -728,8 +728,8 @@ impl RpcSubscriptions {
|
|||
self.enqueue_notification(NotificationEntry::SignaturesReceived(slot_signatures));
|
||||
}
|
||||
|
||||
pub fn notify_vote(&self, vote_pubkey: Pubkey, vote: VoteTransaction) {
|
||||
self.enqueue_notification(NotificationEntry::Vote((vote_pubkey, vote)));
|
||||
pub fn notify_vote(&self, vote_pubkey: Pubkey, vote: VoteTransaction, signature: Signature) {
|
||||
self.enqueue_notification(NotificationEntry::Vote((vote_pubkey, vote, signature)));
|
||||
}
|
||||
|
||||
pub fn notify_roots(&self, mut rooted_slots: Vec<Slot>) {
|
||||
|
@ -814,7 +814,7 @@ impl RpcSubscriptions {
|
|||
// These notifications are only triggered by votes observed on gossip,
|
||||
// unlike `NotificationEntry::Gossip`, which also accounts for slots seen
|
||||
// in VoteState's from bank states built in ReplayStage.
|
||||
NotificationEntry::Vote((vote_pubkey, ref vote_info)) => {
|
||||
NotificationEntry::Vote((vote_pubkey, ref vote_info, signature)) => {
|
||||
if let Some(sub) = subscriptions
|
||||
.node_progress_watchers()
|
||||
.get(&SubscriptionParams::Vote)
|
||||
|
@ -824,6 +824,7 @@ impl RpcSubscriptions {
|
|||
slots: vote_info.slots(),
|
||||
hash: bs58::encode(vote_info.hash()).into_string(),
|
||||
timestamp: vote_info.timestamp(),
|
||||
signature: signature.to_string(),
|
||||
};
|
||||
debug!("vote notify: {:?}", vote_info);
|
||||
inc_new_counter_info!("rpc-subscription-notify-vote", 1);
|
||||
|
|
|
@ -4,12 +4,13 @@ use {
|
|||
hash::Hash,
|
||||
program_utils::limited_deserialize,
|
||||
pubkey::Pubkey,
|
||||
signature::Signature,
|
||||
transaction::{SanitizedTransaction, Transaction},
|
||||
},
|
||||
solana_vote_program::vote_instruction::VoteInstruction,
|
||||
};
|
||||
|
||||
pub type ParsedVote = (Pubkey, VoteTransaction, Option<Hash>);
|
||||
pub type ParsedVote = (Pubkey, VoteTransaction, Option<Hash>, Signature);
|
||||
|
||||
// Used for filtering out votes from the transaction log collector
|
||||
pub(crate) fn is_simple_vote_transaction(transaction: &SanitizedTransaction) -> bool {
|
||||
|
@ -46,7 +47,8 @@ pub fn parse_sanitized_vote_transaction(tx: &SanitizedTransaction) -> Option<Par
|
|||
let first_account = usize::from(*first_instruction.accounts.first()?);
|
||||
let key = message.account_keys().get(first_account)?;
|
||||
let (vote, switch_proof_hash) = parse_vote_instruction_data(&first_instruction.data)?;
|
||||
Some((*key, vote, switch_proof_hash))
|
||||
let signature = tx.signatures().get(0).cloned().unwrap_or_default();
|
||||
Some((*key, vote, switch_proof_hash, signature))
|
||||
}
|
||||
|
||||
// Used for parsing gossip vote transactions
|
||||
|
@ -62,7 +64,8 @@ pub fn parse_vote_transaction(tx: &Transaction) -> Option<ParsedVote> {
|
|||
let first_account = usize::from(*first_instruction.accounts.first()?);
|
||||
let key = message.account_keys.get(first_account)?;
|
||||
let (vote, switch_proof_hash) = parse_vote_instruction_data(&first_instruction.data)?;
|
||||
Some((*key, vote, switch_proof_hash))
|
||||
let signature = tx.signatures.get(0).cloned().unwrap_or_default();
|
||||
Some((*key, vote, switch_proof_hash, signature))
|
||||
}
|
||||
|
||||
fn parse_vote_instruction_data(
|
||||
|
@ -113,10 +116,11 @@ mod test {
|
|||
&auth_voter_keypair,
|
||||
input_hash,
|
||||
);
|
||||
let (key, vote, hash) = parse_vote_transaction(&vote_tx).unwrap();
|
||||
let (key, vote, hash, signature) = parse_vote_transaction(&vote_tx).unwrap();
|
||||
assert_eq!(hash, input_hash);
|
||||
assert_eq!(vote, VoteTransaction::from(Vote::new(vec![42], bank_hash)));
|
||||
assert_eq!(key, vote_keypair.pubkey());
|
||||
assert_eq!(signature, vote_tx.signatures[0]);
|
||||
|
||||
// Test bad program id fails
|
||||
let mut vote_ix = vote_instruction::vote(
|
||||
|
|
Loading…
Reference in New Issue