@@ -26,9 +26,12 @@ use crate::c_oracle_header::{
26
26
pc_map_table_t,
27
27
PC_ACCTYPE_MAPPING ,
28
28
PC_MAGIC ,
29
+ PC_MAP_TABLE_SIZE ,
29
30
} ;
30
31
use crate :: error:: OracleResult ;
31
32
33
+ use crate :: utils:: pyth_assert;
34
+
32
35
use super :: c_entrypoint_wrapper;
33
36
34
37
///Calls the c oracle update_price, and updates the Time Machine if needed
@@ -75,14 +78,44 @@ pub fn init_mapping(
75
78
} ?;
76
79
77
80
// 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
+ } ?;
79
103
80
104
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
+ }
86
119
87
120
Ok ( SUCCESS )
88
121
}
@@ -150,3 +183,38 @@ fn load_account_as_mut<'a, T: Pod>(
150
183
bytemuck:: from_bytes_mut ( & mut data[ 0 ..size_of :: < T > ( ) ] )
151
184
} ) )
152
185
}
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