@@ -19,6 +19,13 @@ use solana_program::program_memory::{
1919use solana_program:: pubkey:: Pubkey ;
2020use solana_program:: rent:: Rent ;
2121
22+
23+ use crate :: time_machine_types:: PriceAccountWrapper ;
24+ use solana_program:: program:: invoke;
25+ use solana_program:: system_instruction:: transfer;
26+ use solana_program:: system_program:: check_id;
27+
28+
2229use crate :: c_oracle_header:: {
2330 cmd_add_price_t,
2431 cmd_add_publisher_t,
@@ -42,41 +49,121 @@ use crate::c_oracle_header::{
4249 PC_MAX_NUM_DECIMALS ,
4350 PC_PROD_ACC_SIZE ,
4451 PC_PTYPE_UNKNOWN ,
52+ PC_VERSION ,
53+ SUCCESSFULLY_UPDATED_AGGREGATE ,
4554} ;
4655use crate :: deserialize:: {
4756 load,
4857 load_account_as,
4958 load_account_as_mut,
5059} ;
5160use crate :: error:: OracleResult ;
52- use crate :: utils:: pyth_assert;
5361use crate :: OracleError ;
5462
63+ use crate :: utils:: pyth_assert;
64+
5565use super :: c_entrypoint_wrapper;
66+ const PRICE_T_SIZE : usize = size_of :: < pc_price_t > ( ) ;
67+ const PRICE_ACCOUNT_SIZE : usize = size_of :: < PriceAccountWrapper > ( ) ;
68+
5669
5770///Calls the c oracle update_price, and updates the Time Machine if needed
5871pub fn update_price (
5972 _program_id : & Pubkey ,
60- _accounts : & [ AccountInfo ] ,
73+ accounts : & [ AccountInfo ] ,
6174 _instruction_data : & [ u8 ] ,
6275 input : * mut u8 ,
6376) -> OracleResult {
64- //For now, we did not change the behavior of this. this is just to show the proposed structure
65- // of the program
66- c_entrypoint_wrapper ( input)
77+ let c_ret_value = c_entrypoint_wrapper ( input) ?;
78+ let price_account_info = & accounts[ 1 ] ;
79+ //accounts checks happen in c_entrypoint
80+ let account_len = price_account_info. try_data_len ( ) ?;
81+ match account_len {
82+ PRICE_T_SIZE => Ok ( c_ret_value) ,
83+ PRICE_ACCOUNT_SIZE => {
84+ if c_ret_value == SUCCESSFULLY_UPDATED_AGGREGATE {
85+ let mut price_account =
86+ load_account_as_mut :: < PriceAccountWrapper > ( price_account_info) ?;
87+ price_account. add_price_to_time_machine ( ) ?;
88+ }
89+ Ok ( c_ret_value)
90+ }
91+ _ => Err ( ProgramError :: InvalidArgument ) ,
92+ }
6793}
68- /// has version number/ account type dependant logic to make sure the given account is compatible
69- /// with the current version
70- /// updates the version number for all accounts, and resizes price accounts
71- pub fn update_version (
72- _program_id : & Pubkey ,
73- _accounts : & [ AccountInfo ] ,
94+ fn send_lamports < ' a > (
95+ from : & AccountInfo < ' a > ,
96+ to : & AccountInfo < ' a > ,
97+ system_program : & AccountInfo < ' a > ,
98+ amount : u64 ,
99+ ) -> Result < ( ) , ProgramError > {
100+ let transfer_instruction = transfer ( from. key , to. key , amount) ;
101+ invoke (
102+ & transfer_instruction,
103+ & [ from. clone ( ) , to. clone ( ) , system_program. clone ( ) ] ,
104+ ) ?;
105+ Ok ( ( ) )
106+ }
107+
108+ /// resizes a price account so that it fits the Time Machine
109+ /// key[0] funding account [signer writable]
110+ /// key[1] price account [Signer writable]
111+ /// key[2] system program [readable]
112+ pub fn resize_price_account (
113+ program_id : & Pubkey ,
114+ accounts : & [ AccountInfo ] ,
74115 _instruction_data : & [ u8 ] ,
75116) -> OracleResult {
76- panic ! ( "Need to merge fix to pythd in order to implement this" ) ;
77- // Ok(SUCCESS)
117+ let [ funding_account_info, price_account_info, system_program] = match accounts {
118+ [ x, y, z] => Ok ( [ x, y, z] ) ,
119+ _ => Err ( ProgramError :: InvalidArgument ) ,
120+ } ?;
121+
122+ check_valid_funding_account ( funding_account_info) ?;
123+ check_valid_signable_account ( program_id, price_account_info, size_of :: < pc_price_t > ( ) ) ?;
124+ pyth_assert (
125+ check_id ( system_program. key ) ,
126+ OracleError :: InvalidSystemAccount . into ( ) ,
127+ ) ?;
128+ //throw an error if not a price account
129+ //need to makre sure it goes out of scope immediatly to avoid mutable borrow errors
130+ {
131+ load_checked :: < pc_price_t > ( price_account_info, PC_VERSION ) ?;
132+ }
133+ let account_len = price_account_info. try_data_len ( ) ?;
134+ match account_len {
135+ PRICE_T_SIZE => {
136+ //ensure account is still rent exempt after resizing
137+ let rent: Rent = Default :: default ( ) ;
138+ let lamports_needed: u64 = rent
139+ . minimum_balance ( size_of :: < PriceAccountWrapper > ( ) )
140+ . saturating_sub ( price_account_info. lamports ( ) ) ;
141+ if lamports_needed > 0 {
142+ send_lamports (
143+ funding_account_info,
144+ price_account_info,
145+ system_program,
146+ lamports_needed,
147+ ) ?;
148+ }
149+ //resize
150+ //we do not need to zero initialize since this is the first time this memory
151+ //is allocated
152+ price_account_info. realloc ( size_of :: < PriceAccountWrapper > ( ) , false ) ?;
153+ //The load below would fail if the account was not a price account, reverting the whole
154+ // transaction
155+ let mut price_account =
156+ load_checked :: < PriceAccountWrapper > ( price_account_info, PC_VERSION ) ?;
157+ //Initialize Time Machine
158+ price_account. initialize_time_machine ( ) ?;
159+ Ok ( SUCCESS )
160+ }
161+ PRICE_ACCOUNT_SIZE => Ok ( SUCCESS ) ,
162+ _ => Err ( ProgramError :: InvalidArgument ) ,
163+ }
78164}
79165
166+
80167/// initialize the first mapping account in a new linked-list of mapping accounts
81168/// accounts[0] funding account [signer writable]
82169/// accounts[1] new mapping account [signer writable]
@@ -150,6 +237,7 @@ pub fn add_price(
150237 ProgramError :: InvalidArgument ,
151238 ) ?;
152239
240+
153241 let [ funding_account, product_account, price_account] = match accounts {
154242 [ x, y, z] => Ok ( [ x, y, z] ) ,
155243 _ => Err ( ProgramError :: InvalidArgument ) ,
0 commit comments