@@ -26,9 +26,12 @@ use crate::c_oracle_header::{
2626 pc_map_table_t,
2727 PC_ACCTYPE_MAPPING ,
2828 PC_MAGIC ,
29+ PC_MAP_TABLE_SIZE ,
2930} ;
3031use crate :: error:: OracleResult ;
3132
33+ use crate :: utils:: pyth_assert;
34+
3235use super :: c_entrypoint_wrapper;
3336
3437///Calls the c oracle update_price, and updates the Time Machine if needed
@@ -75,14 +78,44 @@ pub fn init_mapping(
7578 } ?;
7679
7780 // Initialize by setting to zero again (just in case) and populating the account header
78- clear_account ( fresh_mapping_account) ?;
81+ let hdr = load :: < cmd_hdr_t > ( instruction_data) ?;
82+ initialize_mapping_account ( fresh_mapping_account, hdr. ver_ ) ?;
83+
84+ Ok ( SUCCESS )
85+ }
86+
87+ pub fn add_mapping (
88+ program_id : & Pubkey ,
89+ accounts : & [ AccountInfo ] ,
90+ instruction_data : & [ u8 ] ,
91+ ) -> OracleResult {
92+ let [ _funding_account, cur_mapping, next_mapping] = match accounts {
93+ [ x, y, z]
94+ if valid_funding_account ( x)
95+ && valid_signable_account ( program_id, y, size_of :: < pc_map_table_t > ( ) )
96+ && valid_signable_account ( program_id, z, size_of :: < pc_map_table_t > ( ) )
97+ && valid_fresh_account ( z) =>
98+ {
99+ Ok ( [ x, y, z] )
100+ }
101+ _ => Err ( ProgramError :: InvalidArgument ) ,
102+ } ?;
79103
80104 let hdr = load :: < cmd_hdr_t > ( instruction_data) ?;
81- let mut mapping_data = load_account_as_mut :: < pc_map_table_t > ( fresh_mapping_account) ?;
82- mapping_data. magic_ = PC_MAGIC ;
83- mapping_data. ver_ = hdr. ver_ ;
84- mapping_data. type_ = PC_ACCTYPE_MAPPING ;
85- mapping_data. size_ = ( size_of :: < pc_map_table_t > ( ) - size_of_val ( & mapping_data. prod_ ) ) as u32 ;
105+ let mut cur_mapping = load_mapping_account_mut ( cur_mapping, hdr. ver_ ) ?;
106+ pyth_assert (
107+ cur_mapping. num_ == PC_MAP_TABLE_SIZE
108+ && unsafe { cur_mapping. next_ . k8_ . iter ( ) . all ( |x| * x == 0 ) } ,
109+ ProgramError :: InvalidArgument ,
110+ ) ?;
111+
112+ initialize_mapping_account ( next_mapping, hdr. ver_ ) ?;
113+ unsafe {
114+ cur_mapping
115+ . next_
116+ . k1_
117+ . copy_from_slice ( & next_mapping. key . to_bytes ( ) ) ;
118+ }
86119
87120 Ok ( SUCCESS )
88121}
@@ -150,3 +183,38 @@ fn load_account_as_mut<'a, T: Pod>(
150183 bytemuck:: from_bytes_mut ( & mut data[ 0 ..size_of :: < T > ( ) ] )
151184 } ) )
152185}
186+
187+ /// Mutably borrow the data in `account` as a mapping account, validating that the account
188+ /// is properly formatted. Any mutations to the returned value will be reflected in the
189+ /// account data. Use this to read already-initialized accounts.
190+ fn load_mapping_account_mut < ' a > (
191+ account : & ' a AccountInfo ,
192+ expected_version : u32 ,
193+ ) -> Result < RefMut < ' a , pc_map_table_t > , ProgramError > {
194+ let mapping_account_ref = load_account_as_mut :: < pc_map_table_t > ( account) ?;
195+ let mapping_account = * mapping_account_ref;
196+
197+ pyth_assert (
198+ mapping_account. magic_ == PC_MAGIC
199+ && mapping_account. ver_ == expected_version
200+ && mapping_account. type_ == PC_ACCTYPE_MAPPING ,
201+ ProgramError :: InvalidArgument ,
202+ ) ?;
203+
204+ Ok ( mapping_account_ref)
205+ }
206+
207+ /// Initialize account as a new mapping account. This function will zero out any existing data in
208+ /// the account.
209+ fn initialize_mapping_account ( account : & AccountInfo , version : u32 ) -> Result < ( ) , ProgramError > {
210+ clear_account ( account) ?;
211+
212+ let mut mapping_account = load_account_as_mut :: < pc_map_table_t > ( account) ?;
213+ mapping_account. magic_ = PC_MAGIC ;
214+ mapping_account. ver_ = version;
215+ mapping_account. type_ = PC_ACCTYPE_MAPPING ;
216+ mapping_account. size_ =
217+ ( size_of :: < pc_map_table_t > ( ) - size_of_val ( & mapping_account. prod_ ) ) as u32 ;
218+
219+ Ok ( ( ) )
220+ }
0 commit comments