Skip to content

Commit

Permalink
Relax keypair ordering restriction for VersionedTransaction::try_new (
Browse files Browse the repository at this point in the history
solana-labs#27397)

* Relax keypair ordering restriction for VersionedTransaction::try_new

* feedback
  • Loading branch information
jstarry authored Aug 26, 2022
1 parent a19b5c1 commit 56cebf9
Showing 1 changed file with 80 additions and 6 deletions.
86 changes: 80 additions & 6 deletions sdk/src/transaction/versioned/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl VersionedTransaction {
return Err(SignerError::InvalidInput("invalid message".to_string()));
}

let signer_keys = keypairs.pubkeys();
let signer_keys = keypairs.try_pubkeys()?;
let expected_signer_keys =
&static_account_keys[0..message.header().num_required_signatures as usize];

Expand All @@ -81,12 +81,27 @@ impl VersionedTransaction {
Ordering::Equal => Ok(()),
}?;

if signer_keys != expected_signer_keys {
return Err(SignerError::KeypairPubkeyMismatch);
}

let message_data = message.serialize();
let signatures = keypairs.try_sign_message(&message_data)?;
let signature_indexes: Vec<usize> = expected_signer_keys
.iter()
.map(|signer_key| {
signer_keys
.iter()
.position(|key| key == signer_key)
.ok_or(SignerError::KeypairPubkeyMismatch)
})
.collect::<std::result::Result<_, SignerError>>()?;

let unordered_signatures = keypairs.try_sign_message(&message_data)?;
let signatures: Vec<Signature> = signature_indexes
.into_iter()
.map(|index| {
unordered_signatures
.get(index)
.copied()
.ok_or_else(|| SignerError::InvalidInput("invalid keypairs".to_string()))
})
.collect::<std::result::Result<_, SignerError>>()?;

Ok(Self {
signatures,
Expand Down Expand Up @@ -167,3 +182,62 @@ impl VersionedTransaction {
.collect()
}
}

#[cfg(test)]
mod tests {
use {
super::*,
crate::{
message::Message as LegacyMessage,
signer::{keypair::Keypair, Signer},
},
solana_program::{
instruction::{AccountMeta, Instruction},
pubkey::Pubkey,
},
};

#[test]
fn test_try_new() {
let keypair0 = Keypair::new();
let keypair1 = Keypair::new();
let keypair2 = Keypair::new();

let message = VersionedMessage::Legacy(LegacyMessage::new(
&[Instruction::new_with_bytes(
Pubkey::new_unique(),
&[],
vec![
AccountMeta::new_readonly(keypair1.pubkey(), true),
AccountMeta::new_readonly(keypair2.pubkey(), false),
],
)],
Some(&keypair0.pubkey()),
));

assert_eq!(
VersionedTransaction::try_new(message.clone(), &[&keypair0]),
Err(SignerError::NotEnoughSigners)
);

assert_eq!(
VersionedTransaction::try_new(message.clone(), &[&keypair0, &keypair0]),
Err(SignerError::KeypairPubkeyMismatch)
);

assert_eq!(
VersionedTransaction::try_new(message.clone(), &[&keypair1, &keypair2]),
Err(SignerError::KeypairPubkeyMismatch)
);

match VersionedTransaction::try_new(message.clone(), &[&keypair0, &keypair1]) {
Ok(tx) => assert_eq!(tx.verify_with_results(), vec![true; 2]),
Err(err) => assert_eq!(Some(err), None),
}

match VersionedTransaction::try_new(message, &[&keypair1, &keypair0]) {
Ok(tx) => assert_eq!(tx.verify_with_results(), vec![true; 2]),
Err(err) => assert_eq!(Some(err), None),
}
}
}

0 comments on commit 56cebf9

Please sign in to comment.