@@ -13,12 +13,12 @@ use bytemuck::{
1313 try_from_bytes_mut,
1414 Pod ,
1515} ;
16+ use solana_program:: account_info:: AccountInfo ;
1617use solana_program:: entrypoint:: SUCCESS ;
1718use solana_program:: program_error:: ProgramError ;
1819use solana_program:: program_memory:: sol_memset;
1920use solana_program:: pubkey:: Pubkey ;
2021use solana_program:: rent:: Rent ;
21- use solana_program:: sysvar:: slot_history:: AccountInfo ;
2222
2323use crate :: c_oracle_header:: {
2424 cmd_add_price_t,
@@ -31,12 +31,15 @@ use crate::c_oracle_header::{
3131 PC_ACCTYPE_PRICE ,
3232 PC_ACCTYPE_PRODUCT ,
3333 PC_MAGIC ,
34+ PC_MAP_TABLE_SIZE ,
3435 PC_MAX_NUM_DECIMALS ,
3536 PC_PROD_ACC_SIZE ,
3637 PC_PTYPE_UNKNOWN ,
3738} ;
3839use crate :: error:: OracleResult ;
3940
41+ use crate :: utils:: pyth_assert;
42+
4043use super :: c_entrypoint_wrapper;
4144
4245///Calls the c oracle update_price, and updates the Time Machine if needed
@@ -83,14 +86,44 @@ pub fn init_mapping(
8386 } ?;
8487
8588 // Initialize by setting to zero again (just in case) and populating the account header
86- clear_account ( fresh_mapping_account) ?;
89+ let hdr = load :: < cmd_hdr_t > ( instruction_data) ?;
90+ initialize_mapping_account ( fresh_mapping_account, hdr. ver_ ) ?;
91+
92+ Ok ( SUCCESS )
93+ }
94+
95+ pub fn add_mapping (
96+ program_id : & Pubkey ,
97+ accounts : & [ AccountInfo ] ,
98+ instruction_data : & [ u8 ] ,
99+ ) -> OracleResult {
100+ let [ _funding_account, cur_mapping, next_mapping] = match accounts {
101+ [ x, y, z]
102+ if valid_funding_account ( x)
103+ && valid_signable_account ( program_id, y, size_of :: < pc_map_table_t > ( ) )
104+ && valid_signable_account ( program_id, z, size_of :: < pc_map_table_t > ( ) )
105+ && valid_fresh_account ( z) =>
106+ {
107+ Ok ( [ x, y, z] )
108+ }
109+ _ => Err ( ProgramError :: InvalidArgument ) ,
110+ } ?;
87111
88112 let hdr = load :: < cmd_hdr_t > ( instruction_data) ?;
89- let mut mapping_data = load_account_as_mut :: < pc_map_table_t > ( fresh_mapping_account) ?;
90- mapping_data. magic_ = PC_MAGIC ;
91- mapping_data. ver_ = hdr. ver_ ;
92- mapping_data. type_ = PC_ACCTYPE_MAPPING ;
93- mapping_data. size_ = ( size_of :: < pc_map_table_t > ( ) - size_of_val ( & mapping_data. prod_ ) ) as u32 ;
113+ let mut cur_mapping = load_mapping_account_mut ( cur_mapping, hdr. ver_ ) ?;
114+ pyth_assert (
115+ cur_mapping. num_ == PC_MAP_TABLE_SIZE
116+ && unsafe { cur_mapping. next_ . k8_ . iter ( ) . all ( |x| * x == 0 ) } ,
117+ ProgramError :: InvalidArgument ,
118+ ) ?;
119+
120+ initialize_mapping_account ( next_mapping, hdr. ver_ ) ?;
121+ unsafe {
122+ cur_mapping
123+ . next_
124+ . k1_
125+ . copy_from_slice ( & next_mapping. key . to_bytes ( ) ) ;
126+ }
94127
95128 Ok ( SUCCESS )
96129}
@@ -180,7 +213,7 @@ fn valid_fresh_account(account: &AccountInfo) -> bool {
180213}
181214
182215/// Sets the data of account to all-zero
183- fn clear_account ( account : & AccountInfo ) -> Result < ( ) , ProgramError > {
216+ pub fn clear_account ( account : & AccountInfo ) -> Result < ( ) , ProgramError > {
184217 let mut data = account
185218 . try_borrow_mut_data ( )
186219 . map_err ( |_| ProgramError :: InvalidArgument ) ?;
@@ -201,7 +234,7 @@ fn load_mut<T: Pod>(data: &mut [u8]) -> Result<&mut T, ProgramError> {
201234}
202235
203236/// Get the data stored in `account` as a value of type `T`
204- fn load_account_as < ' a , T : Pod > ( account : & ' a AccountInfo ) -> Result < Ref < ' a , T > , ProgramError > {
237+ pub fn load_account_as < ' a , T : Pod > ( account : & ' a AccountInfo ) -> Result < Ref < ' a , T > , ProgramError > {
205238 let data = account. try_borrow_data ( ) ?;
206239
207240 Ok ( Ref :: map ( data, |data| {
@@ -211,7 +244,7 @@ fn load_account_as<'a, T: Pod>(account: &'a AccountInfo) -> Result<Ref<'a, T>, P
211244
212245/// Mutably borrow the data in `account` as a value of type `T`.
213246/// Any mutations to the returned value will be reflected in the account data.
214- fn load_account_as_mut < ' a , T : Pod > (
247+ pub fn load_account_as_mut < ' a , T : Pod > (
215248 account : & ' a AccountInfo ,
216249) -> Result < RefMut < ' a , T > , ProgramError > {
217250 let data = account. try_borrow_mut_data ( ) ?;
@@ -220,3 +253,38 @@ fn load_account_as_mut<'a, T: Pod>(
220253 bytemuck:: from_bytes_mut ( & mut data[ 0 ..size_of :: < T > ( ) ] )
221254 } ) )
222255}
256+
257+ /// Mutably borrow the data in `account` as a mapping account, validating that the account
258+ /// is properly formatted. Any mutations to the returned value will be reflected in the
259+ /// account data. Use this to read already-initialized accounts.
260+ fn load_mapping_account_mut < ' a > (
261+ account : & ' a AccountInfo ,
262+ expected_version : u32 ,
263+ ) -> Result < RefMut < ' a , pc_map_table_t > , ProgramError > {
264+ let mapping_account_ref = load_account_as_mut :: < pc_map_table_t > ( account) ?;
265+ let mapping_account = * mapping_account_ref;
266+
267+ pyth_assert (
268+ mapping_account. magic_ == PC_MAGIC
269+ && mapping_account. ver_ == expected_version
270+ && mapping_account. type_ == PC_ACCTYPE_MAPPING ,
271+ ProgramError :: InvalidArgument ,
272+ ) ?;
273+
274+ Ok ( mapping_account_ref)
275+ }
276+
277+ /// Initialize account as a new mapping account. This function will zero out any existing data in
278+ /// the account.
279+ fn initialize_mapping_account ( account : & AccountInfo , version : u32 ) -> Result < ( ) , ProgramError > {
280+ clear_account ( account) ?;
281+
282+ let mut mapping_account = load_account_as_mut :: < pc_map_table_t > ( account) ?;
283+ mapping_account. magic_ = PC_MAGIC ;
284+ mapping_account. ver_ = version;
285+ mapping_account. type_ = PC_ACCTYPE_MAPPING ;
286+ mapping_account. size_ =
287+ ( size_of :: < pc_map_table_t > ( ) - size_of_val ( & mapping_account. prod_ ) ) as u32 ;
288+
289+ Ok ( ( ) )
290+ }
0 commit comments