Skip to content
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
f6466df
added resize feature
majabbour Aug 5, 2022
734828f
added update account to log
majabbour Aug 5, 2022
b2af9e2
implemented upgrade instruction
majabbour Aug 8, 2022
58012e5
fixed build errors
majabbour Aug 8, 2022
a054e85
added test for resizing
majabbour Aug 8, 2022
811824d
implemented price updates
majabbour Aug 8, 2022
d2b1449
Merge branch 'main' into new-interface-with-time-machine
majabbour Aug 8, 2022
61ee6b1
fixed merge errors
majabbour Aug 8, 2022
1db05a8
fixed CI fmt error
majabbour Aug 8, 2022
6f5add8
removed duplicate import
majabbour Aug 8, 2022
c389080
fixed typo
majabbour Aug 8, 2022
e0b8d4c
made account upgrade permissionless
majabbour Aug 9, 2022
4e71ed2
fixed borrow bug
majabbour Aug 9, 2022
ac28c5c
removed feature logic
majabbour Aug 9, 2022
fc3c0c1
cargo fmt
majabbour Aug 9, 2022
9b1d170
made resize permissioned
majabbour Aug 9, 2022
be21613
fixed tests that broke because of specific errors
majabbour Aug 9, 2022
3e50c33
tested permissioned resize
majabbour Aug 10, 2022
5941c4e
added reguired package
majabbour Aug 10, 2022
3288adc
fixed error in pytest
majabbour Aug 10, 2022
8120158
added new line
majabbour Aug 10, 2022
7987d89
removed uneeded borrowing
majabbour Aug 10, 2022
dea076f
removed extra sleep in test
majabbour Aug 10, 2022
d6e8335
refactored lamport transfer into a function
majabbour Aug 10, 2022
2ee49dc
changed comment
majabbour Aug 10, 2022
bb7cdc9
fixed doc string
majabbour Aug 10, 2022
af61550
fixed typo
majabbour Aug 10, 2022
60b02dc
renamed upgrade instruction
majabbour Aug 10, 2022
5850ca3
moved try_convert to utils
majabbour Aug 10, 2022
5f02836
try_convert for ergonomicity
majabbour Aug 10, 2022
cdac025
reordered add_price params
majabbour Aug 10, 2022
5f20d65
better interface for time machine
majabbour Aug 10, 2022
0f7cc35
renamed functions
majabbour Aug 10, 2022
bf194b7
Merge branch 'main' into new-interface-with-time-machine
majabbour Aug 10, 2022
705cf9b
fixed merging errors
majabbour Aug 10, 2022
dce35e7
more merge errors
majabbour Aug 10, 2022
e50f644
removed implmentation details for a later PR
majabbour Aug 11, 2022
30a23ab
Merge branch 'main' into new-interface-with-time-machine
majabbour Aug 11, 2022
cd4442c
moved try_convert back to rust orale to minimize differences from main
majabbour Aug 11, 2022
fff8653
changed upgrade instruction to resize
majabbour Aug 11, 2022
fbc394f
read accounts using the same pattern as other instructions
majabbour Aug 11, 2022
33e04a1
added a new line at the end of the docker file
majabbour Aug 11, 2022
fb01b27
removed resizing message
majabbour Aug 11, 2022
1af5472
fixed typo
majabbour Aug 11, 2022
24476a1
match instead of if in updatea_price
majabbour Aug 11, 2022
67dab41
new style of reading accounts
majabbour Aug 11, 2022
89a1453
resolved non deterministic feepayer issue
majabbour Aug 11, 2022
b5d0b24
added sysvar account to add_price
majabbour Aug 11, 2022
fdb1be2
with as syntax instead of closing
majabbour Aug 11, 2022
7fad134
Client has no _enter, can not use with as
majabbour Aug 11, 2022
4054143
fixed typo
majabbour Aug 11, 2022
3fae498
fixed update_price
majabbour Aug 11, 2022
0caeb04
moved call to wrapper to the begining of upd_price
majabbour Aug 11, 2022
c44790f
added load_checked to avoid human error
majabbour Aug 11, 2022
70dd6b8
fixed typo
majabbour Aug 11, 2022
e287e80
renamed sender to publickeypair
majabbour Aug 11, 2022
13f0998
changed inital_size for PriceAccoutWrapper
majabbour Aug 11, 2022
69302a3
switched to index for the wrapper
majabbour Aug 11, 2022
22c6f27
another typo
majabbour Aug 11, 2022
85bd049
Merge branch 'main' into new-interface-with-time-machine
majabbour Aug 11, 2022
b72e93d
merge errors
majabbour Aug 11, 2022
8ca407b
changed initial size to for price account
majabbour Aug 11, 2022
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
7 changes: 5 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ RUN apt-get install -qq \
qt5-qmake \
qtbase5-dev-tools \
libqt5websockets5-dev\
libclang-dev

