Skip to content

Commit 990befe

Browse files
authored
fix(target_chains/solana): use find_program_address on initialize (#1991)
1 parent 3bc3872 commit 990befe

File tree

3 files changed

+40
-13
lines changed

3 files changed

+40
-13
lines changed

target_chains/solana/programs/pyth-price-store/src/processor/initialize_publisher.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use {
1313
validate_authority,
1414
validate_buffer,
1515
validate_config,
16-
validate_publisher_config,
16+
validate_publisher_config_for_init,
1717
validate_system,
1818
},
1919
},
@@ -51,12 +51,11 @@ pub fn initialize_publisher(
5151
let first_account = accounts.next();
5252
let config = validate_config(accounts.next(), args.config_bump, program_id, false)?;
5353
let authority = validate_authority(first_account, config)?;
54-
let publisher_config = validate_publisher_config(
54+
let publisher_config = validate_publisher_config_for_init(
5555
accounts.next(),
5656
args.publisher_config_bump,
5757
&args.publisher.into(),
5858
program_id,
59-
true,
6059
)?;
6160
let buffer = validate_buffer(accounts.next(), program_id)?;
6261
let system = validate_system(accounts.next())?;

target_chains/solana/programs/pyth-price-store/src/processor/submit_prices.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use {
99
validate::{
1010
validate_buffer,
1111
validate_publisher,
12-
validate_publisher_config,
12+
validate_publisher_config_for_access,
1313
},
1414
},
1515
solana_program::{
@@ -39,17 +39,22 @@ pub fn submit_prices(
3939
) -> ProgramResult {
4040
let mut accounts = accounts.iter();
4141
let publisher = validate_publisher(accounts.next())?;
42-
let publisher_config = validate_publisher_config(
42+
let publisher_config = validate_publisher_config_for_access(
4343
accounts.next(),
4444
args.publisher_config_bump,
4545
publisher.key,
4646
program_id,
47-
false,
4847
)?;
4948
let buffer = validate_buffer(accounts.next(), program_id)?;
5049

5150
let publisher_config_data = publisher_config.data.borrow();
5251
let publisher_config = publisher_config::read(*publisher_config_data)?;
52+
// Required to ensure that `find_program_address` returned the same account as
53+
// `create_program_address` in `initialize_publisher`.
54+
ensure!(
55+
ProgramError::InvalidArgument,
56+
sol_memcmp(&publisher.key.to_bytes(), &publisher_config.publisher, 32) == 0
57+
);
5358
ensure!(
5459
ProgramError::InvalidArgument,
5560
sol_memcmp(&buffer.key.to_bytes(), &publisher_config.buffer_account, 32) == 0

target_chains/solana/programs/pyth-price-store/src/validate.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ pub fn validate_config<'a, 'b>(
5757
require_writable: bool,
5858
) -> Result<&'b AccountInfo<'a>, ProgramError> {
5959
let config = account.ok_or(ProgramError::NotEnoughAccountKeys)?;
60-
let config_pda = Pubkey::create_program_address(&[CONFIG_SEED.as_bytes(), &[bump]], program_id)
61-
.map_err(|_| ProgramError::InvalidInstructionData)?;
60+
let (config_pda, expected_bump) =
61+
Pubkey::find_program_address(&[CONFIG_SEED.as_bytes()], program_id);
62+
ensure!(ProgramError::InvalidInstructionData, bump == expected_bump);
6263
ensure!(
6364
ProgramError::InvalidArgument,
6465
pubkey_eq(config.key, &config_pda)
@@ -85,14 +86,17 @@ pub fn validate_authority<'a, 'b>(
8586
Ok(authority)
8687
}
8788

88-
pub fn validate_publisher_config<'a, 'b>(
89+
pub fn validate_publisher_config_for_access<'a, 'b>(
8990
account: Option<&'b AccountInfo<'a>>,
9091
bump: u8,
9192
publisher: &Pubkey,
9293
program_id: &Pubkey,
93-
require_writable: bool,
9494
) -> Result<&'b AccountInfo<'a>, ProgramError> {
9595
let publisher_config = account.ok_or(ProgramError::NotEnoughAccountKeys)?;
96+
// We use `create_program_address` to make the `submit_prices` instruction cheaper.
97+
// `find_program_address` is used in `initialize_publisher`, so we'll always have
98+
// only one publisher config per publisher. As long as we check the publisher key
99+
// stored in the account in `submit_prices`, it should be safe.
96100
let publisher_config_pda = Pubkey::create_program_address(
97101
&[
98102
PUBLISHER_CONFIG_SEED.as_bytes(),
@@ -102,9 +106,28 @@ pub fn validate_publisher_config<'a, 'b>(
102106
program_id,
103107
)
104108
.map_err(|_| ProgramError::InvalidInstructionData)?;
105-
if require_writable {
106-
ensure!(ProgramError::InvalidArgument, publisher_config.is_writable);
107-
}
109+
ensure!(
110+
ProgramError::MissingRequiredSignature,
111+
pubkey_eq(publisher_config.key, &publisher_config_pda)
112+
);
113+
Ok(publisher_config)
114+
}
115+
116+
pub fn validate_publisher_config_for_init<'a, 'b>(
117+
account: Option<&'b AccountInfo<'a>>,
118+
bump: u8,
119+
publisher: &Pubkey,
120+
program_id: &Pubkey,
121+
) -> Result<&'b AccountInfo<'a>, ProgramError> {
122+
let publisher_config = account.ok_or(ProgramError::NotEnoughAccountKeys)?;
123+
// We use `find_program_address` to guarantee that only one publisher_config
124+
// is created per publisher.
125+
let (publisher_config_pda, expected_bump) = Pubkey::find_program_address(
126+
&[PUBLISHER_CONFIG_SEED.as_bytes(), &publisher.to_bytes()],
127+
program_id,
128+
);
129+
ensure!(ProgramError::InvalidInstructionData, bump == expected_bump);
130+
ensure!(ProgramError::InvalidArgument, publisher_config.is_writable);
108131
ensure!(
109132
ProgramError::MissingRequiredSignature,
110133
pubkey_eq(publisher_config.key, &publisher_config_pda)

0 commit comments

Comments
 (0)