Skip to content

Commit

Permalink
Merge fix for SendRewards stack overflow (#566)
Browse files Browse the repository at this point in the history
  • Loading branch information
ruuda committed May 18, 2022
2 parents 7f91f9e + d902957 commit 64fd772
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 5 deletions.
6 changes: 3 additions & 3 deletions anker/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ fn process_send_rewards(
accounts_raw: &[AccountInfo],
wormhole_nonce: u32,
) -> ProgramResult {
let accounts = SendRewardsAccountsInfo::try_from_slice(accounts_raw)?;
let accounts = Box::new(SendRewardsAccountsInfo::try_from_slice(accounts_raw)?);
let anker = deserialize_anker(program_id, accounts.anker, accounts.solido)?.1;
anker.check_ust_reserve_address(
program_id,
Expand Down Expand Up @@ -622,11 +622,11 @@ fn process_send_rewards(
)?;
}

let payload = crate::wormhole::Payload::new(
let payload = Box::new(crate::wormhole::Payload::new(
wormhole_nonce,
reserve_ust_amount,
anker.terra_rewards_destination.to_foreign(),
);
));

// For the order and meaning of the accounts, see also
// https://github.com/certusone/wormhole/blob/537d56b37aa041a585f2c90515fa3a7ffa5898b5/solana/modules/token_bridge/program/src/instructions.rs#L328-L390.
Expand Down
1 change: 1 addition & 0 deletions anker/tests/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ pub mod deposit;
pub mod fetch_pool_price;
pub mod manager;
pub mod sell_rewards;
pub mod send_rewards;
pub mod withdraw;
3 changes: 3 additions & 0 deletions anker/tests/tests/sell_rewards.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: 2022 Chorus One AG
// SPDX-License-Identifier: GPL-3.0

use anker::{
error::AnkerError,
state::{POOL_PRICE_MIN_SAMPLE_DISTANCE, POOL_PRICE_NUM_SAMPLES},
Expand Down
49 changes: 49 additions & 0 deletions anker/tests/tests/send_rewards.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-FileCopyrightText: 2022 Chorus One AG
// SPDX-License-Identifier: GPL-3.0

use solana_program::instruction::InstructionError;
use solana_program_test::tokio;
use solana_sdk::transaction::TransactionError;
use solana_sdk::transport::TransportError;

use lido::token::Lamports;
use testlib::anker_context::Context;

const DEPOSIT_AMOUNT: u64 = 1_000_000_000; // 1e9 units

#[tokio::test]
async fn test_send_rewards_does_not_overflow_stack() {
let mut context = Context::new().await;
context
.initialize_token_pool_and_deposit(Lamports(DEPOSIT_AMOUNT))
.await;
context.fill_historical_st_sol_price_array().await;
context.sell_rewards().await;

let result = context.try_send_rewards().await;

match result {
// An access violation caused by a stack overflow results in this error.
Err(TransportError::TransactionError(TransactionError::InstructionError(
0,
InstructionError::ProgramFailedToComplete,
))) => {
panic!("Did the program overflow the stack?")
}
Err(TransportError::TransactionError(TransactionError::InstructionError(
0,
InstructionError::AccountNotExecutable,
))) => {
// This error is expected, we try to call a dummy address where the
// Wormhole program is supposed to live, but that dummy address is
// not executable. If we get here, it means we executed the entire
// `SendRewards` instruction aside from the final call to the
// Wormhole progrma. In particular we know that we didn't overflow
// the stack.
}
Ok(()) => panic!("This should not have passed without the Wormhole program present."),
Err(err) => {
panic!("Unexpected error: {:?}", err);
}
}
}
63 changes: 61 additions & 2 deletions testlib/src/anker_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,67 @@ impl Context {
)],
vec![],
)
.await?;
Ok(())
.await
}

/// Call the `SendRewards` instruction. Note that this will fail, because we
/// don't have the Wormhole programs available in the test context. But we
/// can still test everything up to the point where we call Wormhole.
pub async fn try_send_rewards(&mut self) -> transport::Result<()> {
let solido_address = self.solido_context.solido.pubkey();

let (anker_instance, _anker_bump_seed) =
anker::find_instance_address(&id(), &solido_address);

let (ust_reserve_account, _ust_reserve_bump_seed) =
anker::find_ust_reserve_account(&id(), &anker_instance);

let (reserve_authority, _reserve_authority_bump_seed) =
find_reserve_authority(&id(), &anker_instance);

let anker = self.get_anker().await;
let message = self.solido_context.deterministic_keypair.new_keypair();

let transfer_args = anker::wormhole::WormholeTransferArgs::new(
anker.wormhole_parameters.token_bridge_program_id,
anker.wormhole_parameters.core_bridge_program_id,
self.token_pool_context.ust_mint_address,
self.solido_context.context.payer.pubkey(),
ust_reserve_account,
reserve_authority,
message.pubkey(),
);

let wormhole_nonce = 1;

send_transaction(
&mut self.solido_context.context,
&mut self.solido_context.nonce,
&[instruction::send_rewards(
&id(),
&instruction::SendRewardsAccountsMeta {
anker: anker_instance,
solido: solido_address,
reserve_authority,
wormhole_token_bridge_program_id: transfer_args.token_bridge_program_id,
wormhole_core_bridge_program_id: transfer_args.core_bridge_program_id,
payer: transfer_args.payer,
config_key: transfer_args.config_key,
ust_reserve_account,
wrapped_meta_key: transfer_args.wrapped_meta_key,
ust_mint: self.token_pool_context.ust_mint_address,
authority_signer_key: transfer_args.authority_signer_key,
bridge_config: transfer_args.bridge_config,
message: message.pubkey(),
emitter_key: transfer_args.emitter_key,
sequence_key: transfer_args.sequence_key,
fee_collector_key: transfer_args.fee_collector_key,
},
wormhole_nonce,
)],
vec![&message],
)
.await
}

/// Return the value of the given amount of stSOL in SOL.
Expand Down

0 comments on commit 64fd772

Please sign in to comment.