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;
3
19
use solana_program:: pubkey:: Pubkey ;
20
+ use solana_program:: rent:: Rent ;
4
21
use solana_program:: sysvar:: slot_history:: AccountInfo ;
5
22
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
+
6
34
///Calls the c oracle update_price, and updates the Time Machine if needed
7
35
pub fn update_price (
8
36
_program_id : & Pubkey ,
@@ -23,4 +51,102 @@ pub fn update_version(
23
51
_instruction_data : & [ u8 ] ,
24
52
) -> OracleResult {
25
53
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
+ } ) )
26
152
}
0 commit comments