-
Notifications
You must be signed in to change notification settings - Fork 119
New interface with time machine #230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 50 commits
f6466df
734828f
b2af9e2
58012e5
a054e85
811824d
d2b1449
61ee6b1
1db05a8
6f5add8
c389080
e0b8d4c
4e71ed2
ac28c5c
fc3c0c1
9b1d170
be21613
3e50c33
5941c4e
3288adc
8120158
7987d89
dea076f
d6e8335
2ee49dc
bb7cdc9
af61550
60b02dc
5850ca3
5f02836
cdac025
5f20d65
0f7cc35
bf194b7
705cf9b
dce35e7
e50f644
30a23ab
cd4442c
fff8653
fbc394f
33e04a1
fb01b27
1af5472
24476a1
67dab41
89a1453
b5d0b24
fdb1be2
7fad134
4054143
3fae498
0caeb04
c44790f
70dd6b8
e287e80
13f0998
69302a3
22c6f27
85bd049
b72e93d
8ca407b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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, | ||
|
|
@@ -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), | ||
|
||
| }?; | ||
| //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 | ||
|
||
| /// 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(), | ||
| )?; | ||
majabbour marked this conversation as resolved.
Show resolved
Hide resolved
guibescos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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] | ||
|
|
@@ -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), | ||
|
|
||
| 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 | ||
|
|
@@ -7,10 +22,52 @@ pub struct TimeMachineWrapper { | |
| place_holder: [u8; 1864], | ||
| } | ||
|
|
||
| #[derive(Copy, Clone)] | ||
guibescos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| #[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; | ||
|
||
| } | ||
|
|
||
| #[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 | ||
|
|
@@ -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>() | ||
| ); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.