From 0e3dd8d9ab5e7d6b610b25d1d7a805ad432b5f8c Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Mon, 29 Jan 2024 14:14:46 +0000 Subject: [PATCH 01/15] Checkpoint --- pythnet/pythnet_sdk/src/test_utils/mod.rs | 45 +++++------------------ 1 file changed, 9 insertions(+), 36 deletions(-) diff --git a/pythnet/pythnet_sdk/src/test_utils/mod.rs b/pythnet/pythnet_sdk/src/test_utils/mod.rs index bdd3383894..df1d75cacb 100644 --- a/pythnet/pythnet_sdk/src/test_utils/mod.rs +++ b/pythnet/pythnet_sdk/src/test_utils/mod.rs @@ -37,8 +37,6 @@ use { wormhole_sdk::{ vaa::{ Body, - Header, - }, Address, Chain, Vaa, @@ -181,17 +179,8 @@ pub fn create_vaa_from_payload( emitter_chain: Chain, sequence: u64, ) -> Vaa> { - let guardians = dummy_guardians(); - - let body: Body> = Body { - emitter_chain, - emitter_address, - sequence, - payload: >::from(payload.to_vec()), - ..Default::default() - }; - - let digest = libsecp256k1Message::parse_slice(&body.digest().unwrap().secp256k_hash).unwrap(); + let digest = libsecp256k1Message::parse_slice(&digest(payload).unwrap().secp256k_hash).unwrap(); + let guardians = create_dummy_guardians(); let signatures: Vec<(Signature, RecoveryId)> = guardians .iter() @@ -211,30 +200,14 @@ pub fn create_vaa_from_payload( }) .collect(); - let mut wormhole_signatures_subset: Vec = wormhole_signatures - .choose_multiple(&mut thread_rng(), DEFAULT_NUM_SIGNATURES) - .cloned() - .collect(); - - wormhole_signatures_subset.sort_by(|a, b| a.index.cmp(&b.index)); - - let header = Header { - version: 1, - signatures: wormhole_signatures_subset, + let vaa: Vaa> = Vaa { + emitter_chain: emitter_chain, + emitter_address: emitter_address, + sequence, + payload: >::from(payload.to_vec()), + signatures: wormhole_signatures, ..Default::default() }; - - (header, body).into() -} - -pub fn trim_vaa_signatures(vaa: Vaa<&RawMessage>, n: u8) -> Vaa<&RawMessage> { - let mut vaa_copy = vaa.clone(); - vaa_copy.signatures = vaa - .signatures - .choose_multiple(&mut thread_rng(), n.into()) - .cloned() - .collect(); - vaa_copy.signatures.sort_by(|a, b| a.index.cmp(&b.index)); - vaa_copy + vaa } From 31143adec7ce412a40b97e4680a90bbd9a02911b Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Mon, 29 Jan 2024 14:21:23 +0000 Subject: [PATCH 02/15] Checkpoint --- pythnet/pythnet_sdk/src/test_utils/mod.rs | 2 +- target_chains/solana/cli/src/main.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pythnet/pythnet_sdk/src/test_utils/mod.rs b/pythnet/pythnet_sdk/src/test_utils/mod.rs index df1d75cacb..75d4ae0ed5 100644 --- a/pythnet/pythnet_sdk/src/test_utils/mod.rs +++ b/pythnet/pythnet_sdk/src/test_utils/mod.rs @@ -182,7 +182,7 @@ pub fn create_vaa_from_payload( let digest = libsecp256k1Message::parse_slice(&digest(payload).unwrap().secp256k_hash).unwrap(); let guardians = create_dummy_guardians(); - let signatures: Vec<(Signature, RecoveryId)> = guardians + let signatures: Vec<(Signature, RecoveryId)> = guardians[0..NUM_SIGNATURES] .iter() .map(|x| libsecp256k1::sign(&digest, &x)) .collect(); diff --git a/target_chains/solana/cli/src/main.rs b/target_chains/solana/cli/src/main.rs index bed6f2cc67..3c4863de78 100644 --- a/target_chains/solana/cli/src/main.rs +++ b/target_chains/solana/cli/src/main.rs @@ -280,6 +280,7 @@ pub fn process_post_price_update_atomic( } fn trim_signatures(header: &mut Header, n_signatures: usize) { + println!("There are {} signatures", header.signatures.len()); header.signatures = header.signatures[..(n_signatures)].to_vec(); } From 299dbc09bddaa4b77d6c10e102cd2d743c4e97b1 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Mon, 29 Jan 2024 16:14:19 +0000 Subject: [PATCH 03/15] Cleanup --- .../programs/pyth-solana-receiver/tests/test_post_updates.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs index fd22e4773c..071e9cb3d7 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs @@ -50,7 +50,7 @@ async fn test_post_updates() { poster.pubkey(), encoded_vaa_addresses[0], price_update_keypair.pubkey(), - merkle_price_updates[0].clone(), + accumulator_update_data.1[0].clone(), ), &vec![&poster, &price_update_keypair], None, @@ -81,7 +81,7 @@ async fn test_post_updates() { poster.pubkey(), encoded_vaa_addresses[0], price_update_keypair.pubkey(), - merkle_price_updates[1].clone(), + accumulator_update_data.1[1].clone(), ), &vec![&poster, &price_update_keypair], None, From 71356ceceb081ba6573510e8d88aa050aef744e5 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Mon, 29 Jan 2024 17:04:08 +0000 Subject: [PATCH 04/15] Checkpoint, debug --- pythnet/pythnet_sdk/src/test_utils/mod.rs | 5 +++-- target_chains/solana/cli/src/main.rs | 1 - .../programs/pyth-solana-receiver/tests/common/mod.rs | 6 ++++++ .../pyth-solana-receiver/tests/test_post_updates.rs | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pythnet/pythnet_sdk/src/test_utils/mod.rs b/pythnet/pythnet_sdk/src/test_utils/mod.rs index 75d4ae0ed5..5a48434092 100644 --- a/pythnet/pythnet_sdk/src/test_utils/mod.rs +++ b/pythnet/pythnet_sdk/src/test_utils/mod.rs @@ -201,8 +201,9 @@ pub fn create_vaa_from_payload( .collect(); let vaa: Vaa> = Vaa { - emitter_chain: emitter_chain, - emitter_address: emitter_address, + version: 1, + emitter_chain, + emitter_address, sequence, payload: >::from(payload.to_vec()), signatures: wormhole_signatures, diff --git a/target_chains/solana/cli/src/main.rs b/target_chains/solana/cli/src/main.rs index 3c4863de78..bed6f2cc67 100644 --- a/target_chains/solana/cli/src/main.rs +++ b/target_chains/solana/cli/src/main.rs @@ -280,7 +280,6 @@ pub fn process_post_price_update_atomic( } fn trim_signatures(header: &mut Header, n_signatures: usize) { - println!("There are {} signatures", header.signatures.len()); header.signatures = header.signatures[..(n_signatures)].to_vec(); } diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs index 631158c812..e8854a2ddd 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs @@ -170,3 +170,9 @@ pub async fn setup_pyth_receiver(vaas: Vec>) -> ProgramTestFixt encoded_vaa_addresses, } } + +pub fn trim_vaa_signatures(vaa: Vec, n: u8) -> Vec { + let mut parsed_vaa: Vaa<&RawMessage> = serde_wormhole::from_slice(vaa.as_slice()).unwrap(); + parsed_vaa.signatures = parsed_vaa.signatures[0..n as usize].to_vec(); + serde_wormhole::to_vec(&parsed_vaa).unwrap() +} diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs index 071e9cb3d7..fd22e4773c 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs @@ -50,7 +50,7 @@ async fn test_post_updates() { poster.pubkey(), encoded_vaa_addresses[0], price_update_keypair.pubkey(), - accumulator_update_data.1[0].clone(), + merkle_price_updates[0].clone(), ), &vec![&poster, &price_update_keypair], None, @@ -81,7 +81,7 @@ async fn test_post_updates() { poster.pubkey(), encoded_vaa_addresses[0], price_update_keypair.pubkey(), - accumulator_update_data.1[1].clone(), + merkle_price_updates[1].clone(), ), &vec![&poster, &price_update_keypair], None, From 422c2dbb5313a05aaf9e1d84eebdb6893e907a27 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Mon, 29 Jan 2024 17:47:32 +0000 Subject: [PATCH 05/15] Go --- pythnet/pythnet_sdk/src/test_utils/mod.rs | 22 +++++++++++++------ .../tests/test_post_updates_atomic.rs | 15 +++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/pythnet/pythnet_sdk/src/test_utils/mod.rs b/pythnet/pythnet_sdk/src/test_utils/mod.rs index 5a48434092..5098d3e525 100644 --- a/pythnet/pythnet_sdk/src/test_utils/mod.rs +++ b/pythnet/pythnet_sdk/src/test_utils/mod.rs @@ -37,6 +37,7 @@ use { wormhole_sdk::{ vaa::{ Body, + }, Address, Chain, Vaa, @@ -179,9 +180,18 @@ pub fn create_vaa_from_payload( emitter_chain: Chain, sequence: u64, ) -> Vaa> { - let digest = libsecp256k1Message::parse_slice(&digest(payload).unwrap().secp256k_hash).unwrap(); let guardians = create_dummy_guardians(); + let body: Body> = Body { + emitter_chain, + emitter_address, + sequence, + payload: >::from(payload.to_vec()), + ..Default::default() + }; + + let digest = libsecp256k1Message::parse_slice(&body.digest().unwrap().secp256k_hash).unwrap(); + let signatures: Vec<(Signature, RecoveryId)> = guardians[0..NUM_SIGNATURES] .iter() .map(|x| libsecp256k1::sign(&digest, &x)) @@ -200,15 +210,13 @@ pub fn create_vaa_from_payload( }) .collect(); - let vaa: Vaa> = Vaa { + + let header = Header { version: 1, - emitter_chain, - emitter_address, - sequence, - payload: >::from(payload.to_vec()), signatures: wormhole_signatures, ..Default::default() }; - vaa + + (header, body).into() } diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs index 972692ffe4..881bfcd32c 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs @@ -1,5 +1,12 @@ use { +<<<<<<< HEAD crate::common::DEFAULT_GUARDIAN_SET_INDEX, +======= + crate::common::{ + trim_vaa_signatures, + DEFAULT_GUARDIAN_SET_INDEX, + }, +>>>>>>> c6431163 (Go) common::{ setup_pyth_receiver, ProgramTestFixtures, @@ -17,7 +24,10 @@ use { test_utils::{ create_accumulator_message, create_dummy_price_feed_message, +<<<<<<< HEAD trim_vaa_signatures, +======= +>>>>>>> c6431163 (Go) }, }, solana_sdk::{ @@ -36,11 +46,16 @@ async fn test_post_updates_atomic() { let feed_2 = create_dummy_price_feed_message(200); let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], false); let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap(); +<<<<<<< HEAD let vaa = serde_wormhole::to_vec(&trim_vaa_signatures( serde_wormhole::from_slice(&vaa).unwrap(), 5, )) .unwrap(); +======= + + let vaa = trim_vaa_signatures(vaa, 5); +>>>>>>> c6431163 (Go) let ProgramTestFixtures { mut program_simulator, From 8e810fc9832eb6c4c0a58e1ef279b3ef36ab9c23 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Mon, 29 Jan 2024 19:26:17 +0000 Subject: [PATCH 06/15] Checkpoint --- target_chains/solana/Cargo.lock | 1 + .../solana/program_simulator/Cargo.toml | 1 + .../solana/program_simulator/src/lib.rs | 27 ++- .../pyth-solana-receiver/src/error.rs | 2 + .../programs/pyth-solana-receiver/src/lib.rs | 4 +- .../tests/test_post_updates_atomic.rs | 186 +++++++++++++++++- 6 files changed, 214 insertions(+), 7 deletions(-) diff --git a/target_chains/solana/Cargo.lock b/target_chains/solana/Cargo.lock index 402f6f20c2..3ce3971cd7 100644 --- a/target_chains/solana/Cargo.lock +++ b/target_chains/solana/Cargo.lock @@ -2981,6 +2981,7 @@ dependencies = [ name = "program-simulator" version = "0.1.0" dependencies = [ + "anchor-lang", "bincode", "borsh 0.10.3", "solana-client", diff --git a/target_chains/solana/program_simulator/Cargo.toml b/target_chains/solana/program_simulator/Cargo.toml index 58c10329fa..44d0832e4e 100644 --- a/target_chains/solana/program_simulator/Cargo.toml +++ b/target_chains/solana/program_simulator/Cargo.toml @@ -15,3 +15,4 @@ solana-program-test = "1.16.20" solana-program = "1.16.20" bincode = "1.3.3" borsh = "0.10.3" +anchor-lang = "0.28.0" diff --git a/target_chains/solana/program_simulator/src/lib.rs b/target_chains/solana/program_simulator/src/lib.rs index e0594dff3e..ac47390cea 100644 --- a/target_chains/solana/program_simulator/src/lib.rs +++ b/target_chains/solana/program_simulator/src/lib.rs @@ -2,8 +2,12 @@ use { borsh::BorshDeserialize, solana_program::{ hash::Hash, - instruction::Instruction, + instruction::{ + Instruction, + InstructionError, + }, native_token::LAMPORTS_PER_SOL, + program_error::ProgramError, pubkey::Pubkey, system_instruction, }, @@ -14,11 +18,15 @@ use { ProgramTestBanksClientExt, }, solana_sdk::{ + compute_budget, signature::{ Keypair, Signer, }, - transaction::Transaction, + transaction::{ + Transaction, + TransactionError, + }, }, }; @@ -49,9 +57,13 @@ impl ProgramSimulator { signers: &Vec<&Keypair>, payer: Option<&Keypair>, ) -> Result<(), BanksClientError> { + let compute_units_ixs = + compute_budget::ComputeBudgetInstruction::set_compute_unit_limit(2000000); let actual_payer = payer.unwrap_or(&self.genesis_keypair); - let mut transaction = - Transaction::new_with_payer(&[instruction], Some(&actual_payer.pubkey())); + let mut transaction = Transaction::new_with_payer( + &[instruction, compute_units_ixs], + Some(&actual_payer.pubkey()), + ); let blockhash = self .banks_client @@ -94,3 +106,10 @@ impl ProgramSimulator { Ok(T::deserialize(&mut &account.data[8..])?) } } + +pub fn into_transation_error>(error: T) -> TransactionError { + TransactionError::InstructionError( + 0, + InstructionError::try_from(u64::from(ProgramError::from(error.into()))).unwrap(), + ) +} diff --git a/target_chains/solana/programs/pyth-solana-receiver/src/error.rs b/target_chains/solana/programs/pyth-solana-receiver/src/error.rs index 80b93eed22..220d814a16 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/src/error.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/src/error.rs @@ -43,4 +43,6 @@ pub enum ReceiverError { InvalidSignature, #[msg("The recovered guardian public key doesn't match the guardian set")] InvalidGuardianKeyRecovery, + #[msg("The guardian set account is owned by the wrong program")] + WrongGuardianSetOwner, } diff --git a/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs b/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs index 3f97c263c2..651660cc6f 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs @@ -258,7 +258,7 @@ pub struct AuthorizeGovernanceAuthorityTransfer<'info> { pub struct PostUpdates<'info> { #[account(mut)] pub payer: Signer<'info>, - #[account(owner = config.wormhole)] + #[account(owner = config.wormhole @ ReceiverError::WrongVaaOwner)] /// CHECK: We aren't deserializing the VAA here but later with VaaAccount::load, which is the recommended way pub encoded_vaa: AccountInfo<'info>, #[account(seeds = [CONFIG_SEED.as_ref()], bump)] @@ -281,7 +281,7 @@ pub struct PostUpdatesAtomic<'info> { /// CHECK: We can't use AccountVariant:: here because its owner is hardcoded as the "official" Wormhole program and we want to get the wormhole address from the config. /// Instead we do the same steps in deserialize_guardian_set_checked. #[account( - owner = config.wormhole)] + owner = config.wormhole @ ReceiverError::WrongGuardianSetOwner)] pub guardian_set: AccountInfo<'info>, #[account(seeds = [CONFIG_SEED.as_ref()], bump)] pub config: Account<'info, Config>, diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs index 881bfcd32c..65a93286c8 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs @@ -11,9 +11,14 @@ use { setup_pyth_receiver, ProgramTestFixtures, }, + program_simulator::into_transation_error, pyth_solana_receiver::{ + error::ReceiverError, instruction::PostUpdatesAtomic, - sdk::deserialize_accumulator_update_data, + sdk::{ + deserialize_accumulator_update_data, + get_guardian_set_address, + }, state::price_update::{ PriceUpdateV1, VerificationLevel, @@ -30,11 +35,13 @@ use { >>>>>>> c6431163 (Go) }, }, + serde_wormhole::RawMessage, solana_sdk::{ signature::Keypair, signer::Signer, }, wormhole_core_bridge_solana::ID as BRIDGE_ID, + wormhole_sdk::Vaa, }; mod common; @@ -131,3 +138,180 @@ async fn test_post_updates_atomic() { feed_2 ); } + +#[tokio::test] +async fn test_post_updates_atomic_wrong_vaa() { + let feed_1 = create_dummy_price_feed_message(100); + let feed_2 = create_dummy_price_feed_message(200); + let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], false); + let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap(); + + let ProgramTestFixtures { + mut program_simulator, + encoded_vaa_addresses: _, + } = setup_pyth_receiver(vec![]).await; + + let poster = program_simulator.get_funded_keypair().await.unwrap(); + let price_update_keypair = Keypair::new(); + + let vaa_wrong_num_signatures = trim_vaa_signatures(vaa.clone(), 4); + assert_eq!( + program_simulator + .process_ix( + PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + vaa_wrong_num_signatures.clone(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::InsufficientGuardianSignatures) + ); + + let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); + vaa_copy.version = 0; + + assert_eq!( + program_simulator + .process_ix( + PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + serde_wormhole::to_vec(&vaa_copy).unwrap(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::InvalidVaaVersion) + ); + + let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); + vaa_copy.guardian_set_index = 1; + + assert_eq!( + program_simulator + .process_ix( + PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + serde_wormhole::to_vec(&vaa_copy).unwrap(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::GuardianSetMismatch) + ); + + let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); + vaa_copy.signatures[0].index = 20; + + assert_eq!( + program_simulator + .process_ix( + PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + serde_wormhole::to_vec(&vaa_copy).unwrap(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::InvalidGuardianIndex) + ); + + let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); + vaa_copy.signatures[0].signature[64] = 5; + + assert_eq!( + program_simulator + .process_ix( + PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + serde_wormhole::to_vec(&vaa_copy).unwrap(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::InvalidSignature) + ); + + + let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); + vaa_copy.signatures[0].signature = vaa_copy.signatures[1].signature; + + assert_eq!( + program_simulator + .process_ix( + PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + serde_wormhole::to_vec(&vaa_copy).unwrap(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::InvalidGuardianKeyRecovery) + ); + + let mut wrong_instruction = PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + vaa.clone(), + merkle_price_updates[0].clone(), + ); + + let wrong_guardian_set = get_guardian_set_address(BRIDGE_ID, 1); + wrong_instruction.accounts[1].pubkey = wrong_guardian_set; + assert_eq!( + program_simulator + .process_ix( + wrong_instruction, + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::WrongGuardianSetOwner) + ); +} From 4ba2740183bed849ac47becaf7ef8c1fc95d9075 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Tue, 30 Jan 2024 14:15:17 +0000 Subject: [PATCH 07/15] Fix --- pythnet/pythnet_sdk/src/test_utils/mod.rs | 24 ++++++++++++++++--- .../tests/test_post_updates_atomic.rs | 21 ++++------------ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/pythnet/pythnet_sdk/src/test_utils/mod.rs b/pythnet/pythnet_sdk/src/test_utils/mod.rs index 5098d3e525..bdd3383894 100644 --- a/pythnet/pythnet_sdk/src/test_utils/mod.rs +++ b/pythnet/pythnet_sdk/src/test_utils/mod.rs @@ -37,6 +37,7 @@ use { wormhole_sdk::{ vaa::{ Body, + Header, }, Address, Chain, @@ -180,7 +181,7 @@ pub fn create_vaa_from_payload( emitter_chain: Chain, sequence: u64, ) -> Vaa> { - let guardians = create_dummy_guardians(); + let guardians = dummy_guardians(); let body: Body> = Body { emitter_chain, @@ -192,7 +193,7 @@ pub fn create_vaa_from_payload( let digest = libsecp256k1Message::parse_slice(&body.digest().unwrap().secp256k_hash).unwrap(); - let signatures: Vec<(Signature, RecoveryId)> = guardians[0..NUM_SIGNATURES] + let signatures: Vec<(Signature, RecoveryId)> = guardians .iter() .map(|x| libsecp256k1::sign(&digest, &x)) .collect(); @@ -210,13 +211,30 @@ pub fn create_vaa_from_payload( }) .collect(); + let mut wormhole_signatures_subset: Vec = wormhole_signatures + .choose_multiple(&mut thread_rng(), DEFAULT_NUM_SIGNATURES) + .cloned() + .collect(); + + wormhole_signatures_subset.sort_by(|a, b| a.index.cmp(&b.index)); let header = Header { version: 1, - signatures: wormhole_signatures, + signatures: wormhole_signatures_subset, ..Default::default() }; (header, body).into() } + +pub fn trim_vaa_signatures(vaa: Vaa<&RawMessage>, n: u8) -> Vaa<&RawMessage> { + let mut vaa_copy = vaa.clone(); + vaa_copy.signatures = vaa + .signatures + .choose_multiple(&mut thread_rng(), n.into()) + .cloned() + .collect(); + vaa_copy.signatures.sort_by(|a, b| a.index.cmp(&b.index)); + vaa_copy +} diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs index 65a93286c8..17465fddbf 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs @@ -1,12 +1,5 @@ use { -<<<<<<< HEAD crate::common::DEFAULT_GUARDIAN_SET_INDEX, -======= - crate::common::{ - trim_vaa_signatures, - DEFAULT_GUARDIAN_SET_INDEX, - }, ->>>>>>> c6431163 (Go) common::{ setup_pyth_receiver, ProgramTestFixtures, @@ -29,10 +22,7 @@ use { test_utils::{ create_accumulator_message, create_dummy_price_feed_message, -<<<<<<< HEAD trim_vaa_signatures, -======= ->>>>>>> c6431163 (Go) }, }, serde_wormhole::RawMessage, @@ -53,16 +43,11 @@ async fn test_post_updates_atomic() { let feed_2 = create_dummy_price_feed_message(200); let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], false); let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap(); -<<<<<<< HEAD let vaa = serde_wormhole::to_vec(&trim_vaa_signatures( serde_wormhole::from_slice(&vaa).unwrap(), 5, )) .unwrap(); -======= - - let vaa = trim_vaa_signatures(vaa, 5); ->>>>>>> c6431163 (Go) let ProgramTestFixtures { mut program_simulator, @@ -154,7 +139,11 @@ async fn test_post_updates_atomic_wrong_vaa() { let poster = program_simulator.get_funded_keypair().await.unwrap(); let price_update_keypair = Keypair::new(); - let vaa_wrong_num_signatures = trim_vaa_signatures(vaa.clone(), 4); + let vaa_wrong_num_signatures = serde_wormhole::to_vec(&trim_vaa_signatures( + serde_wormhole::from_slice(&vaa).unwrap(), + 4, + )) + .unwrap(); assert_eq!( program_simulator .process_ix( From 860b4a9edc10997e1148498435db47528570622b Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Tue, 30 Jan 2024 14:19:23 +0000 Subject: [PATCH 08/15] Add new error and test --- .../pyth-solana-receiver/src/error.rs | 2 ++ .../programs/pyth-solana-receiver/src/lib.rs | 2 +- .../tests/test_post_updates_atomic.rs | 24 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/target_chains/solana/programs/pyth-solana-receiver/src/error.rs b/target_chains/solana/programs/pyth-solana-receiver/src/error.rs index 220d814a16..ee40471168 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/src/error.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/src/error.rs @@ -37,6 +37,8 @@ pub enum ReceiverError { InvalidVaaVersion, #[msg("Guardian set version in the VAA doesn't match the guardian set passed")] GuardianSetMismatch, + #[msg("Guardian signature indices must be increasing")] + InvalidGuardianOrder, #[msg("Guardian index exceeds the number of guardians in the set")] InvalidGuardianIndex, #[msg("A VAA signature is invalid")] diff --git a/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs b/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs index 651660cc6f..ebef649782 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs @@ -143,7 +143,7 @@ pub mod pyth_solana_receiver { // We do not allow for non-increasing guardian signature indices. let index = usize::from(sig.guardian_index()); if let Some(last_index) = last_guardian_index { - require!(index > last_index, ReceiverError::InvalidGuardianIndex); + require!(index > last_index, ReceiverError::InvalidGuardianOrder); } // Does this guardian index exist in this guardian set? diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs index 17465fddbf..9d4c3e0afa 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs @@ -210,6 +210,30 @@ async fn test_post_updates_atomic_wrong_vaa() { into_transation_error(ReceiverError::GuardianSetMismatch) ); + let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); + vaa_copy.signatures[0] = vaa_copy.signatures[1]; + + assert_eq!( + program_simulator + .process_ix( + PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + serde_wormhole::to_vec(&vaa_copy).unwrap(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::InvalidGuardianOrder) + ); + + let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); vaa_copy.signatures[0].index = 20; From 6ea2a86b0a730a12e4ed94eebfa0c3e9a64561f2 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Tue, 30 Jan 2024 14:20:18 +0000 Subject: [PATCH 09/15] Cleanup --- .../programs/pyth-solana-receiver/tests/common/mod.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs index e8854a2ddd..631158c812 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs @@ -170,9 +170,3 @@ pub async fn setup_pyth_receiver(vaas: Vec>) -> ProgramTestFixt encoded_vaa_addresses, } } - -pub fn trim_vaa_signatures(vaa: Vec, n: u8) -> Vec { - let mut parsed_vaa: Vaa<&RawMessage> = serde_wormhole::from_slice(vaa.as_slice()).unwrap(); - parsed_vaa.signatures = parsed_vaa.signatures[0..n as usize].to_vec(); - serde_wormhole::to_vec(&parsed_vaa).unwrap() -} From e491fb95ca890b8d7fea888e6e814c358d967987 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Tue, 30 Jan 2024 14:41:34 +0000 Subject: [PATCH 10/15] Add another test --- .../pyth-solana-receiver/src/error.rs | 33 ++++++++--------- .../tests/test_post_updates.rs | 37 +++++++++++++++++++ 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/target_chains/solana/programs/pyth-solana-receiver/src/error.rs b/target_chains/solana/programs/pyth-solana-receiver/src/error.rs index ee40471168..005dd410ff 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/src/error.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/src/error.rs @@ -2,16 +2,9 @@ use anchor_lang::prelude::*; #[error_code] pub enum ReceiverError { + // Pyth payload errors #[msg("The tuple emitter chain, emitter doesn't match one of the valid data sources.")] InvalidDataSource, - #[msg("The posted VAA account has the wrong owner.")] - WrongVaaOwner, - #[msg("The posted VAA has wrong magic number.")] - PostedVaaHeaderWrongMagicNumber, - #[msg("An error occurred when deserializing the VAA.")] - DeserializeVaaFailed, - #[msg("An error occurred when deserializing the updates.")] - DeserializeUpdateFailed, #[msg("An error occurred when deserializing the message")] DeserializeMessageFailed, #[msg("Received an invalid wormhole message")] @@ -20,19 +13,18 @@ pub enum ReceiverError { InvalidPriceUpdate, #[msg("This type of message is not supported currently")] UnsupportedMessageType, - #[msg("The signer is not authorized to perform this governance action")] - GovernanceAuthorityMismatch, - #[msg("The signer is not authorized to accept the governance authority")] - TargetGovernanceAuthorityMismatch, - #[msg("The governance authority needs to request a transfer first")] - NonexistentGovernanceAuthorityTransferRequest, #[msg("Funds are insufficient to pay the receiving fee")] InsufficientFunds, - #[msg("The number of guardian signatures is below the minimum")] - InsufficientGuardianSignatures, + // Wormhole contract encoded vaa error (from post_updates) + #[msg("The posted VAA account has the wrong owner.")] + WrongVaaOwner, + // Wormhole signatures verification errors (from post_updates_atomic) + #[msg("An error occurred when deserializing the VAA.")] + DeserializeVaaFailed, #[msg("The Guardian Set account doesn't match the PDA derivation")] InvalidGuardianSetPda, - // Wormhole errors + #[msg("The number of guardian signatures is below the minimum")] + InsufficientGuardianSignatures, #[msg("Invalid VAA version")] InvalidVaaVersion, #[msg("Guardian set version in the VAA doesn't match the guardian set passed")] @@ -47,4 +39,11 @@ pub enum ReceiverError { InvalidGuardianKeyRecovery, #[msg("The guardian set account is owned by the wrong program")] WrongGuardianSetOwner, + // Governance errors + #[msg("The signer is not authorized to perform this governance action")] + GovernanceAuthorityMismatch, + #[msg("The signer is not authorized to accept the governance authority")] + TargetGovernanceAuthorityMismatch, + #[msg("The governance authority needs to request a transfer first")] + NonexistentGovernanceAuthorityTransferRequest, } diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs index fd22e4773c..c7398626ed 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs @@ -3,7 +3,9 @@ use { setup_pyth_receiver, ProgramTestFixtures, }, + program_simulator::into_transation_error, pyth_solana_receiver::{ + error::ReceiverError, instruction::PostUpdates, sdk::deserialize_accumulator_update_data, state::price_update::{ @@ -18,6 +20,7 @@ use { create_dummy_price_feed_message, }, }, + solana_program::pubkey::Pubkey, solana_sdk::{ signature::Keypair, signer::Signer, @@ -105,3 +108,37 @@ async fn test_post_updates() { feed_2 ); } + +#[tokio::test] +async fn test_post_updates_wrong_vaa() { + let feed_1 = create_dummy_price_feed_message(100); + let feed_2 = create_dummy_price_feed_message(200); + let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], false); + let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap(); + + let ProgramTestFixtures { + mut program_simulator, + encoded_vaa_addresses: _, + } = setup_pyth_receiver(vec![serde_wormhole::from_slice(&vaa).unwrap()]).await; + + let poster = program_simulator.get_funded_keypair().await.unwrap(); + let price_update_keypair = Keypair::new(); + + assert_eq!( + program_simulator + .process_ix( + PostUpdates::populate( + poster.pubkey(), + Pubkey::new_unique(), + price_update_keypair.pubkey(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::WrongVaaOwner) + ); +} From b3510b02dc8b3e580a7ba727a074f899a023e5ec Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Tue, 30 Jan 2024 15:06:32 +0000 Subject: [PATCH 11/15] Keep adding errors --- .../pyth-solana-receiver/src/error.rs | 6 +- .../programs/pyth-solana-receiver/src/lib.rs | 6 ++ .../pyth-solana-receiver/tests/common/mod.rs | 54 +++++++++++--- .../tests/test_post_updates.rs | 53 +++++++++++++- .../tests/test_post_updates_atomic.rs | 70 ++++++++++++++++++- 5 files changed, 173 insertions(+), 16 deletions(-) diff --git a/target_chains/solana/programs/pyth-solana-receiver/src/error.rs b/target_chains/solana/programs/pyth-solana-receiver/src/error.rs index 005dd410ff..ff8b5fa036 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/src/error.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/src/error.rs @@ -21,8 +21,6 @@ pub enum ReceiverError { // Wormhole signatures verification errors (from post_updates_atomic) #[msg("An error occurred when deserializing the VAA.")] DeserializeVaaFailed, - #[msg("The Guardian Set account doesn't match the PDA derivation")] - InvalidGuardianSetPda, #[msg("The number of guardian signatures is below the minimum")] InsufficientGuardianSignatures, #[msg("Invalid VAA version")] @@ -39,6 +37,10 @@ pub enum ReceiverError { InvalidGuardianKeyRecovery, #[msg("The guardian set account is owned by the wrong program")] WrongGuardianSetOwner, + #[msg("The Guardian Set account doesn't match the PDA derivation")] + InvalidGuardianSetPda, + #[msg("The Guardian Set is expired")] + GuardianSetExpired, // Governance errors #[msg("The signer is not authorized to perform this governance action")] GovernanceAuthorityMismatch, diff --git a/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs b/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs index ebef649782..5e030ac7d7 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/src/lib.rs @@ -324,6 +324,12 @@ fn deserialize_guardian_set_checked( ReceiverError::InvalidGuardianSetPda ); + let timestamp = Clock::get().map(Into::into)?; + require!( + guardian_set.inner().is_active(×tamp), + ReceiverError::GuardianSetExpired + ); + Ok(guardian_set) } diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs index 631158c812..3bff972b8d 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs @@ -44,6 +44,7 @@ use { }; pub const DEFAULT_GUARDIAN_SET_INDEX: u32 = 0; +pub const WRONG_GUARDIAN_SET_INDEX: u32 = 1; pub fn default_receiver_config() -> Config { Config { @@ -65,11 +66,20 @@ pub struct ProgramTestFixtures { pub encoded_vaa_addresses: Vec, } -pub fn build_encoded_vaa_account_from_vaa(vaa: Vaa<&RawMessage>) -> Account { +pub fn build_encoded_vaa_account_from_vaa( + vaa: Vaa<&RawMessage>, + wrong_setup_option: WrongSetupOption, +) -> Account { let encoded_vaa_data = ( ::DISCRIMINATOR, Header { - status: ProcessingStatus::Verified, + status: { + if matches!(wrong_setup_option, WrongSetupOption::UnverifiedEncodedVaa) { + ProcessingStatus::Writing + } else { + ProcessingStatus::Verified + } + }, write_authority: Pubkey::new_unique(), version: 1, }, @@ -87,9 +97,15 @@ pub fn build_encoded_vaa_account_from_vaa(vaa: Vaa<&RawMessage>) -> Account { } } -pub fn build_guardian_set_account() -> Account { +pub fn build_guardian_set_account(wrong_setup_option: WrongSetupOption) -> Account { let guardian_set = GuardianSet { - index: DEFAULT_GUARDIAN_SET_INDEX, + index: { + if matches!(wrong_setup_option, WrongSetupOption::GuardianSetWrongIndex) { + WRONG_GUARDIAN_SET_INDEX + } else { + DEFAULT_GUARDIAN_SET_INDEX + } + }, keys: dummy_guardians() .iter() .map(|x| { @@ -101,7 +117,14 @@ pub fn build_guardian_set_account() -> Account { }) .collect::>(), creation_time: 0.into(), - expiration_time: 0.into(), + expiration_time: { + if matches!(wrong_setup_option, WrongSetupOption::GuardianSetExpired) { + 1 + } else { + 0 + } + } + .into(), }; let guardian_set_data = ( @@ -119,12 +142,24 @@ pub fn build_guardian_set_account() -> Account { rent_epoch: 0, } } + +#[derive(Copy, Clone)] +pub enum WrongSetupOption { + None, + GuardianSetExpired, + GuardianSetWrongIndex, + UnverifiedEncodedVaa, +} + /** * Setup to test the Pyth Receiver. The return values are a tuple composed of : * - The program simulator, which is used to send transactions * - The pubkeys of the encoded VAA accounts corresponding to the VAAs passed as argument, these accounts are prepopulated and can be used to test post_updates */ -pub async fn setup_pyth_receiver(vaas: Vec>) -> ProgramTestFixtures { +pub async fn setup_pyth_receiver( + vaas: Vec>, + wrong_setup_option: WrongSetupOption, +) -> ProgramTestFixtures { let mut program_test = ProgramTest::default(); program_test.add_program("pyth_solana_receiver", ID, None); @@ -132,11 +167,14 @@ pub async fn setup_pyth_receiver(vaas: Vec>) -> ProgramTestFixt for vaa in vaas { let encoded_vaa_address = Pubkey::new_unique(); encoded_vaa_addresses.push(encoded_vaa_address); - program_test.add_account(encoded_vaa_address, build_encoded_vaa_account_from_vaa(vaa)); + program_test.add_account( + encoded_vaa_address, + build_encoded_vaa_account_from_vaa(vaa, wrong_setup_option), + ); } program_test.add_account( get_guardian_set_address(BRIDGE_ID, DEFAULT_GUARDIAN_SET_INDEX), - build_guardian_set_account(), + build_guardian_set_account(wrong_setup_option), ); let mut program_simulator = ProgramSimulator::start_from_program_test(program_test).await; diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs index c7398626ed..6143e3b5fc 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs @@ -1,4 +1,5 @@ use { + crate::common::WrongSetupOption, common::{ setup_pyth_receiver, ProgramTestFixtures, @@ -41,7 +42,11 @@ async fn test_post_updates() { let ProgramTestFixtures { mut program_simulator, encoded_vaa_addresses, - } = setup_pyth_receiver(vec![serde_wormhole::from_slice(&vaa).unwrap()]).await; + } = setup_pyth_receiver( + vec![serde_wormhole::from_slice(&vaa).unwrap()], + WrongSetupOption::None, + ) + .await; let poster = program_simulator.get_funded_keypair().await.unwrap(); let price_update_keypair = Keypair::new(); @@ -110,7 +115,7 @@ async fn test_post_updates() { } #[tokio::test] -async fn test_post_updates_wrong_vaa() { +async fn test_post_updates_wrong_encoded_vaa_owner() { let feed_1 = create_dummy_price_feed_message(100); let feed_2 = create_dummy_price_feed_message(200); let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], false); @@ -119,7 +124,11 @@ async fn test_post_updates_wrong_vaa() { let ProgramTestFixtures { mut program_simulator, encoded_vaa_addresses: _, - } = setup_pyth_receiver(vec![serde_wormhole::from_slice(&vaa).unwrap()]).await; + } = setup_pyth_receiver( + vec![serde_wormhole::from_slice(&vaa).unwrap()], + WrongSetupOption::None, + ) + .await; let poster = program_simulator.get_funded_keypair().await.unwrap(); let price_update_keypair = Keypair::new(); @@ -142,3 +151,41 @@ async fn test_post_updates_wrong_vaa() { into_transation_error(ReceiverError::WrongVaaOwner) ); } + +#[tokio::test] +async fn test_post_updates_wrong_setup() { + let feed_1 = create_dummy_price_feed_message(100); + let feed_2 = create_dummy_price_feed_message(200); + let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], false); + let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap(); + + let ProgramTestFixtures { + mut program_simulator, + encoded_vaa_addresses, + } = setup_pyth_receiver( + vec![serde_wormhole::from_slice(&vaa).unwrap()], + WrongSetupOption::UnverifiedEncodedVaa, + ) + .await; + + let poster = program_simulator.get_funded_keypair().await.unwrap(); + let price_update_keypair = Keypair::new(); + + assert_eq!( + program_simulator + .process_ix( + PostUpdates::populate( + poster.pubkey(), + encoded_vaa_addresses[0], + price_update_keypair.pubkey(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(wormhole_core_bridge_solana::error::CoreBridgeError::UnverifiedVaa) + ); +} diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs index 9d4c3e0afa..4f036f4d9b 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs @@ -1,5 +1,8 @@ use { - crate::common::DEFAULT_GUARDIAN_SET_INDEX, + crate::common::{ + WrongSetupOption, + DEFAULT_GUARDIAN_SET_INDEX, + }, common::{ setup_pyth_receiver, ProgramTestFixtures, @@ -52,7 +55,7 @@ async fn test_post_updates_atomic() { let ProgramTestFixtures { mut program_simulator, encoded_vaa_addresses: _, - } = setup_pyth_receiver(vec![]).await; + } = setup_pyth_receiver(vec![], WrongSetupOption::None).await; let poster = program_simulator.get_funded_keypair().await.unwrap(); let price_update_keypair = Keypair::new(); @@ -134,7 +137,7 @@ async fn test_post_updates_atomic_wrong_vaa() { let ProgramTestFixtures { mut program_simulator, encoded_vaa_addresses: _, - } = setup_pyth_receiver(vec![]).await; + } = setup_pyth_receiver(vec![], WrongSetupOption::None).await; let poster = program_simulator.get_funded_keypair().await.unwrap(); let price_update_keypair = Keypair::new(); @@ -328,3 +331,64 @@ async fn test_post_updates_atomic_wrong_vaa() { into_transation_error(ReceiverError::WrongGuardianSetOwner) ); } + + +#[tokio::test] +async fn test_post_updates_atomic_wrong_setup() { + let feed_1 = create_dummy_price_feed_message(100); + let feed_2 = create_dummy_price_feed_message(200); + let message = create_accumulator_message(&[feed_1, feed_2], &[feed_1, feed_2], false); + let (vaa, merkle_price_updates) = deserialize_accumulator_update_data(message).unwrap(); + let price_update_keypair = Keypair::new(); + + let ProgramTestFixtures { + mut program_simulator, + encoded_vaa_addresses: _, + } = setup_pyth_receiver(vec![], WrongSetupOption::GuardianSetWrongIndex).await; + let poster: Keypair = program_simulator.get_funded_keypair().await.unwrap(); + assert_eq!( + program_simulator + .process_ix( + PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + vaa.clone(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::InvalidGuardianSetPda) + ); + + + let ProgramTestFixtures { + mut program_simulator, + encoded_vaa_addresses: _, + } = setup_pyth_receiver(vec![], WrongSetupOption::GuardianSetExpired).await; + let poster = program_simulator.get_funded_keypair().await.unwrap(); + assert_eq!( + program_simulator + .process_ix( + PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + vaa.clone(), + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::GuardianSetExpired) + ); +} From e01e64b52ef8d78afe9d4e36a452da4adce5732f Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Tue, 30 Jan 2024 15:18:20 +0000 Subject: [PATCH 12/15] Another test --- .../tests/test_post_updates_atomic.rs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs index 4f036f4d9b..94edebc62c 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs @@ -142,6 +142,29 @@ async fn test_post_updates_atomic_wrong_vaa() { let poster = program_simulator.get_funded_keypair().await.unwrap(); let price_update_keypair = Keypair::new(); + let mut vaa_buffer_copy: Vec = vaa.clone(); + // Mess up with the length of signatures + vaa_buffer_copy[5] = 255; + assert_eq!( + program_simulator + .process_ix( + PostUpdatesAtomic::populate( + poster.pubkey(), + price_update_keypair.pubkey(), + BRIDGE_ID, + DEFAULT_GUARDIAN_SET_INDEX, + vaa_buffer_copy, + merkle_price_updates[0].clone(), + ), + &vec![&poster, &price_update_keypair], + None, + ) + .await + .unwrap_err() + .unwrap(), + into_transation_error(ReceiverError::DeserializeVaaFailed) + ); + let vaa_wrong_num_signatures = serde_wormhole::to_vec(&trim_vaa_signatures( serde_wormhole::from_slice(&vaa).unwrap(), 4, @@ -167,6 +190,7 @@ async fn test_post_updates_atomic_wrong_vaa() { into_transation_error(ReceiverError::InsufficientGuardianSignatures) ); + let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); vaa_copy.version = 0; From d2c92c46a3b9a793dc1b1931325cb1a71f964b34 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Tue, 30 Jan 2024 15:43:16 +0000 Subject: [PATCH 13/15] Add comment --- .../programs/pyth-solana-receiver/tests/test_post_updates.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs index 6143e3b5fc..f8bc560825 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs @@ -138,7 +138,7 @@ async fn test_post_updates_wrong_encoded_vaa_owner() { .process_ix( PostUpdates::populate( poster.pubkey(), - Pubkey::new_unique(), + Pubkey::new_unique(), // Random pubkey instead of the encoded VAA address price_update_keypair.pubkey(), merkle_price_updates[0].clone(), ), From d3622f847b280b5171e445743e074515f0db66de Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Wed, 31 Jan 2024 13:48:52 +0000 Subject: [PATCH 14/15] Rename --- .../solana/program_simulator/src/lib.rs | 5 ++-- .../pyth-solana-receiver/tests/common/mod.rs | 2 +- .../tests/test_post_updates.rs | 8 +++--- .../tests/test_post_updates_atomic.rs | 26 +++++++++---------- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/target_chains/solana/program_simulator/src/lib.rs b/target_chains/solana/program_simulator/src/lib.rs index ac47390cea..a6833fd952 100644 --- a/target_chains/solana/program_simulator/src/lib.rs +++ b/target_chains/solana/program_simulator/src/lib.rs @@ -51,7 +51,7 @@ impl ProgramSimulator { /// Process a transaction containing `instruction` signed by `signers`. /// `payer` is used to pay for and sign the transaction. - pub async fn process_ix( + pub async fn process_ix_with_default_compute_limit( &mut self, instruction: Instruction, signers: &Vec<&Keypair>, @@ -83,7 +83,8 @@ impl ProgramSimulator { let instruction = system_instruction::transfer(&self.genesis_keypair.pubkey(), to, lamports); - self.process_ix(instruction, &vec![], None).await + self.process_ix_with_default_compute_limit(instruction, &vec![], None) + .await } pub async fn get_funded_keypair(&mut self) -> Result { diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs index 3bff972b8d..968374dd46 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/common/mod.rs @@ -183,7 +183,7 @@ pub async fn setup_pyth_receiver( let setup_keypair: Keypair = program_simulator.get_funded_keypair().await.unwrap(); program_simulator - .process_ix( + .process_ix_with_default_compute_limit( Initialize::populate(&setup_keypair.pubkey(), initial_config.clone()), &vec![&setup_keypair], None, diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs index f8bc560825..566eec4a0e 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs @@ -53,7 +53,7 @@ async fn test_post_updates() { // post one update program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdates::populate( poster.pubkey(), encoded_vaa_addresses[0], @@ -84,7 +84,7 @@ async fn test_post_updates() { // post another update to the same account program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdates::populate( poster.pubkey(), encoded_vaa_addresses[0], @@ -135,7 +135,7 @@ async fn test_post_updates_wrong_encoded_vaa_owner() { assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdates::populate( poster.pubkey(), Pubkey::new_unique(), // Random pubkey instead of the encoded VAA address @@ -173,7 +173,7 @@ async fn test_post_updates_wrong_setup() { assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdates::populate( poster.pubkey(), encoded_vaa_addresses[0], diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs index 94edebc62c..cf12792c24 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs @@ -62,7 +62,7 @@ async fn test_post_updates_atomic() { // post one update atomically program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -95,7 +95,7 @@ async fn test_post_updates_atomic() { // post another update to the same account program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -147,7 +147,7 @@ async fn test_post_updates_atomic_wrong_vaa() { vaa_buffer_copy[5] = 255; assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -172,7 +172,7 @@ async fn test_post_updates_atomic_wrong_vaa() { .unwrap(); assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -196,7 +196,7 @@ async fn test_post_updates_atomic_wrong_vaa() { assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -219,7 +219,7 @@ async fn test_post_updates_atomic_wrong_vaa() { assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -242,7 +242,7 @@ async fn test_post_updates_atomic_wrong_vaa() { assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -266,7 +266,7 @@ async fn test_post_updates_atomic_wrong_vaa() { assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -289,7 +289,7 @@ async fn test_post_updates_atomic_wrong_vaa() { assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -313,7 +313,7 @@ async fn test_post_updates_atomic_wrong_vaa() { assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -344,7 +344,7 @@ async fn test_post_updates_atomic_wrong_vaa() { wrong_instruction.accounts[1].pubkey = wrong_guardian_set; assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( wrong_instruction, &vec![&poster, &price_update_keypair], None, @@ -372,7 +372,7 @@ async fn test_post_updates_atomic_wrong_setup() { let poster: Keypair = program_simulator.get_funded_keypair().await.unwrap(); assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), @@ -398,7 +398,7 @@ async fn test_post_updates_atomic_wrong_setup() { let poster = program_simulator.get_funded_keypair().await.unwrap(); assert_eq!( program_simulator - .process_ix( + .process_ix_with_default_compute_limit( PostUpdatesAtomic::populate( poster.pubkey(), price_update_keypair.pubkey(), From 35ee492bb03232fbe01d0ae6fa537d18ca436eef Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Wed, 31 Jan 2024 13:49:45 +0000 Subject: [PATCH 15/15] Rename --- .../solana/program_simulator/src/lib.rs | 2 +- .../tests/test_post_updates.rs | 6 ++--- .../tests/test_post_updates_atomic.rs | 24 +++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/target_chains/solana/program_simulator/src/lib.rs b/target_chains/solana/program_simulator/src/lib.rs index a6833fd952..b592384b7a 100644 --- a/target_chains/solana/program_simulator/src/lib.rs +++ b/target_chains/solana/program_simulator/src/lib.rs @@ -108,7 +108,7 @@ impl ProgramSimulator { } } -pub fn into_transation_error>(error: T) -> TransactionError { +pub fn into_transaction_error>(error: T) -> TransactionError { TransactionError::InstructionError( 0, InstructionError::try_from(u64::from(ProgramError::from(error.into()))).unwrap(), diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs index 566eec4a0e..b3b0761ec7 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs @@ -4,7 +4,7 @@ use { setup_pyth_receiver, ProgramTestFixtures, }, - program_simulator::into_transation_error, + program_simulator::into_transaction_error, pyth_solana_receiver::{ error::ReceiverError, instruction::PostUpdates, @@ -148,7 +148,7 @@ async fn test_post_updates_wrong_encoded_vaa_owner() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::WrongVaaOwner) + into_transaction_error(ReceiverError::WrongVaaOwner) ); } @@ -186,6 +186,6 @@ async fn test_post_updates_wrong_setup() { .await .unwrap_err() .unwrap(), - into_transation_error(wormhole_core_bridge_solana::error::CoreBridgeError::UnverifiedVaa) + into_transaction_error(wormhole_core_bridge_solana::error::CoreBridgeError::UnverifiedVaa) ); } diff --git a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs index cf12792c24..a464e7ef9f 100644 --- a/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs +++ b/target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs @@ -7,7 +7,7 @@ use { setup_pyth_receiver, ProgramTestFixtures, }, - program_simulator::into_transation_error, + program_simulator::into_transaction_error, pyth_solana_receiver::{ error::ReceiverError, instruction::PostUpdatesAtomic, @@ -162,7 +162,7 @@ async fn test_post_updates_atomic_wrong_vaa() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::DeserializeVaaFailed) + into_transaction_error(ReceiverError::DeserializeVaaFailed) ); let vaa_wrong_num_signatures = serde_wormhole::to_vec(&trim_vaa_signatures( @@ -187,7 +187,7 @@ async fn test_post_updates_atomic_wrong_vaa() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::InsufficientGuardianSignatures) + into_transaction_error(ReceiverError::InsufficientGuardianSignatures) ); @@ -211,7 +211,7 @@ async fn test_post_updates_atomic_wrong_vaa() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::InvalidVaaVersion) + into_transaction_error(ReceiverError::InvalidVaaVersion) ); let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); @@ -234,7 +234,7 @@ async fn test_post_updates_atomic_wrong_vaa() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::GuardianSetMismatch) + into_transaction_error(ReceiverError::GuardianSetMismatch) ); let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); @@ -257,7 +257,7 @@ async fn test_post_updates_atomic_wrong_vaa() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::InvalidGuardianOrder) + into_transaction_error(ReceiverError::InvalidGuardianOrder) ); @@ -281,7 +281,7 @@ async fn test_post_updates_atomic_wrong_vaa() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::InvalidGuardianIndex) + into_transaction_error(ReceiverError::InvalidGuardianIndex) ); let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap(); @@ -304,7 +304,7 @@ async fn test_post_updates_atomic_wrong_vaa() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::InvalidSignature) + into_transaction_error(ReceiverError::InvalidSignature) ); @@ -328,7 +328,7 @@ async fn test_post_updates_atomic_wrong_vaa() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::InvalidGuardianKeyRecovery) + into_transaction_error(ReceiverError::InvalidGuardianKeyRecovery) ); let mut wrong_instruction = PostUpdatesAtomic::populate( @@ -352,7 +352,7 @@ async fn test_post_updates_atomic_wrong_vaa() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::WrongGuardianSetOwner) + into_transaction_error(ReceiverError::WrongGuardianSetOwner) ); } @@ -387,7 +387,7 @@ async fn test_post_updates_atomic_wrong_setup() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::InvalidGuardianSetPda) + into_transaction_error(ReceiverError::InvalidGuardianSetPda) ); @@ -413,6 +413,6 @@ async fn test_post_updates_atomic_wrong_setup() { .await .unwrap_err() .unwrap(), - into_transation_error(ReceiverError::GuardianSetExpired) + into_transaction_error(ReceiverError::GuardianSetExpired) ); }