1- use super :: c_entrypoint_wrapper;
2- use crate :: error:: OracleResult ;
1+ use std:: borrow:: BorrowMut ;
2+ use std:: cell:: {
3+ Ref ,
4+ RefMut ,
5+ } ;
6+ use std:: mem:: {
7+ size_of,
8+ size_of_val,
9+ } ;
10+
11+ use bytemuck:: {
12+ try_from_bytes,
13+ try_from_bytes_mut,
14+ Pod ,
15+ } ;
16+ use solana_program:: entrypoint:: SUCCESS ;
17+ use solana_program:: program_error:: ProgramError ;
18+ use solana_program:: program_memory:: sol_memset;
319use solana_program:: pubkey:: Pubkey ;
20+ use solana_program:: rent:: Rent ;
421use solana_program:: sysvar:: slot_history:: AccountInfo ;
522
23+ use crate :: c_oracle_header:: {
24+ cmd_hdr_t,
25+ pc_acc,
26+ pc_map_table_t,
27+ PC_ACCTYPE_MAPPING ,
28+ PC_MAGIC ,
29+ } ;
30+ use crate :: error:: OracleResult ;
31+
32+ use super :: c_entrypoint_wrapper;
33+
634///Calls the c oracle update_price, and updates the Time Machine if needed
735pub fn update_price (
836 _program_id : & Pubkey ,
@@ -23,4 +51,102 @@ pub fn update_version(
2351 _instruction_data : & [ u8 ] ,
2452) -> OracleResult {
2553 panic ! ( "Need to merge fix to pythd in order to implement this" ) ;
54+ // Ok(SUCCESS)
55+ }
56+
57+
58+ /// initialize the first mapping account in a new linked-list of mapping accounts
59+ /// accounts[0] funding account [signer writable]
60+ /// accounts[1] new mapping account [signer writable]
61+ pub fn init_mapping (
62+ program_id : & Pubkey ,
63+ accounts : & [ AccountInfo ] ,
64+ instruction_data : & [ u8 ] ,
65+ ) -> OracleResult {
66+ let [ _funding_account, fresh_mapping_account] = match accounts {
67+ [ x, y]
68+ if valid_funding_account ( x)
69+ && valid_signable_account ( program_id, y, size_of :: < pc_map_table_t > ( ) )
70+ && valid_fresh_account ( y) =>
71+ {
72+ Ok ( [ x, y] )
73+ }
74+ _ => Err ( ProgramError :: InvalidArgument ) ,
75+ } ?;
76+
77+ // Initialize by setting to zero again (just in case) and populating the account header
78+ clear_account ( fresh_mapping_account) ?;
79+
80+ 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 ;
86+
87+ Ok ( SUCCESS )
88+ }
89+
90+ fn valid_funding_account ( account : & AccountInfo ) -> bool {
91+ account. is_signer && account. is_writable
92+ }
93+
94+ fn valid_signable_account ( program_id : & Pubkey , account : & AccountInfo , minimum_size : usize ) -> bool {
95+ account. is_signer
96+ && account. is_writable
97+ && account. owner == program_id
98+ && account. data_len ( ) >= minimum_size
99+ && Rent :: default ( ) . is_exempt ( account. lamports ( ) , account. data_len ( ) )
100+ }
101+
102+ /// Returns `true` if the `account` is fresh, i.e., its data can be overwritten.
103+ /// Use this check to prevent accidentally overwriting accounts whose data is already populated.
104+ fn valid_fresh_account ( account : & AccountInfo ) -> bool {
105+ let pyth_acc = load_account_as :: < pc_acc > ( account) ;
106+ match pyth_acc {
107+ Ok ( pyth_acc) => pyth_acc. magic_ == 0 && pyth_acc. ver_ == 0 ,
108+ Err ( _) => false ,
109+ }
110+ }
111+
112+ /// Sets the data of account to all-zero
113+ fn clear_account ( account : & AccountInfo ) -> Result < ( ) , ProgramError > {
114+ let mut data = account
115+ . try_borrow_mut_data ( )
116+ . map_err ( |_| ProgramError :: InvalidArgument ) ?;
117+ let length = data. len ( ) ;
118+ sol_memset ( data. borrow_mut ( ) , 0 , length) ;
119+ Ok ( ( ) )
120+ }
121+
122+ /// Interpret the bytes in `data` as a value of type `T`
123+ fn load < T : Pod > ( data : & [ u8 ] ) -> Result < & T , ProgramError > {
124+ try_from_bytes ( & data[ 0 ..size_of :: < T > ( ) ] ) . map_err ( |_| ProgramError :: InvalidArgument )
125+ }
126+
127+ /// Interpret the bytes in `data` as a mutable value of type `T`
128+ #[ allow( unused) ]
129+ fn load_mut < T : Pod > ( data : & mut [ u8 ] ) -> Result < & mut T , ProgramError > {
130+ try_from_bytes_mut ( & mut data[ 0 ..size_of :: < T > ( ) ] ) . map_err ( |_| ProgramError :: InvalidArgument )
131+ }
132+
133+ /// Get the data stored in `account` as a value of type `T`
134+ fn load_account_as < ' a , T : Pod > ( account : & ' a AccountInfo ) -> Result < Ref < ' a , T > , ProgramError > {
135+ let data = account. try_borrow_data ( ) ?;
136+
137+ Ok ( Ref :: map ( data, |data| {
138+ bytemuck:: from_bytes ( & data[ 0 ..size_of :: < T > ( ) ] )
139+ } ) )
140+ }
141+
142+ /// Mutably borrow the data in `account` as a value of type `T`.
143+ /// Any mutations to the returned value will be reflected in the account data.
144+ fn load_account_as_mut < ' a , T : Pod > (
145+ account : & ' a AccountInfo ,
146+ ) -> Result < RefMut < ' a , T > , ProgramError > {
147+ let data = account. try_borrow_mut_data ( ) ?;
148+
149+ Ok ( RefMut :: map ( data, |data| {
150+ bytemuck:: from_bytes_mut ( & mut data[ 0 ..size_of :: < T > ( ) ] )
151+ } ) )
26152}
0 commit comments