libclang-dev\
python3-pip

# Install jcon-cpp library
RUN git clone https://github.com/joncol/jcon-cpp.git /jcon-cpp && cd /jcon-cpp && git checkout 2235654e39c7af505d7158bf996e47e37a23d6e3 && mkdir build && cd build && cmake .. && make -j4 && make install

Expand Down Expand Up @@ -56,6 +57,8 @@ export PYTHONPATH=\"\${PYTHONPATH:+\$PYTHONPATH:}\${HOME}/pyth-client\"\n\

COPY --chown=pyth:pyth . pyth-client/

RUN pip3 install solana

# Build off-chain binaries.
RUN cd pyth-client && ./scripts/build.sh

Expand Down
6 changes: 3 additions & 3 deletions program/c/src/oracle/oracle.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,11 @@ typedef enum {
// key[2] sysvar_clock account [readable]
e_cmd_upd_price_no_fail_on_error,

// performs migation logic on the upgraded account. (resizes price accounts)
// resizes a price accpunt so that it fits the Time Machine
// key[0] funding account [signer writable]
// key[1] upgraded account [writable]
// key[1] price account [Signer writable]
// key[2] system program [readable]
e_cmd_upd_account_version,
e_cmd_resize_price_account,
} command_t;

typedef struct cmd_hdr
Expand Down
5 changes: 5 additions & 0 deletions program/rust/src/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ pub fn pre_log(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResu
command_t_e_cmd_upd_product => {
msg!("UpdateProduct");
}

command_t_e_cmd_resize_price_account => {
//accounts[1] is the updated account
msg!("ResizePriceAccount: {}", accounts[1].key);
}
_ => {
msg!("UnrecognizedInstruction");
return Err(OracleError::UnrecognizedInstruction.into());
Expand Down
8 changes: 4 additions & 4 deletions program/rust/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use crate::c_oracle_header::{
command_t_e_cmd_add_publisher,
command_t_e_cmd_agg_price,
command_t_e_cmd_init_mapping,
command_t_e_cmd_resize_price_account,
command_t_e_cmd_set_min_pub,
command_t_e_cmd_upd_account_version,
command_t_e_cmd_upd_price,
command_t_e_cmd_upd_price_no_fail_on_error,
command_t_e_cmd_upd_product,
Expand All @@ -29,10 +29,10 @@ use crate::rust_oracle::{
add_product,
add_publisher,
init_mapping,
resize_price_account,
set_min_pub,
upd_product,
update_price,
update_version,
};

///dispatch to the right instruction in the oracle
Expand All @@ -59,8 +59,8 @@ pub fn process_instruction(
command_t_e_cmd_upd_price
| command_t_e_cmd_upd_price_no_fail_on_error
| command_t_e_cmd_agg_price => update_price(program_id, accounts, instruction_data, input),
command_t_e_cmd_upd_account_version => {
update_version(program_id, accounts, instruction_data)
command_t_e_cmd_resize_price_account => {
resize_price_account(program_id, accounts, instruction_data)
}
command_t_e_cmd_add_price => add_price(program_id, accounts, instruction_data),
command_t_e_cmd_init_mapping => init_mapping(program_id, accounts, instruction_data),
Expand Down
112 changes: 99 additions & 13 deletions program/rust/src/rust_oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ use solana_program::program_memory::{
use solana_program::pubkey::Pubkey;
use solana_program::rent::Rent;


use crate::time_machine_types::PriceAccountWrapper;
use solana_program::program::invoke;
use solana_program::system_instruction::transfer;
use solana_program::system_program::check_id;


use crate::c_oracle_header::{
cmd_add_price_t,
cmd_add_publisher_t,
Expand All @@ -38,41 +45,119 @@ use crate::c_oracle_header::{
PC_MAX_NUM_DECIMALS,
PC_PROD_ACC_SIZE,
PC_PTYPE_UNKNOWN,
PC_VERSION,
SUCCESSFULLY_UPDATED_AGGREGATE,
};
use crate::deserialize::{
load,
load_account_as,
load_account_as_mut,
};
use crate::error::OracleResult;
use crate::utils::pyth_assert;
use crate::OracleError;

use crate::utils::pyth_assert;

use super::c_entrypoint_wrapper;
const PRICE_T_SIZE: usize = size_of::<pc_price_t>();
const PRICE_ACCOUNT_SIZE: usize = size_of::<PriceAccountWrapper>();


///Calls the c oracle update_price, and updates the Time Machine if needed
pub fn update_price(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
accounts: &[AccountInfo],
_instruction_data: &[u8],
input: *mut u8,
) -> OracleResult {
//For now, we did not change the behavior of this. this is just to show the proposed structure
// of the program
c_entrypoint_wrapper(input)
let [_funding_account_info, price_account_info, _sysvar_clock] = match accounts {
[x, y, z] => Ok([x, y, z]),
_ => Err(ProgramError::InvalidArgument),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to fix this, it's actually more like :

    let [funding_account, price_account, clock_account] = match accounts {
        [x, y,z ] => Ok([x, y, z]),
        [x, y,_ , z ] => Ok([x, y, z]),
        _ => Err(ProgramError::InvalidArgument),
    }?;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a thin wrapper around c_entrypoint_wrapper, you want to avoid writing code that could accidentally change the behavior. The best way to have approached this problem, imo, would have been something like:

let c_ret_value = c_entrypoint_wrapper(input)?;

let price_account = accounts.get(2)?; 
let account_len = ...
match {
  ... => price_account.add_price_to_time_machine();
} 

If you structure your code that way, all of your additions happen after c_entrypoint_wrapper, which makes it hard for future edits to accidentally forget to call that function.

}?;
//accounts checks happen in c_entrypoint
let account_len = price_account_info.try_data_len()?;
match account_len {
PRICE_T_SIZE => c_entrypoint_wrapper(input),
PRICE_ACCOUNT_SIZE => {
let c_ret_value = c_entrypoint_wrapper(input)?;
if c_ret_value == SUCCESSFULLY_UPDATED_AGGREGATE {
let mut price_account =
load_account_as_mut::<PriceAccountWrapper>(price_account_info)?;
price_account.add_price_to_time_machine()?;
}
Ok(c_ret_value)
}
_ => Err(ProgramError::InvalidArgument),
}
}
/// has version number/ account type dependant logic to make sure the given account is compatible
/// with the current version
/// updates the version number for all accounts, and resizes price accounts
pub fn update_version(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
fn send_lamports<'a>(
from: &AccountInfo<'a>,
to: &AccountInfo<'a>,
system_program: &AccountInfo<'a>,
amount: u64,
) -> Result<(), ProgramError> {
let transfer_instruction = transfer(from.key, to.key, amount);
invoke(
&transfer_instruction,
&[from.clone(), to.clone(), system_program.clone()],
)?;
Ok(())
}

/// resizes a price accpunt so that it fits the Time Machine
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: account

/// key[0] funding account [signer writable]
/// key[1] price account [Signer writable]
/// key[2] system program [readable]
pub fn resize_price_account(
program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> OracleResult {
panic!("Need to merge fix to pythd in order to implement this");
// Ok(SUCCESS)
let [funding_account_info, price_account_info, system_program] = match accounts {
[x, y, z] => Ok([x, y, z]),
_ => Err(ProgramError::InvalidArgument),
}?;

check_valid_funding_account(funding_account_info)?;
check_valid_signable_account(program_id, price_account_info, size_of::<pc_price_t>())?;
pyth_assert(
check_id(system_program.key),
OracleError::InvalidSystemAccount.into(),
)?;
let account_len = price_account_info.try_data_len()?;
match account_len {
PRICE_T_SIZE => {
//ensure account is still rent exempt after resizing
let rent: Rent = Default::default();
let lamports_needed: u64 = rent
.minimum_balance(size_of::<PriceAccountWrapper>())
.saturating_sub(price_account_info.lamports());
if lamports_needed > 0 {
send_lamports(
funding_account_info,
price_account_info,
system_program,
lamports_needed,
)?;
}
//resize
//we do not need to zero initialize since this is the first time this memory
//is allocated
price_account_info.realloc(size_of::<PriceAccountWrapper>(), false)?;
//The load below would fail if the account was not a price account, reverting the whole
// transaction
let mut price_account =
load_checked::<PriceAccountWrapper>(price_account_info, PC_VERSION)?;
//Initialize Time Machine
price_account.initialize_time_machine()?;
Ok(SUCCESS)
}
PRICE_ACCOUNT_SIZE => Ok(SUCCESS),
_ => Err(ProgramError::InvalidArgument),
}
}


/// initialize the first mapping account in a new linked-list of mapping accounts
/// accounts[0] funding account [signer writable]
/// accounts[1] new mapping account [signer writable]
Expand Down Expand Up @@ -147,6 +232,7 @@ pub fn add_price(
return Err(ProgramError::InvalidArgument);
}


let [funding_account, product_account, price_account] = match accounts {
[x, y, z] => Ok([x, y, z]),
_ => Err(ProgramError::InvalidArgument),
Expand Down
74 changes: 71 additions & 3 deletions program/rust/src/time_machine_types.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
#[derive(Debug, Clone)]
use crate::c_oracle_header::{
pc_price_t,
PythAccount,
EXTRA_PUBLISHER_SPACE,
PC_ACCTYPE_PRICE,
};
use crate::error::OracleError;
use bytemuck::{
Pod,
Zeroable,
};
use solana_program::msg;
use std::mem::size_of;


#[derive(Debug, Clone, Copy)]
#[repr(C)]
/// this wraps multiple SMA and tick trackers, and includes all the state
/// used by the time machine
Expand All @@ -7,10 +22,52 @@ pub struct TimeMachineWrapper {
place_holder: [u8; 1864],
}

#[derive(Copy, Clone)]
#[repr(C)]
/// wraps everything stored in a price account
pub struct PriceAccountWrapper {
//an instance of the c price_t type
pub price_data: pc_price_t,
//space for more publishers
pub extra_publisher_space: [u8; EXTRA_PUBLISHER_SPACE as usize],
//TimeMachine
pub time_machine: TimeMachineWrapper,
}
impl PriceAccountWrapper {
pub fn initialize_time_machine(&mut self) -> Result<(), OracleError> {
msg!("implement me");
Ok(())
}

pub fn add_price_to_time_machine(&mut self) -> Result<(), OracleError> {
msg!("implement me");
Ok(())
}
}

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

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

impl PythAccount for PriceAccountWrapper {
const ACCOUNT_TYPE: u32 = PC_ACCTYPE_PRICE;
const INITIAL_SIZE: u32 = size_of::<PriceAccountWrapper>() as u32;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this consistent with PythAccount for pc_price_t

}

#[cfg(test)]
pub mod tests {
use crate::c_oracle_header::TIME_MACHINE_STRUCT_SIZE;
use crate::time_machine_types::TimeMachineWrapper;
use crate::c_oracle_header::{
PRICE_ACCOUNT_SIZE,
TIME_MACHINE_STRUCT_SIZE,
};
use crate::time_machine_types::{
PriceAccountWrapper,
TimeMachineWrapper,
};
use std::mem::size_of;
#[test]
///test that the size defined in C matches that
Expand All @@ -24,4 +81,15 @@ pub mod tests {
size_of::<TimeMachineWrapper>()
);
}
#[test]
///test that priceAccountWrapper has a correct size
fn c_price_account_size_is_correct() {
assert_eq!(
size_of::<PriceAccountWrapper>(),
PRICE_ACCOUNT_SIZE.try_into().unwrap(),
"expected PRICE_ACCOUNT_SIZE ({}) in oracle.h to the same as the size of PriceAccountWrapper ({})",
PRICE_ACCOUNT_SIZE,
size_of::<PriceAccountWrapper>()
);
}
}
Loading