From b3d55e41d6f6043b19db8c4e606e4f857df8140f Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Thu, 4 Aug 2022 23:44:02 +0000 Subject: [PATCH 1/3] First test --- program/rust/src/lib.rs | 1 + program/rust/src/rust_oracle.rs | 2 +- program/rust/src/test_oracle.rs | 78 +++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 program/rust/src/test_oracle.rs diff --git a/program/rust/src/lib.rs b/program/rust/src/lib.rs index e397a0506..ad1839fbc 100644 --- a/program/rust/src/lib.rs +++ b/program/rust/src/lib.rs @@ -10,6 +10,7 @@ mod error; mod log; mod processor; mod rust_oracle; +mod test_oracle; mod time_machine_types; use crate::c_oracle_header::SUCCESSFULLY_UPDATED_AGGREGATE; diff --git a/program/rust/src/rust_oracle.rs b/program/rust/src/rust_oracle.rs index e19a09680..5311c3116 100644 --- a/program/rust/src/rust_oracle.rs +++ b/program/rust/src/rust_oracle.rs @@ -120,7 +120,7 @@ fn clear_account(account: &AccountInfo) -> Result<(), ProgramError> { } /// Interpret the bytes in `data` as a value of type `T` -fn load(data: &[u8]) -> Result<&T, ProgramError> { +pub fn load(data: &[u8]) -> Result<&T, ProgramError> { try_from_bytes(&data[0..size_of::()]).map_err(|_| ProgramError::InvalidArgument) } diff --git a/program/rust/src/test_oracle.rs b/program/rust/src/test_oracle.rs new file mode 100644 index 000000000..1c6e20953 --- /dev/null +++ b/program/rust/src/test_oracle.rs @@ -0,0 +1,78 @@ +#[cfg(test)] +mod test { + use crate::c_oracle_header::{ + cmd_hdr_t, + command_t_e_cmd_init_mapping, + pc_map_table_t, + PC_ACCTYPE_MAPPING, + PC_MAGIC, + PC_VERSION, + }; + use crate::rust_oracle::{ + init_mapping, + load, + }; + use bytemuck::bytes_of; + use solana_program::account_info::AccountInfo; + use solana_program::clock::Epoch; + use solana_program::native_token::LAMPORTS_PER_SOL; + use solana_program::pubkey::Pubkey; + use solana_program::rent::Rent; + use solana_program::system_program; + use std::mem::size_of; + + #[test] + fn test_init_mapping() { + let hdr: cmd_hdr_t = cmd_hdr_t { + ver_: PC_VERSION, + cmd_: command_t_e_cmd_init_mapping as i32, + }; + let instruction_data = bytes_of::(&hdr); + + let program_id = Pubkey::new_unique(); + let funding_key = Pubkey::new_unique(); + let mapping_key = Pubkey::new_unique(); + let system_program = system_program::id(); + + let mut funding_balance = LAMPORTS_PER_SOL.clone(); + let funding_account = AccountInfo::new( + &funding_key, + true, + true, + &mut funding_balance, + &mut [], + &system_program, + false, + Epoch::default(), + ); + + + let mut mapping_balance = + Rent::minimum_balance(&Rent::default(), size_of::()); + let mut mapping_raw_data = [0u8; size_of::()]; + + let mapping_account = AccountInfo::new( + &mapping_key, + true, + true, + &mut mapping_balance, + &mut mapping_raw_data, + &program_id, + false, + Epoch::default(), + ); + + assert!(init_mapping( + &program_id, + &[funding_account, mapping_account], + instruction_data + ) + .is_ok()); + + let mapping_data = load::(&mapping_raw_data).unwrap(); + assert_eq!(mapping_data.ver_, PC_VERSION); + assert_eq!(mapping_data.magic_, PC_MAGIC); + assert_eq!(mapping_data.type_, PC_ACCTYPE_MAPPING); + assert_eq!(mapping_data.size_, 56); + } +} From 22acd6932eaff425a5a2964f44c333b6936dba27 Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Fri, 5 Aug 2022 00:53:28 +0000 Subject: [PATCH 2/3] Mapping --- program/rust/src/rust_oracle.rs | 10 +-- program/rust/src/test_oracle.rs | 124 +++++++++++++++++++++++++++++--- 2 files changed, 119 insertions(+), 15 deletions(-) diff --git a/program/rust/src/rust_oracle.rs b/program/rust/src/rust_oracle.rs index 5311c3116..c8c63583a 100644 --- a/program/rust/src/rust_oracle.rs +++ b/program/rust/src/rust_oracle.rs @@ -13,12 +13,12 @@ use bytemuck::{ try_from_bytes_mut, Pod, }; +use solana_program::account_info::AccountInfo; use solana_program::entrypoint::SUCCESS; use solana_program::program_error::ProgramError; use solana_program::program_memory::sol_memset; use solana_program::pubkey::Pubkey; use solana_program::rent::Rent; -use solana_program::sysvar::slot_history::AccountInfo; use crate::c_oracle_header::{ cmd_hdr_t, @@ -110,7 +110,7 @@ fn valid_fresh_account(account: &AccountInfo) -> bool { } /// Sets the data of account to all-zero -fn clear_account(account: &AccountInfo) -> Result<(), ProgramError> { +pub fn clear_account(account: &AccountInfo) -> Result<(), ProgramError> { let mut data = account .try_borrow_mut_data() .map_err(|_| ProgramError::InvalidArgument)?; @@ -120,7 +120,7 @@ fn clear_account(account: &AccountInfo) -> Result<(), ProgramError> { } /// Interpret the bytes in `data` as a value of type `T` -pub fn load(data: &[u8]) -> Result<&T, ProgramError> { +fn load(data: &[u8]) -> Result<&T, ProgramError> { try_from_bytes(&data[0..size_of::()]).map_err(|_| ProgramError::InvalidArgument) } @@ -131,7 +131,7 @@ fn load_mut(data: &mut [u8]) -> Result<&mut T, ProgramError> { } /// Get the data stored in `account` as a value of type `T` -fn load_account_as<'a, T: Pod>(account: &'a AccountInfo) -> Result, ProgramError> { +pub fn load_account_as<'a, T: Pod>(account: &'a AccountInfo) -> Result, ProgramError> { let data = account.try_borrow_data()?; Ok(Ref::map(data, |data| { @@ -141,7 +141,7 @@ fn load_account_as<'a, T: Pod>(account: &'a AccountInfo) -> Result, P /// 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. -fn load_account_as_mut<'a, T: Pod>( +pub fn load_account_as_mut<'a, T: Pod>( account: &'a AccountInfo, ) -> Result, ProgramError> { let data = account.try_borrow_mut_data()?; diff --git a/program/rust/src/test_oracle.rs b/program/rust/src/test_oracle.rs index 1c6e20953..0e313cc49 100644 --- a/program/rust/src/test_oracle.rs +++ b/program/rust/src/test_oracle.rs @@ -9,17 +9,21 @@ mod test { PC_VERSION, }; use crate::rust_oracle::{ + clear_account, init_mapping, - load, + load_account_as, }; use bytemuck::bytes_of; use solana_program::account_info::AccountInfo; use solana_program::clock::Epoch; use solana_program::native_token::LAMPORTS_PER_SOL; + use solana_program::program_error::ProgramError; use solana_program::pubkey::Pubkey; use solana_program::rent::Rent; use solana_program::system_program; + use std::cell::RefCell; use std::mem::size_of; + use std::rc::Rc; #[test] fn test_init_mapping() { @@ -30,12 +34,13 @@ mod test { let instruction_data = bytes_of::(&hdr); let program_id = Pubkey::new_unique(); + let program_id_2 = Pubkey::new_unique(); let funding_key = Pubkey::new_unique(); let mapping_key = Pubkey::new_unique(); let system_program = system_program::id(); let mut funding_balance = LAMPORTS_PER_SOL.clone(); - let funding_account = AccountInfo::new( + let mut funding_account = AccountInfo::new( &funding_key, true, true, @@ -46,12 +51,11 @@ mod test { Epoch::default(), ); - let mut mapping_balance = Rent::minimum_balance(&Rent::default(), size_of::()); let mut mapping_raw_data = [0u8; size_of::()]; - let mapping_account = AccountInfo::new( + let mut mapping_account = AccountInfo::new( &mapping_key, true, true, @@ -64,15 +68,115 @@ mod test { assert!(init_mapping( &program_id, - &[funding_account, mapping_account], + &[funding_account.clone(), mapping_account.clone()], instruction_data ) .is_ok()); - let mapping_data = load::(&mapping_raw_data).unwrap(); - assert_eq!(mapping_data.ver_, PC_VERSION); - assert_eq!(mapping_data.magic_, PC_MAGIC); - assert_eq!(mapping_data.type_, PC_ACCTYPE_MAPPING); - assert_eq!(mapping_data.size_, 56); + { + let mapping_data = load_account_as::(&mapping_account).unwrap(); + + assert_eq!(mapping_data.ver_, PC_VERSION); + assert_eq!(mapping_data.magic_, PC_MAGIC); + assert_eq!(mapping_data.type_, PC_ACCTYPE_MAPPING); + assert_eq!(mapping_data.size_, 56); + } + + assert_eq!( + init_mapping( + &program_id, + &[funding_account.clone(), mapping_account.clone()], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); + + clear_account(&mapping_account).unwrap(); + + assert_eq!( + init_mapping(&program_id, &[funding_account.clone()], instruction_data), + Err(ProgramError::InvalidArgument) + ); + + funding_account.is_signer = false; + + assert_eq!( + init_mapping( + &program_id, + &[funding_account.clone(), mapping_account.clone()], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); + + funding_account.is_signer = true; + mapping_account.is_signer = false; + + assert_eq!( + init_mapping( + &program_id, + &[funding_account.clone(), mapping_account.clone()], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); + + mapping_account.is_signer = true; + funding_account.is_writable = false; + + assert_eq!( + init_mapping( + &program_id, + &[funding_account.clone(), mapping_account.clone()], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); + + funding_account.is_writable = true; + mapping_account.is_writable = false; + + assert_eq!( + init_mapping( + &program_id, + &[funding_account.clone(), mapping_account.clone()], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); + + mapping_account.is_writable = true; + mapping_account.owner = &program_id_2; + + assert_eq!( + init_mapping( + &program_id, + &[funding_account.clone(), mapping_account.clone()], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); + + mapping_account.owner = &program_id; + let prev_data = mapping_account.data; + mapping_account.data = Rc::new(RefCell::new(&mut [])); + + assert_eq!( + init_mapping( + &program_id, + &[funding_account.clone(), mapping_account.clone()], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); + + mapping_account.data = prev_data; + + assert!(init_mapping( + &program_id, + &[funding_account.clone(), mapping_account.clone()], + instruction_data + ) + .is_ok()); } } From 29d0439101336c68e910e738887fccfafe07234a Mon Sep 17 00:00:00 2001 From: Guillermo Bescos Date: Fri, 5 Aug 2022 01:10:12 +0000 Subject: [PATCH 3/3] Delete c version of init_mapping --- program/c/src/oracle/oracle.c | 29 +----------- program/c/src/oracle/test_oracle.c | 75 ------------------------------ 2 files changed, 1 insertion(+), 103 deletions(-) diff --git a/program/c/src/oracle/oracle.c b/program/c/src/oracle/oracle.c index fe0f837ae..09615a5a7 100644 --- a/program/c/src/oracle/oracle.c +++ b/program/c/src/oracle/oracle.c @@ -59,33 +59,6 @@ static bool valid_writable_account( SolParameters *prm, is_rent_exempt( *ka->lamports, ka->data_len ); } -static uint64_t init_mapping( SolParameters *prm, SolAccountInfo *ka ) -{ - // Verify that the new account is signed and writable, with correct - // ownership and size - if ( prm->ka_num != 2 || - !valid_funding_account( &ka[0] ) || - !valid_signable_account( prm, &ka[1], sizeof( pc_map_table_t ) ) ) { - return ERROR_INVALID_ARGUMENT; - } - - // Check that the account has not already been initialized - pc_map_table_t *tptr = (pc_map_table_t*)ka[1].data; - if ( tptr->magic_ != 0 || tptr->ver_ != 0 ) { - return ERROR_INVALID_ARGUMENT; - } - - // Initialize by setting to zero again (just in case) and setting - // the version number - cmd_hdr_t *hdr = (cmd_hdr_t*)prm->data; - sol_memset( tptr, 0, sizeof( pc_map_table_t ) ); - tptr->magic_ = PC_MAGIC; - tptr->ver_ = hdr->ver_; - tptr->type_ = PC_ACCTYPE_MAPPING; - tptr->size_ = sizeof( pc_map_table_t ) - sizeof( tptr->prod_ ); - return SUCCESS; -} - static uint64_t add_mapping( SolParameters *prm, SolAccountInfo *ka ) { // Account (1) is the tail or last mapping account in the chain @@ -539,7 +512,7 @@ static uint64_t dispatch( SolParameters *prm, SolAccountInfo *ka ) case e_cmd_agg_price: return upd_price( prm, ka ); case e_cmd_upd_price_no_fail_on_error: return upd_price_no_fail_on_error( prm, ka ); // init_mapping is overridden in Rust, but still implemented here to make the C unit tests pass. - case e_cmd_init_mapping: return init_mapping( prm, ka ); + case e_cmd_init_mapping: return ERROR_INVALID_ARGUMENT; case e_cmd_add_mapping: return add_mapping( prm, ka ); case e_cmd_add_product: return add_product( prm, ka ); case e_cmd_upd_product: return upd_product( prm, ka ); diff --git a/program/c/src/oracle/test_oracle.c b/program/c/src/oracle/test_oracle.c index 84d62d118..8076ae83e 100644 --- a/program/c/src/oracle/test_oracle.c +++ b/program/c/src/oracle/test_oracle.c @@ -7,81 +7,6 @@ uint64_t MAPPING_ACCOUNT_LAMPORTS = 143821440; uint64_t PRODUCT_ACCOUNT_LAMPORTS = 4454400; uint64_t PRICE_ACCOUNT_LAMPORTS = 23942400; -Test(oracle, init_mapping) { - - // start with perfect inputs - cmd_hdr_t idata = { - .ver_ = PC_VERSION, - .cmd_ = e_cmd_init_mapping - }; - SolPubkey p_id = {.x = { 0xff, }}; - SolPubkey p_id2 = {.x = { 0xfe, }}; - SolPubkey pkey = {.x = { 1, }}; - SolPubkey mkey = {.x = { 2, }}; - uint64_t pqty = 100; - pc_map_table_t mptr[1]; - sol_memset( mptr, 0, sizeof( pc_map_table_t ) ); - SolAccountInfo acc[] = {{ - .key = &pkey, - .lamports = &pqty, - .data_len = 0, - .data = NULL, - .owner = NULL, - .rent_epoch = 0, - .is_signer = true, - .is_writable = true, - .executable = false - },{ - .key = &mkey, - .lamports = &MAPPING_ACCOUNT_LAMPORTS, - .data_len = sizeof( pc_map_table_t ), - .data = (uint8_t*)mptr, - .owner = &p_id, - .rent_epoch = 0, - .is_signer = true, - .is_writable = true, - .executable = false - }}; - SolParameters prm = { - .ka = acc, - .ka_num = 2, - .data = (const uint8_t*)&idata, - .data_len = sizeof( idata ), - .program_id = &p_id - }; - cr_assert( SUCCESS == dispatch( &prm, acc ) ); - cr_assert( mptr->ver_ == PC_VERSION ); - cr_assert( mptr->type_ == PC_ACCTYPE_MAPPING ); - - // cant reinitialize because version has been set - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - sol_memset( mptr, 0, sizeof( pc_map_table_t ) ); - - // check other params - prm.ka_num = 1; - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - prm.ka_num = 2; - acc[0].is_signer = false; - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - acc[0].is_signer = true; - acc[1].is_signer = false; - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - acc[1].is_signer = true; - acc[0].is_writable = false; - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - acc[0].is_writable = true; - acc[1].is_writable = false; - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - acc[1].is_writable = true; - acc[1].owner = &p_id2; - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - acc[1].owner = &p_id; - acc[1].data_len = 0; - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - acc[1].data_len = sizeof( pc_map_table_t ); - cr_assert( SUCCESS == dispatch( &prm, acc ) ); -} - Test(oracle, add_mapping ) { // start with perfect inputs cmd_hdr_t idata = {