Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion program/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ bindgen = "0.60.1"

[dependencies]
solana-program = "=1.10.29"
borsh = "0.9"
bytemuck = "1.11.0"
thiserror = "1.0"

Expand Down
9 changes: 1 addition & 8 deletions program/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,8 @@ use bindgen::Builder;
fn main() {
println!("cargo:rustc-link-search=./program/c/target");

let borsh_derives = ["BorshSerialize".to_string(), "BorshDeserialize".to_string()];

//make a parser and to it type, traits pairs
let mut parser = build_utils::DeriveAdderParserCallback::new();
parser.register_traits("cmd_hdr", borsh_derives.to_vec());
parser.register_traits("pc_acc", borsh_derives.to_vec());
parser.register_traits("pc_price_info", borsh_derives.to_vec());
parser.register_traits("cmd_upd_price", borsh_derives.to_vec());
parser.register_traits("pc_ema", borsh_derives.to_vec());
let parser = build_utils::DeriveAdderParserCallback::new();

//generate and write bindings
let bindings = Builder::default()
Expand Down
1 change: 1 addition & 0 deletions program/rust/build_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ impl<'a> DeriveAdderParserCallback<'a> {
Default::default()
}
//add pairs of types and their desired traits
#[allow(dead_code)]
pub fn register_traits(&mut self, type_name: &'a str, traits: Vec<String>) {
self.types_to_traits.insert(type_name, traits);
}
Expand Down
1 change: 0 additions & 1 deletion program/rust/src/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,3 @@ typedef signed long int int64_t;
typedef unsigned long int uint64_t;

#include "../../c/src/oracle/oracle.h"
#include "price_t_offsets.h"
28 changes: 24 additions & 4 deletions program/rust/src/c_oracle_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
//we do not use all the variables in oracle.h, so this helps with the warnings
#![allow(dead_code)]
//All the custom trait imports should go here
use borsh::{
BorshDeserialize,
BorshSerialize,
};
use bytemuck::{
Pod,
Zeroable,
Expand Down Expand Up @@ -57,6 +53,30 @@ unsafe impl Pod for cmd_hdr {
}

#[cfg(target_endian = "little")]

unsafe impl Zeroable for pc_price_info {
}

#[cfg(target_endian = "little")]
unsafe impl Pod for pc_price_info {
}

#[cfg(target_endian = "little")]
unsafe impl Zeroable for cmd_upd_price {
}

#[cfg(target_endian = "little")]
unsafe impl Pod for cmd_upd_price {
}

#[cfg(target_endian = "little")]
unsafe impl Zeroable for pc_ema {
}

#[cfg(target_endian = "little")]
unsafe impl Pod for pc_ema {
}

unsafe impl Zeroable for cmd_add_price_t {
}

Expand Down
73 changes: 42 additions & 31 deletions program/rust/src/deserialize.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,47 @@
use crate::c_oracle_header::size_t;
use crate::error::OracleError;
use borsh::BorshDeserialize;
use std::mem::size_of;

use bytemuck::{
try_from_bytes,
try_from_bytes_mut,
Pod,
};

use std::cell::{
Ref,
RefMut,
};

use solana_program::account_info::AccountInfo;
use solana_program::program_error::ProgramError;
use std::mem::size_of;
use std::result::Result;

/// Deserialize field in `source` with offset `offset`
pub fn deserialize_single_field_from_buffer<T: BorshDeserialize>(
source: &[u8],
offset: Option<size_t>,
) -> Result<T, ProgramError> {
let start: usize = offset
.unwrap_or(0)
.try_into()
.map_err(|_| OracleError::IntegerCastingError)?;

let res: T = T::try_from_slice(&source[start..(start + size_of::<T>())])?;
Ok(res)

/// Interpret the bytes in `data` as a value of type `T`
pub fn load<T: Pod>(data: &[u8]) -> Result<&T, ProgramError> {
try_from_bytes(&data[0..size_of::<T>()]).map_err(|_| ProgramError::InvalidArgument)
}

/// Deserialize field in `i` rank of `accounts` with offset `offset`
pub fn deserialize_single_field_from_account<T: BorshDeserialize>(
accounts: &[AccountInfo],
i: usize,
offset: Option<size_t>,
) -> Result<T, ProgramError> {
deserialize_single_field_from_buffer::<T>(
&accounts
.get(i)
.ok_or(ProgramError::NotEnoughAccountKeys)?
.try_borrow_data()?,
offset,
)
/// Interpret the bytes in `data` as a mutable value of type `T`
#[allow(unused)]
pub fn load_mut<T: Pod>(data: &mut [u8]) -> Result<&mut T, ProgramError> {
try_from_bytes_mut(&mut data[0..size_of::<T>()]).map_err(|_| ProgramError::InvalidArgument)
}

/// Get the data stored in `account` as a value of type `T`
pub fn load_account_as<'a, T: Pod>(account: &'a AccountInfo) -> Result<Ref<'a, T>, ProgramError> {
let data = account.try_borrow_data()?;

Ok(Ref::map(data, |data| {
bytemuck::from_bytes(&data[0..size_of::<T>()])
}))
}

/// Mutably borrow the data in `account` as a value of type `T`.
/// Any mutations to the returned value will be reflected in the account data.
pub fn load_account_as_mut<'a, T: Pod>(
account: &'a AccountInfo,
) -> Result<RefMut<'a, T>, ProgramError> {
let data = account.try_borrow_mut_data()?;

Ok(RefMut::map(data, |data| {
bytemuck::from_bytes_mut(&mut data[0..size_of::<T>()])
}))
}
2 changes: 2 additions & 0 deletions program/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::error::{
OracleError,
OracleResult,
};

