@@ -19,6 +19,13 @@ use solana_program::program_memory::{
19
19
use solana_program:: pubkey:: Pubkey ;
20
20
use solana_program:: rent:: Rent ;
21
21
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
+
22
29
use crate :: c_oracle_header:: {
23
30
cmd_add_price_t,
24
31
cmd_add_publisher_t,
@@ -42,41 +49,121 @@ use crate::c_oracle_header::{
42
49
PC_MAX_NUM_DECIMALS ,
43
50
PC_PROD_ACC_SIZE ,
44
51
PC_PTYPE_UNKNOWN ,
52
+ PC_VERSION ,
53
+ SUCCESSFULLY_UPDATED_AGGREGATE ,
45
54
} ;
46
55
use crate :: deserialize:: {
47
56
load,
48
57
load_account_as,
49
58
load_account_as_mut,
50
59
} ;
51
60
use crate :: error:: OracleResult ;
52
- use crate :: utils:: pyth_assert;
53
61
use crate :: OracleError ;
54
62
63
+ use crate :: utils:: pyth_assert;
64
+
55
65
use 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
+
56
69
57
70
///Calls the c oracle update_price, and updates the Time Machine if needed
58
71
pub fn update_price (
59
72
_program_id : & Pubkey ,
60
- _accounts : & [ AccountInfo ] ,
73
+ accounts : & [ AccountInfo ] ,
61
74
_instruction_data : & [ u8 ] ,
62
75
input : * mut u8 ,
63
76
) -> 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
+ }
67
93
}
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 ] ,
74
115
_instruction_data : & [ u8 ] ,
75
116
) -> 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
+ }
78
164
}
79
165
166
+
80
167
/// initialize the first mapping account in a new linked-list of mapping accounts
81
168
/// accounts[0] funding account [signer writable]
82
169
/// accounts[1] new mapping account [signer writable]
@@ -150,6 +237,7 @@ pub fn add_price(
150
237
ProgramError :: InvalidArgument ,
151
238
) ?;
152
239
240
+
153
241
let [ funding_account, product_account, price_account] = match accounts {
154
242
[ x, y, z] => Ok ( [ x, y, z] ) ,
155
243
_ => Err ( ProgramError :: InvalidArgument ) ,
0 commit comments