From 9d6c921b5f73351702ba492cb3dee60d6e2db72f Mon Sep 17 00:00:00 2001 From: Tao Zhu <82401714+taozhu-chicago@users.noreply.github.com> Date: Thu, 25 May 2023 15:45:15 -0500 Subject: [PATCH] check simple vote could have 1 or 2 signatures when creating sanitized transaction (#31807) * check simple vote could have 1 or 2 signatures when creating sanitized transaction --- perf/src/sigverify.rs | 15 ++++++ sdk/src/transaction/sanitized.rs | 84 +++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/perf/src/sigverify.rs b/perf/src/sigverify.rs index d17f97e037..b7f04f7b9e 100644 --- a/perf/src/sigverify.rs +++ b/perf/src/sigverify.rs @@ -1410,6 +1410,21 @@ mod tests { check_for_simple_vote_transaction(&mut packet, &packet_offsets, 0).ok(); assert!(!packet.meta().is_simple_vote_tx()); } + + // single legacy vote tx with extra (invalid) signature is not + { + let mut tx = new_test_vote_tx(&mut rng); + tx.signatures.push(Signature::default()); + tx.message.header.num_required_signatures = 3; + tx.message.instructions[0].data = vec![1, 2, 3]; + let mut packet = Packet::from_data(None, tx).unwrap(); + let packet_offsets = do_get_packet_offsets(&packet, 0).unwrap(); + assert_eq!( + Err(PacketError::InvalidSignatureLen), + check_for_simple_vote_transaction(&mut packet, &packet_offsets, 0) + ); + assert!(!packet.meta().is_simple_vote_tx()); + } } #[test] diff --git a/sdk/src/transaction/sanitized.rs b/sdk/src/transaction/sanitized.rs index 0064007790..6f598eed0e 100644 --- a/sdk/src/transaction/sanitized.rs +++ b/sdk/src/transaction/sanitized.rs @@ -117,7 +117,10 @@ impl SanitizedTransaction { }; let is_simple_vote_tx = is_simple_vote_tx.unwrap_or_else(|| { - if message.instructions().len() == 1 && matches!(message, SanitizedMessage::Legacy(_)) { + if signatures.len() < 3 + && message.instructions().len() == 1 + && matches!(message, SanitizedMessage::Legacy(_)) + { let mut ix_iter = message.program_instructions_iter(); ix_iter.next().map(|(program_id, _ix)| program_id) == Some(&crate::vote::program::id()) @@ -294,3 +297,82 @@ impl SanitizedTransaction { } } } + +#[cfg(test)] +#[allow(clippy::integer_arithmetic)] +mod tests { + use { + super::*, + crate::signer::{keypair::Keypair, Signer}, + solana_program::vote::{self, state::Vote}, + }; + + #[test] + fn test_try_create_simple_vote_tx() { + let bank_hash = Hash::default(); + let block_hash = Hash::default(); + let vote_keypair = Keypair::new(); + let node_keypair = Keypair::new(); + let auth_keypair = Keypair::new(); + let votes = Vote::new(vec![1, 2, 3], bank_hash); + let vote_ix = + vote::instruction::vote(&vote_keypair.pubkey(), &auth_keypair.pubkey(), votes); + let mut vote_tx = Transaction::new_with_payer(&[vote_ix], Some(&node_keypair.pubkey())); + vote_tx.partial_sign(&[&node_keypair], block_hash); + vote_tx.partial_sign(&[&auth_keypair], block_hash); + + // single legacy vote ix, 2 signatures + { + let vote_transaction = SanitizedTransaction::try_create( + VersionedTransaction::from(vote_tx.clone()), + MessageHash::Compute, + None, + SimpleAddressLoader::Disabled, + true, // require_static_program_ids + ) + .unwrap(); + assert!(vote_transaction.is_simple_vote_transaction()); + } + + { + // call side says it is not a vote + let vote_transaction = SanitizedTransaction::try_create( + VersionedTransaction::from(vote_tx.clone()), + MessageHash::Compute, + Some(false), + SimpleAddressLoader::Disabled, + true, // require_static_program_ids + ) + .unwrap(); + assert!(!vote_transaction.is_simple_vote_transaction()); + } + + // single legacy vote ix, 3 signatures + vote_tx.signatures.push(Signature::default()); + vote_tx.message.header.num_required_signatures = 3; + { + let vote_transaction = SanitizedTransaction::try_create( + VersionedTransaction::from(vote_tx.clone()), + MessageHash::Compute, + None, + SimpleAddressLoader::Disabled, + true, // require_static_program_ids + ) + .unwrap(); + assert!(!vote_transaction.is_simple_vote_transaction()); + } + + { + // call site says it is simple vote + let vote_transaction = SanitizedTransaction::try_create( + VersionedTransaction::from(vote_tx), + MessageHash::Compute, + Some(true), + SimpleAddressLoader::Disabled, + true, // require_static_program_ids + ) + .unwrap(); + assert!(vote_transaction.is_simple_vote_transaction()); + } + } +}