Skip to content

Commit 1a6ce1b

Browse files
authored
Move minimum size check to load_checked and initialize_checked (#271)
* Size moved to deserialization functions * Stop using load_account_as in rust * Comments
1 parent 16f61d5 commit 1a6ce1b

File tree

6 files changed

+43
-53
lines changed

6 files changed

+43
-53
lines changed

program/rust/src/deserialize.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::c_oracle_header::{
1313
};
1414
use crate::error::OracleError;
1515
use crate::utils::{
16+
check_valid_fresh_account,
1617
clear_account,
1718
pyth_assert,
1819
};
@@ -45,7 +46,8 @@ pub fn load_mut<T: Pod>(data: &mut [u8]) -> Result<&mut T, OracleError> {
4546
.map_err(|_| OracleError::InstructionDataSliceMisaligned)
4647
}
4748

48-
/// Get the data stored in `account` as a value of type `T`
49+
/// Get the data stored in `account` as a value of type `T`.
50+
/// WARNING : Use `load_checked` to load initialized Pyth accounts
4951
pub fn load_account_as<'a, T: Pod>(account: &'a AccountInfo) -> Result<Ref<'a, T>, ProgramError> {
5052
let data = account.try_borrow_data()?;
5153

@@ -56,6 +58,7 @@ pub fn load_account_as<'a, T: Pod>(account: &'a AccountInfo) -> Result<Ref<'a, T
5658

