Skip to content

Commit b1b202c

Browse files
authored
Merge branch 'main' into remove-borsh
2 parents aa938ab + 608d2ed commit b1b202c

File tree

3 files changed

+105
-11
lines changed

3 files changed

+105
-11
lines changed

program/rust/src/c_oracle_header.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ unsafe impl Pod for cmd_hdr {
5353
}
5454

5555
#[cfg(target_endian = "little")]
56+
5657
unsafe impl Zeroable for pc_price_info {
5758
}
5859

@@ -74,4 +75,19 @@ unsafe impl Zeroable for pc_ema {
7475

7576
#[cfg(target_endian = "little")]
7677
unsafe impl Pod for pc_ema {
78+
79+
unsafe impl Zeroable for cmd_add_price_t {
80+
}
81+
82+
#[cfg(target_endian = "little")]
83+
unsafe impl Pod for cmd_add_price_t {
84+
}
85+
86+
#[cfg(target_endian = "little")]
87+
unsafe impl Zeroable for pc_pub_key_t {
88+
}
89+
90+
#[cfg(target_endian = "little")]
91+
unsafe impl Pod for pc_pub_key_t {
92+
7793
}

program/rust/src/processor.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::c_entrypoint_wrapper;
88
use crate::c_oracle_header::{
99
cmd_hdr,
1010
command_t_e_cmd_add_mapping,
11+
command_t_e_cmd_add_price,
1112
command_t_e_cmd_agg_price,
1213
command_t_e_cmd_init_mapping,
1314
command_t_e_cmd_upd_account_version,
@@ -21,6 +22,7 @@ use crate::error::{
2122
};
2223
use crate::rust_oracle::{
2324
add_mapping,
25+
add_price,
2426
init_mapping,
2527
update_price,
2628
update_version,
@@ -58,6 +60,7 @@ pub fn process_instruction(
5860
command_t_e_cmd_upd_account_version => {
5961
update_version(program_id, accounts, instruction_data)
6062
}
63+
command_t_e_cmd_add_price => add_price(program_id, accounts, instruction_data),
6164
command_t_e_cmd_init_mapping => init_mapping(program_id, accounts, instruction_data),
6265
command_t_e_cmd_add_mapping => add_mapping(program_id, accounts, instruction_data),
6366
_ => c_entrypoint_wrapper(input),

program/rust/src/rust_oracle.rs

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,21 @@ use solana_program::pubkey::Pubkey;
2020
use solana_program::rent::Rent;
2121

2222
use crate::c_oracle_header::{
23+
cmd_add_price_t,
2324
cmd_hdr_t,
2425
pc_acc,
2526
pc_map_table_t,
27+
pc_price_t,
28+
pc_prod_t,
29+
pc_pub_key_t,
2630
PC_ACCTYPE_MAPPING,
31+
PC_ACCTYPE_PRICE,
32+
PC_ACCTYPE_PRODUCT,
2733
PC_MAGIC,
2834
PC_MAP_TABLE_SIZE,
35+
PC_MAX_NUM_DECIMALS,
36+
PC_PROD_ACC_SIZE,
37+
PC_PTYPE_UNKNOWN,
2938
};
3039
use crate::error::OracleResult;
3140

@@ -109,13 +118,56 @@ pub fn add_mapping(
109118
)?;
110119

111120
initialize_mapping_account(next_mapping, hdr.ver_)?;
112-
unsafe {
113-
cur_mapping
114-
.next_
115-
.k1_
116-
.copy_from_slice(&next_mapping.key.to_bytes());
121+
pubkey_assign(&mut cur_mapping.next_, &next_mapping.key.to_bytes());
122+
123+
Ok(SUCCESS)
124+
}
125+
126+
/// add a price account to a product account
127+
/// accounts[0] funding account [signer writable]
128+
/// accounts[1] product account to add the price account to [signer writable]
129+
/// accounts[2] newly created price account [signer writable]
130+
pub fn add_price(
131+
program_id: &Pubkey,
132+
accounts: &[AccountInfo],
133+
instruction_data: &[u8],
134+
) -> OracleResult {
135+
let cmd_args = load::<cmd_add_price_t>(instruction_data)?;
136+
137+
if cmd_args.expo_ > PC_MAX_NUM_DECIMALS as i32
138+
|| cmd_args.expo_ < -(PC_MAX_NUM_DECIMALS as i32)
139+
|| cmd_args.ptype_ == PC_PTYPE_UNKNOWN
140+
{
141+
return Err(ProgramError::InvalidArgument);
117142
}
118143

144+
let [_funding_account, product_account, price_account] = match accounts {
145+
[x, y, z]
146+
if valid_funding_account(x)
147+
&& valid_signable_account(program_id, y, PC_PROD_ACC_SIZE as usize)
148+
&& valid_signable_account(program_id, z, size_of::<pc_price_t>())
149+
&& valid_fresh_account(z) =>
150+
{
151+
Ok([x, y, z])
152+
}
153+
_ => Err(ProgramError::InvalidArgument),
154+
}?;
155+
156+
let mut product_data = load_product_account_mut(product_account, cmd_args.ver_)?;
157+
158+
clear_account(price_account)?;
159+
160+
let mut price_data = load_account_as_mut::<pc_price_t>(price_account)?;
161+
price_data.magic_ = PC_MAGIC;
162+
price_data.ver_ = cmd_args.ver_;
163+
price_data.type_ = PC_ACCTYPE_PRICE;
164+
price_data.size_ = (size_of::<pc_price_t>() - size_of_val(&price_data.comp_)) as u32;
165+
price_data.expo_ = cmd_args.expo_;
166+
price_data.ptype_ = cmd_args.ptype_;
167+
pubkey_assign(&mut price_data.prod_, &product_account.key.to_bytes());
168+
pubkey_assign(&mut price_data.next_, bytes_of(&product_data.px_acc_));
169+
pubkey_assign(&mut product_data.px_acc_, &price_account.key.to_bytes());
170+
119171
Ok(SUCCESS)
120172
}
121173

@@ -159,17 +211,16 @@ fn load_mapping_account_mut<'a>(
159211
account: &'a AccountInfo,
160212
expected_version: u32,
161213
) -> Result<RefMut<'a, pc_map_table_t>, ProgramError> {
162-
let mapping_account_ref = load_account_as_mut::<pc_map_table_t>(account)?;
163-
let mapping_account = *mapping_account_ref;
214+
let mapping_data = load_account_as_mut::<pc_map_table_t>(account)?;
164215

165216
pyth_assert(
166-
mapping_account.magic_ == PC_MAGIC
167-
&& mapping_account.ver_ == expected_version
168-
&& mapping_account.type_ == PC_ACCTYPE_MAPPING,
217+
mapping_data.magic_ == PC_MAGIC
218+
&& mapping_data.ver_ == expected_version
219+
&& mapping_data.type_ == PC_ACCTYPE_MAPPING,
169220
ProgramError::InvalidArgument,
170221
)?;
171222

172-
Ok(mapping_account_ref)
223+
Ok(mapping_data)
173224
}
174225

175226
/// Initialize account as a new mapping account. This function will zero out any existing data in
@@ -186,3 +237,27 @@ fn initialize_mapping_account(account: &AccountInfo, version: u32) -> Result<(),
186237

187238
Ok(())
188239
}
240+
241+
/// Mutably borrow the data in `account` as a product account, validating that the account
242+
/// is properly formatted. Any mutations to the returned value will be reflected in the
243+
/// account data. Use this to read already-initialized accounts.
244+
fn load_product_account_mut<'a>(
245+
account: &'a AccountInfo,
246+
expected_version: u32,
247+
) -> Result<RefMut<'a, pc_prod_t>, ProgramError> {
248+
let product_data = load_account_as_mut::<pc_prod_t>(account)?;
249+
250+
pyth_assert(
251+
product_data.magic_ == PC_MAGIC
252+
&& product_data.ver_ == expected_version
253+
&& product_data.type_ == PC_ACCTYPE_PRODUCT,
254+
ProgramError::InvalidArgument,
255+
)?;
256+
257+
Ok(product_data)
258+
}
259+
260+
// Assign pubkey bytes from source to target, fails if source is not 32 bytes
261+
fn pubkey_assign(target: &mut pc_pub_key_t, source: &[u8]) {
262+
unsafe { target.k1_.copy_from_slice(source) }
263+
}

0 commit comments

Comments
 (0)