use crate::log::{
post_log,
pre_log,
Expand Down Expand Up @@ -92,6 +93,7 @@ pub extern "C" fn entrypoint(input: *mut u8) -> u64 {
return error.into();
}


if c_ret_val == SUCCESSFULLY_UPDATED_AGGREGATE {
//0 is the SUCCESS value for solana
0
Expand Down
52 changes: 17 additions & 35 deletions program/rust/src/log.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::c_oracle_header::*;
use crate::deserialize::{
deserialize_single_field_from_account,
deserialize_single_field_from_buffer,
load,
load_account_as,
};
use crate::error::OracleError;
use borsh::BorshDeserialize;
use solana_program::account_info::AccountInfo;
use solana_program::clock::Clock;
use solana_program::entrypoint::ProgramResult;
Expand All @@ -15,8 +14,7 @@ use solana_program::sysvar::Sysvar;
pub fn pre_log(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult {
msg!("Pyth oracle contract");

let instruction_header: cmd_hdr =
deserialize_single_field_from_buffer::<cmd_hdr>(instruction_data, None)?;
let instruction_header: &cmd_hdr = load::<cmd_hdr>(instruction_data)?;
let instruction_id: u32 = instruction_header
.cmd_
.try_into()
Expand All @@ -25,13 +23,9 @@ pub fn pre_log(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResu

match instruction_id {
command_t_e_cmd_upd_price | command_t_e_cmd_agg_price => {
let instruction: cmd_upd_price = cmd_upd_price::try_from_slice(instruction_data)?;
let instruction: &cmd_upd_price = load::<cmd_upd_price>(instruction_data)?;
// Account 1 is price_info in this instruction
let expo: i32 = deserialize_single_field_from_account::<i32>(
accounts,
1,
Some(PRICE_T_EXPO_OFFSET),
)?;
let price_account = load_account_as::<pc_price_t>(&accounts[1])?;
msg!(
"UpdatePrice: publisher={:}, price_account={:}, price={:}, conf={:}, expo={:}, status={:}, slot={:}, solana_time={:}",
accounts.get(0)
Expand All @@ -40,20 +34,16 @@ pub fn pre_log(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResu
.ok_or(ProgramError::NotEnoughAccountKeys)?.key,
instruction.price_,
instruction.conf_,
expo,
price_account.expo_,
instruction.status_,
instruction.pub_slot_,
Clock::get()?.unix_timestamp
);
}
command_t_e_cmd_upd_price_no_fail_on_error => {
let instruction: cmd_upd_price = cmd_upd_price::try_from_slice(instruction_data)?;
let instruction: &cmd_upd_price = load::<cmd_upd_price>(instruction_data)?;
// Account 1 is price_info in this instruction
let expo: i32 = deserialize_single_field_from_account::<i32>(
accounts,
1,
Some(PRICE_T_EXPO_OFFSET),
)?;
let price_account = load_account_as::<pc_price_t>(&accounts[1])?;
msg!(
"UpdatePriceNoFailOnError: publisher={:}, price_account={:}, price={:}, conf={:}, expo={:}, status={:}, slot={:}, solana_time={:}",
accounts.get(0)
Expand All @@ -62,7 +52,7 @@ pub fn pre_log(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResu
.ok_or(ProgramError::NotEnoughAccountKeys)?.key,
instruction.price_,
instruction.conf_,
expo,
price_account.expo_,
instruction.status_,
instruction.pub_slot_,
Clock::get()?.unix_timestamp
Expand Down Expand Up @@ -104,31 +94,23 @@ pub fn pre_log(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResu
Ok(())
}


pub fn post_log(c_ret_val: u64, accounts: &[AccountInfo]) -> ProgramResult {
if c_ret_val == SUCCESSFULLY_UPDATED_AGGREGATE {
// We trust that the C oracle has properly checked account 1, we can only get here through
// the update price instructions
let aggregate_price_info: pc_price_info = deserialize_single_field_from_account::<
pc_price_info,
>(
accounts, 1, Some(PRICE_T_AGGREGATE_OFFSET)
)?;
let ema_info: pc_ema =
deserialize_single_field_from_account::<pc_ema>(accounts, 1, Some(PRICE_T_EMA_OFFSET))?;
let expo: i32 =
deserialize_single_field_from_account::<i32>(accounts, 1, Some(PRICE_T_EXPO_OFFSET))?;

let price_account = load_account_as::<pc_price_t>(&accounts[1])?;
msg!(
"UpdateAggregate : price_account={:}, price={:}, conf={:}, expo={:}, status={:}, slot={:}, solana_time={:}, ema={:}",
accounts.get(1)
.ok_or(ProgramError::NotEnoughAccountKeys)?.key,
aggregate_price_info.price_,
aggregate_price_info.conf_,
expo,
aggregate_price_info.status_,
aggregate_price_info.pub_slot_,
price_account.agg_.price_,
price_account.agg_.conf_,
price_account.expo_,
price_account.agg_.status_,
price_account.agg_.pub_slot_,
Clock::get()?.unix_timestamp,
ema_info.val_
price_account.twap_.val_
);
}
Ok(())
Expand Down
15 changes: 0 additions & 15 deletions program/rust/src/price_t_offsets.h

This file was deleted.

4 changes: 2 additions & 2 deletions program/rust/src/processor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::mem::size_of;

use borsh::BorshDeserialize;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::Pubkey;
use solana_program::sysvar::slot_history::AccountInfo;
Expand Down Expand Up @@ -29,6 +28,7 @@ use crate::rust_oracle::{
update_version,
};

use crate::deserialize::load;
///dispatch to the right instruction in the oracle
pub fn process_instruction(
program_id: &Pubkey,
Expand All @@ -40,7 +40,7 @@ pub fn process_instruction(
if instruction_data.len() < cmd_hdr_size {
return Err(ProgramError::InvalidArgument);
}
let cmd_data = cmd_hdr::try_from_slice(&instruction_data[..cmd_hdr_size])?;
let cmd_data = load::<cmd_hdr>(&instruction_data[..cmd_hdr_size])?;

if cmd_data.ver_ != PC_VERSION {
//FIXME: I am not sure what's best to do here (this is copied from C)
Expand Down
52 changes: 8 additions & 44 deletions program/rust/src/rust_oracle.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
use std::borrow::BorrowMut;
use std::cell::{
Ref,
RefMut,
};
use std::cell::RefMut;
use std::mem::{
size_of,
size_of_val,
};

use bytemuck::{
bytes_of,
try_from_bytes,
try_from_bytes_mut,
Pod,
use crate::deserialize::{
load,
load_account_as,
load_account_as_mut,
};

use bytemuck::bytes_of;

use solana_program::account_info::AccountInfo;
use solana_program::entrypoint::SUCCESS;
use solana_program::program_error::ProgramError;
Expand Down Expand Up @@ -205,41 +204,6 @@ pub fn clear_account(account: &AccountInfo) -> Result<(), ProgramError> {
Ok(())
}

/// Interpret the bytes in `data` as a value of type `T`
fn load<T: Pod>(data: &[u8]) -> Result<&T, ProgramError> {
try_from_bytes(
data.get(0..size_of::<T>())
.ok_or(ProgramError::InvalidArgument)?,
)
.map_err(|_| ProgramError::InvalidArgument)
}

/// Interpret the bytes in `data` as a mutable value of type `T`
#[allow(unused)]
fn load_mut<T: Pod>(data: &mut [u8]) -> Result<&mut T, ProgramError> {
try_from_bytes_mut(&mut data[0..size_of::<T>()]).map_err(|_| ProgramError::InvalidArgument)
}

/// Get the data stored in `account` as a value of type `T`
pub fn load_account_as<'a, T: Pod>(account: &'a AccountInfo) -> Result<Ref<'a, T>, ProgramError> {
let data = account.try_borrow_data()?;

Ok(Ref::map(data, |data| {
bytemuck::from_bytes(&data[0..size_of::<T>()])
}))
}

/// Mutably borrow the data in `account` as a value of type `T`.
/// Any mutations to the returned value will be reflected in the account data.
pub fn load_account_as_mut<'a, T: Pod>(
account: &'a AccountInfo,
) -> Result<RefMut<'a, T>, ProgramError> {
let data = account.try_borrow_mut_data()?;

Ok(RefMut::map(data, |data| {
bytemuck::from_bytes_mut(&mut data[0..size_of::<T>()])
}))
}

/// Mutably borrow the data in `account` as a mapping account, validating that the account
/// is properly formatted. Any mutations to the returned value will be reflected in the
Expand Down
Loading