Procházet zdrojové kódy

[solana] Add wrong vaa tests (#1262)

* Checkpoint

* Checkpoint

* Cleanup

* Checkpoint, debug

* Go

* Checkpoint

* Fix

* Add new error and test

* Cleanup

* Add another test

* Keep adding errors

* Another test

* Add comment

* Rename

* Rename
guibescos před 1 rokem
rodič
revize
2ab72d994d

+ 1 - 0
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",

+ 1 - 0
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"

+ 26 - 6
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,
+        },
     },
 };
 
@@ -43,15 +51,19 @@ 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>,
         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
@@ -71,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<Keypair, BanksClientError> {
@@ -94,3 +107,10 @@ impl ProgramSimulator {
         Ok(T::deserialize(&mut &account.data[8..])?)
     }
 }
+
+pub fn into_transaction_error<T: Into<anchor_lang::prelude::Error>>(error: T) -> TransactionError {
+    TransactionError::InstructionError(
+        0,
+        InstructionError::try_from(u64::from(ProgramError::from(error.into()))).unwrap(),
+    )
+}

+ 22 - 17
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,27 +13,39 @@ 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,
+    // 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 number of guardian signatures is below the minimum")]
     InsufficientGuardianSignatures,
-    #[msg("The Guardian Set account doesn't match the PDA derivation")]
-    InvalidGuardianSetPda,
-    // Wormhole errors
     #[msg("Invalid VAA version")]
     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")]
     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,
+    #[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,
+    #[msg("The signer is not authorized to accept the governance authority")]
+    TargetGovernanceAuthorityMismatch,
+    #[msg("The governance authority needs to request a transfer first")]
+    NonexistentGovernanceAuthorityTransferRequest,
 }

+ 9 - 3
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?
@@ -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::<GuardianSet> 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>,
@@ -324,6 +324,12 @@ fn deserialize_guardian_set_checked(
         ReceiverError::InvalidGuardianSetPda
     );
 
+    let timestamp = Clock::get().map(Into::into)?;
+    require!(
+        guardian_set.inner().is_active(&timestamp),
+        ReceiverError::GuardianSetExpired
+    );
+
     Ok(guardian_set)
 }
 

+ 47 - 9
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<Pubkey>,
 }
 
-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 = (
         <EncodedVaa as anchor_lang::Discriminator>::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::<Vec<[u8; 20]>>(),
         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<Vaa<&RawMessage>>) -> ProgramTestFixtures {
+pub async fn setup_pyth_receiver(
+    vaas: Vec<Vaa<&RawMessage>>,
+    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<Vaa<&RawMessage>>) -> 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;
@@ -145,7 +183,7 @@ pub async fn setup_pyth_receiver(vaas: Vec<Vaa<&RawMessage>>) -> ProgramTestFixt
     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,

+ 87 - 3
target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates.rs

@@ -1,9 +1,12 @@
 use {
+    crate::common::WrongSetupOption,
     common::{
         setup_pyth_receiver,
         ProgramTestFixtures,
     },
+    program_simulator::into_transaction_error,
     pyth_solana_receiver::{
+        error::ReceiverError,
         instruction::PostUpdates,
         sdk::deserialize_accumulator_update_data,
         state::price_update::{
@@ -18,6 +21,7 @@ use {
             create_dummy_price_feed_message,
         },
     },
+    solana_program::pubkey::Pubkey,
     solana_sdk::{
         signature::Keypair,
         signer::Signer,
@@ -38,14 +42,18 @@ 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();
 
     // post one update
     program_simulator
-        .process_ix(
+        .process_ix_with_default_compute_limit(
             PostUpdates::populate(
                 poster.pubkey(),
                 encoded_vaa_addresses[0],
@@ -76,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],
@@ -105,3 +113,79 @@ async fn test_post_updates() {
         feed_2
     );
 }
+
+#[tokio::test]
+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);
+    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::None,
+    )
+    .await;
+
+    let poster = program_simulator.get_funded_keypair().await.unwrap();
+    let price_update_keypair = Keypair::new();
+
+    assert_eq!(
+        program_simulator
+            .process_ix_with_default_compute_limit(
+                PostUpdates::populate(
+                    poster.pubkey(),
+                    Pubkey::new_unique(), // Random pubkey instead of the encoded VAA address
+                    price_update_keypair.pubkey(),
+                    merkle_price_updates[0].clone(),
+                ),
+                &vec![&poster, &price_update_keypair],
+                None,
+            )
+            .await
+            .unwrap_err()
+            .unwrap(),
+        into_transaction_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_with_default_compute_limit(
+                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_transaction_error(wormhole_core_bridge_solana::error::CoreBridgeError::UnverifiedVaa)
+    );
+}

+ 305 - 5
target_chains/solana/programs/pyth-solana-receiver/tests/test_post_updates_atomic.rs

@@ -1,12 +1,20 @@
 use {
-    crate::common::DEFAULT_GUARDIAN_SET_INDEX,
+    crate::common::{
+        WrongSetupOption,
+        DEFAULT_GUARDIAN_SET_INDEX,
+    },
     common::{
         setup_pyth_receiver,
         ProgramTestFixtures,
     },
+    program_simulator::into_transaction_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,
@@ -20,11 +28,13 @@ use {
             trim_vaa_signatures,
         },
     },
+    serde_wormhole::RawMessage,
     solana_sdk::{
         signature::Keypair,
         signer::Signer,
     },
     wormhole_core_bridge_solana::ID as BRIDGE_ID,
+    wormhole_sdk::Vaa,
 };
 
 mod common;
@@ -45,14 +55,14 @@ 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();
 
     // post one update atomically
     program_simulator
-        .process_ix(
+        .process_ix_with_default_compute_limit(
             PostUpdatesAtomic::populate(
                 poster.pubkey(),
                 price_update_keypair.pubkey(),
@@ -85,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(),
@@ -116,3 +126,293 @@ 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![], WrongSetupOption::None).await;
+
+    let poster = program_simulator.get_funded_keypair().await.unwrap();
+    let price_update_keypair = Keypair::new();
+
+    let mut vaa_buffer_copy: Vec<u8> = vaa.clone();
+    // Mess up with the length of signatures
+    vaa_buffer_copy[5] = 255;
+    assert_eq!(
+        program_simulator
+            .process_ix_with_default_compute_limit(
+                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_transaction_error(ReceiverError::DeserializeVaaFailed)
+    );
+
+    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_with_default_compute_limit(
+                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_transaction_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_with_default_compute_limit(
+                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_transaction_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_with_default_compute_limit(
+                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_transaction_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_with_default_compute_limit(
+                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_transaction_error(ReceiverError::InvalidGuardianOrder)
+    );
+
+
+    let mut vaa_copy: Vaa<&RawMessage> = serde_wormhole::from_slice(&vaa).unwrap();
+    vaa_copy.signatures[0].index = 20;
+
+    assert_eq!(
+        program_simulator
+            .process_ix_with_default_compute_limit(
+                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_transaction_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_with_default_compute_limit(
+                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_transaction_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_with_default_compute_limit(
+                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_transaction_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_with_default_compute_limit(
+                wrong_instruction,
+                &vec![&poster, &price_update_keypair],
+                None,
+            )
+            .await
+            .unwrap_err()
+            .unwrap(),
+        into_transaction_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_with_default_compute_limit(
+                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_transaction_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_with_default_compute_limit(
+                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_transaction_error(ReceiverError::GuardianSetExpired)
+    );
+}