5759
/// Mutably borrow the data in `account` as a value of type `T`.
5860
/// Any mutations to the returned value will be reflected in the account data.
61+
/// WARNING : Use `load_checked` to load initialized Pyth accounts
5962
pub fn load_account_as_mut<'a, T: Pod>(
6063
account: &'a AccountInfo,
6164
) -> Result<RefMut<'a, T>, ProgramError> {
@@ -70,6 +73,11 @@ pub fn load_checked<'a, T: PythAccount>(
7073
account: &'a AccountInfo,
7174
version: u32,
7275
) -> Result<RefMut<'a, T>, ProgramError> {
76+
pyth_assert(
77+
account.data_len() >= T::minimum_size(),
78+
OracleError::AccountTooSmall.into(),
79+
)?;
80+
7381
{
7482
let account_header = load_account_as::<AccountHeader>(account)?;
7583
pyth_assert(
@@ -87,6 +95,11 @@ pub fn initialize_pyth_account_checked<'a, T: PythAccount>(
8795
account: &'a AccountInfo,
8896
version: u32,
8997
) -> Result<RefMut<'a, T>, ProgramError> {
98+
pyth_assert(
99+
account.data_len() >= T::minimum_size(),
100+
OracleError::AccountTooSmall.into(),
101+
)?;
102+
check_valid_fresh_account(account)?;
90103
clear_account(account)?;
91104

92105
{

program/rust/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub enum OracleError {
3232
InstructionDataTooShort = 610,
3333
#[error("InstructionDataSliceMisaligned")]
3434
InstructionDataSliceMisaligned = 611,
35+
#[error("AccountTooSmall")]
36+
AccountTooSmall = 612,
3537
}
3638

3739
impl From<OracleError> for ProgramError {

program/rust/src/rust_oracle.rs

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use crate::c_oracle_header::{
2222
use crate::deserialize::{
2323
initialize_pyth_account_checked,
2424
load,
25-
load_account_as_mut,
2625
load_checked,
2726
};
2827
use crate::instruction::{
@@ -37,7 +36,6 @@ use crate::instruction::{
3736
use crate::time_machine_types::PriceAccountWrapper;
3837
use crate::utils::{
3938
check_exponent_range,
40-
check_valid_fresh_account,
4139
check_valid_funding_account,
4240
check_valid_signable_account,
4341
check_valid_writable_account,
@@ -115,7 +113,7 @@ pub fn resize_price_account(
115113
}?;
116114

117115
check_valid_funding_account(funding_account_info)?;
118-
check_valid_signable_account(program_id, price_account_info, size_of::<PriceAccount>())?;
116+
check_valid_signable_account(program_id, price_account_info)?;
119117
pyth_assert(
120118
check_id(system_program.key),
121119
OracleError::InvalidSystemAccount.into(),
@@ -145,11 +143,7 @@ pub fn resize_price_account(
145143
price_account_info.realloc(size_of::<PriceAccountWrapper>(), false)?;
146144

147145
// Check that everything is ok
148-
check_valid_signable_account(
149-
program_id,
150-
price_account_info,
151-
size_of::<PriceAccountWrapper>(),
152-
)?;
146+
check_valid_signable_account(program_id, price_account_info)?;
153147
let mut price_account =
154148
load_checked::<PriceAccountWrapper>(price_account_info, PC_VERSION)?;
155149
// Initialize Time Machine
@@ -176,12 +170,7 @@ pub fn init_mapping(
176170
}?;
177171

178172
check_valid_funding_account(funding_account)?;
179-
check_valid_signable_account(
180-
program_id,
181-
fresh_mapping_account,
182-
size_of::<MappingAccount>(),
183-
)?;
184-
check_valid_fresh_account(fresh_mapping_account)?;
173+
check_valid_signable_account(program_id, fresh_mapping_account)?;
185174

186175
// Initialize by setting to zero again (just in case) and populating the account header
187176
let hdr = load::<CommandHeader>(instruction_data)?;
@@ -201,9 +190,8 @@ pub fn add_mapping(
201190
}?;
202191

203192
check_valid_funding_account(funding_account)?;
204-
check_valid_signable_account(program_id, cur_mapping, size_of::<MappingAccount>())?;
205-
check_valid_signable_account(program_id, next_mapping, size_of::<MappingAccount>())?;
206-
check_valid_fresh_account(next_mapping)?;
193+
check_valid_signable_account(program_id, cur_mapping)?;
194+
check_valid_signable_account(program_id, next_mapping)?;
207195

208196
let hdr = load::<CommandHeader>(instruction_data)?;
209197
let mut cur_mapping = load_checked::<MappingAccount>(cur_mapping, hdr.version)?;
@@ -240,7 +228,7 @@ pub fn upd_price(
240228
}?;
241229

242230
check_valid_funding_account(funding_account)?;
243-
check_valid_writable_account(program_id, price_account, size_of::<PriceAccount>())?;
231+
check_valid_writable_account(program_id, price_account)?;
244232
// Check clock
245233
let clock = Clock::from_account_info(clock_account)?;
246234

@@ -291,7 +279,8 @@ pub fn upd_price(
291279

292280
let account_len = price_account.try_data_len()?;
293281
if aggregate_updated && account_len == PRICE_ACCOUNT_SIZE {
294-
let mut price_account = load_account_as_mut::<PriceAccountWrapper>(price_account)?;
282+
let mut price_account =
283+
load_checked::<PriceAccountWrapper>(price_account, cmd_args.header.version)?;
295284
price_account.add_price_to_time_machine()?;
296285
}
297286

@@ -358,9 +347,8 @@ pub fn add_price(
358347
}?;
359348

360349
check_valid_funding_account(funding_account)?;
361-
check_valid_signable_account(program_id, product_account, PC_PROD_ACC_SIZE as usize)?;
362-
check_valid_signable_account(program_id, price_account, size_of::<PriceAccount>())?;
363-
check_valid_fresh_account(price_account)?;
350+
check_valid_signable_account(program_id, product_account)?;
351+
check_valid_signable_account(program_id, price_account)?;
364352

365353
let mut product_data =
366354
load_checked::<ProductAccount>(product_account, cmd_args.header.version)?;
@@ -403,8 +391,8 @@ pub fn del_price(
403391
}?;
404392

405393
check_valid_funding_account(funding_account)?;
406-
check_valid_signable_account(program_id, product_account, PC_PROD_ACC_SIZE as usize)?;
407-
check_valid_signable_account(program_id, price_account, size_of::<PriceAccount>())?;
394+
check_valid_signable_account(program_id, product_account)?;
395+
check_valid_signable_account(program_id, price_account)?;
408396

409397
{
410398
let cmd_args = load::<CommandHeader>(instruction_data)?;
@@ -454,7 +442,7 @@ pub fn init_price(
454442
}?;
455443

456444
check_valid_funding_account(funding_account)?;
457-
check_valid_signable_account(program_id, price_account, size_of::<PriceAccount>())?;
445+
check_valid_signable_account(program_id, price_account)?;
458446

459447
let mut price_data = load_checked::<PriceAccount>(price_account, cmd_args.header.version)?;
460448
pyth_assert(
@@ -524,7 +512,7 @@ pub fn add_publisher(
524512
}?;
525513

526514
check_valid_funding_account(funding_account)?;
527-
check_valid_signable_account(program_id, price_account, size_of::<PriceAccount>())?;
515+
check_valid_signable_account(program_id, price_account)?;
528516

529517
let mut price_data = load_checked::<PriceAccount>(price_account, cmd_args.header.version)?;
530518

@@ -577,7 +565,7 @@ pub fn del_publisher(
577565
}?;
578566

579567
check_valid_funding_account(funding_account)?;
580-
check_valid_signable_account(program_id, price_account, size_of::<PriceAccount>())?;
568+
check_valid_signable_account(program_id, price_account)?;
581569

582570
let mut price_data = load_checked::<PriceAccount>(price_account, cmd_args.header.version)?;
583571

@@ -613,13 +601,8 @@ pub fn add_product(
613601
}?;
614602

615603
check_valid_funding_account(funding_account)?;
616-
check_valid_signable_account(
617-
program_id,
618-
tail_mapping_account,
619-
size_of::<MappingAccount>(),
620-
)?;
621-
check_valid_signable_account(program_id, new_product_account, PC_PROD_ACC_SIZE as usize)?;
622-
check_valid_fresh_account(new_product_account)?;
604+
check_valid_signable_account(program_id, tail_mapping_account)?;
605+
check_valid_signable_account(program_id, new_product_account)?;
623606

624607
let hdr = load::<CommandHeader>(instruction_data)?;
625608
let mut mapping_data = load_checked::<MappingAccount>(tail_mapping_account, hdr.version)?;
@@ -658,7 +641,7 @@ pub fn upd_product(
658641
}?;
659642

660643
check_valid_funding_account(funding_account)?;
661-
check_valid_signable_account(program_id, product_account, try_convert(PC_PROD_ACC_SIZE)?)?;
644+
check_valid_signable_account(program_id, product_account)?;
662645

663646
let hdr = load::<CommandHeader>(instruction_data)?;
664647
{
@@ -723,7 +706,7 @@ pub fn set_min_pub(
723706
}?;
724707

725708
check_valid_funding_account(funding_account)?;
726-
check_valid_signable_account(program_id, price_account, size_of::<PriceAccount>())?;
709+
check_valid_signable_account(program_id, price_account)?;
727710

728711
let mut price_account_data = load_checked::<PriceAccount>(price_account, cmd.header.version)?;
729712
price_account_data.min_pub_ = cmd.minimum_publishers;
@@ -749,8 +732,8 @@ pub fn del_product(
749732
}?;
750733

751734
check_valid_funding_account(funding_account)?;
752-
check_valid_signable_account(program_id, mapping_account, size_of::<MappingAccount>())?;
753-
check_valid_signable_account(program_id, product_account, PC_PROD_ACC_SIZE as usize)?;
735+
check_valid_signable_account(program_id, mapping_account)?;
736+
check_valid_signable_account(program_id, product_account)?;
754737

755738
{
756739
let cmd_args = load::<CommandHeader>(instruction_data)?;

program/rust/src/tests/test_add_product.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ fn test_add_product() {
131131
],
132132
instruction_data
133133
),
134-
Err(OracleError::InvalidSignableAccount.into())
134+
Err(OracleError::AccountTooSmall.into())
135135
);
136136

137137
// test fill up of mapping table

program/rust/src/tests/test_init_mapping.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ fn test_init_mapping() {
134134
&[funding_account.clone(), mapping_account.clone()],
135135
instruction_data
136136
),
137-
Err(OracleError::InvalidSignableAccount.into())
137+
Err(OracleError::AccountTooSmall.into())
138138
);
139139

140140
mapping_account.data = prev_data;

program/rust/src/utils.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,19 @@ pub fn check_valid_funding_account(account: &AccountInfo) -> Result<(), ProgramE
4747
)
4848
}
4949

50-
pub fn valid_signable_account(
51-
program_id: &Pubkey,
52-
account: &AccountInfo,
53-
minimum_size: usize,
54-
) -> bool {
50+
pub fn valid_signable_account(program_id: &Pubkey, account: &AccountInfo) -> bool {
5551
account.is_signer
5652
&& account.is_writable
5753
&& account.owner == program_id
58-
&& account.data_len() >= minimum_size
5954
&& Rent::default().is_exempt(account.lamports(), account.data_len())
6055
}
6156

6257
pub fn check_valid_signable_account(
6358
program_id: &Pubkey,
6459
account: &AccountInfo,
65-
minimum_size: usize,
6660
) -> Result<(), ProgramError> {
6761
pyth_assert(
68-
valid_signable_account(program_id, account, minimum_size),
62+
valid_signable_account(program_id, account),
6963
OracleError::InvalidSignableAccount.into(),
7064
)
7165
}
@@ -138,20 +132,18 @@ pub fn read_pc_str_t(source: &[u8]) -> Result<&[u8], ProgramError> {
138132
}
139133
}
140134

141-
fn valid_writable_account(program_id: &Pubkey, account: &AccountInfo, minimum_size: usize) -> bool {
135+
fn valid_writable_account(program_id: &Pubkey, account: &AccountInfo) -> bool {
142136
account.is_writable
143137
&& account.owner == program_id
144-
&& account.data_len() >= minimum_size
145138
&& Rent::default().is_exempt(account.lamports(), account.data_len())
146139
}
147140

148141
pub fn check_valid_writable_account(
149142
program_id: &Pubkey,
150143
account: &AccountInfo,
151-
minimum_size: usize,
152144
) -> Result<(), ProgramError> {
153145
pyth_assert(
154-
valid_writable_account(program_id, account, minimum_size),
146+
valid_writable_account(program_id, account),
155147
OracleError::InvalidWritableAccount.into(),
156148
)
157149
}

0 commit comments

Comments
 (0)