diff --git a/program/c/src/oracle/oracle.c b/program/c/src/oracle/oracle.c index 254a43b6f..cdc341f91 100644 --- a/program/c/src/oracle/oracle.c +++ b/program/c/src/oracle/oracle.c @@ -59,55 +59,6 @@ static bool valid_writable_account( SolParameters *prm, is_rent_exempt( *ka->lamports, ka->data_len ); } -static uint64_t add_price( SolParameters *prm, SolAccountInfo *ka ) -{ - // Validate command parameters - cmd_add_price_t *cptr = (cmd_add_price_t*)prm->data; - if ( prm->data_len != sizeof( cmd_add_price_t ) || - cptr->expo_ > PC_MAX_NUM_DECIMALS || - cptr->expo_ < -PC_MAX_NUM_DECIMALS || - cptr->ptype_ == PC_PTYPE_UNKNOWN ) { - return ERROR_INVALID_ARGUMENT; - } - - // Account (1) is the product account that we're going to add to - // Account (2) is the new price account - // Verify that these are signed, writable accounts with correct ownership - // and size - if ( prm->ka_num != 3 || - !valid_funding_account( &ka[0] ) || - !valid_signable_account( prm, &ka[1], PC_PROD_ACC_SIZE ) || - !valid_signable_account( prm, &ka[2], sizeof( pc_price_t ) ) ) { - return ERROR_INVALID_ARGUMENT; - } - - // Verify that the product account is valid - // and that the new price account is uninitialized - pc_prod_t *pptr = (pc_prod_t*)ka[1].data; - pc_price_t *sptr = (pc_price_t*)ka[2].data; - if ( pptr->magic_ != PC_MAGIC || - pptr->ver_ != cptr->ver_ || - pptr->type_ != PC_ACCTYPE_PRODUCT || - sptr->magic_ != 0 ) { - return ERROR_INVALID_ARGUMENT; - } - - // Initialize symbol account - sol_memset( sptr, 0, sizeof( pc_price_t ) ); - sptr->magic_ = PC_MAGIC; - sptr->ver_ = cptr->ver_; - sptr->type_ = PC_ACCTYPE_PRICE; - sptr->size_ = sizeof( pc_price_t ) - sizeof( sptr->comp_ ); - sptr->expo_ = cptr->expo_; - sptr->ptype_ = cptr->ptype_; - pc_pub_key_assign( &sptr->prod_, (pc_pub_key_t*)ka[1].key ); - - // bind price account to product account - pc_pub_key_assign( &sptr->next_, &pptr->px_acc_ ); - pc_pub_key_assign( &pptr->px_acc_, (pc_pub_key_t*)ka[2].key ); - return SUCCESS; -} - static uint64_t init_price( SolParameters *prm, SolAccountInfo *ka ) { // Validate command parameters @@ -156,53 +107,6 @@ static uint64_t init_price( SolParameters *prm, SolAccountInfo *ka ) return SUCCESS; } -static uint64_t add_publisher( SolParameters *prm, SolAccountInfo *ka ) -{ - // Validate command parameters - cmd_add_publisher_t *cptr = (cmd_add_publisher_t*)prm->data; - if ( prm->data_len != sizeof( cmd_add_publisher_t ) || - pc_pub_key_is_zero( &cptr->pub_ ) ) { - return ERROR_INVALID_ARGUMENT; - } - - // Account (1) is the price account - // Verify that this is signed, writable with correct ownership - // and size - if ( prm->ka_num != 2 || - !valid_funding_account( &ka[0] ) || - !valid_signable_account( prm, &ka[1], sizeof( pc_price_t ) ) ) { - return ERROR_INVALID_ARGUMENT; - } - - // Verify that symbol account is initialized and corresponds to the - // same symbol and price-type in the instruction parameters - pc_price_t *sptr = (pc_price_t*)ka[1].data; - if ( sptr->magic_ != PC_MAGIC || - sptr->ver_ != cptr->ver_ || - sptr->type_ != PC_ACCTYPE_PRICE ) { - return ERROR_INVALID_ARGUMENT; - } - - // try to add publisher - for(uint32_t i=0; i != sptr->num_; ++i ) { - pc_price_comp_t *iptr = &sptr->comp_[i]; - if ( pc_pub_key_equal( &iptr->pub_, &cptr->pub_ ) ) { - return ERROR_INVALID_ARGUMENT; - } - } - if ( sptr->num_ >= PC_COMP_SIZE ) { - return ERROR_INVALID_ARGUMENT; - } - pc_price_comp_t *iptr = &sptr->comp_[sptr->num_++]; - sol_memset( iptr, 0, sizeof( pc_price_comp_t ) ); - pc_pub_key_assign( &iptr->pub_, &cptr->pub_ ); - - // update size of account - sptr->size_ = sizeof( pc_price_t ) - sizeof( sptr->comp_ ) + - sptr->num_ * sizeof( pc_price_comp_t ); - return SUCCESS; -} - // remove publisher from price node static uint64_t del_publisher( SolParameters *prm, SolAccountInfo *ka ) { @@ -353,8 +257,8 @@ static uint64_t dispatch( SolParameters *prm, SolAccountInfo *ka ) case e_cmd_add_mapping: return ERROR_INVALID_ARGUMENT; case e_cmd_add_product: return ERROR_INVALID_ARGUMENT; case e_cmd_upd_product: return ERROR_INVALID_ARGUMENT; - case e_cmd_add_price: return add_price( prm, ka ); - case e_cmd_add_publisher: return add_publisher( prm, ka ); + case e_cmd_add_price: return ERROR_INVALID_ARGUMENT; + case e_cmd_add_publisher: return ERROR_INVALID_ARGUMENT; case e_cmd_del_publisher: return del_publisher( prm, ka ); case e_cmd_init_price: return init_price( prm, ka ); case e_cmd_init_test: return ERROR_INVALID_ARGUMENT; diff --git a/program/c/src/oracle/test_oracle.c b/program/c/src/oracle/test_oracle.c index 316345eef..74e44e5a2 100644 --- a/program/c/src/oracle/test_oracle.c +++ b/program/c/src/oracle/test_oracle.c @@ -7,88 +7,6 @@ uint64_t MAPPING_ACCOUNT_LAMPORTS = 143821440; uint64_t PRODUCT_ACCOUNT_LAMPORTS = 4454400; uint64_t PRICE_ACCOUNT_LAMPORTS = 23942400; -Test( oracle, add_publisher ) { - // start with perfect inputs - cmd_add_publisher_t idata = { - .ver_ = PC_VERSION, - .cmd_ = e_cmd_add_publisher, - .pub_ = { .k8_ = { 3UL, 4UL, 5UL, 6UL } } - }; - SolPubkey p_id = {.x = { 0xff, }}; - SolPubkey pkey = {.x = { 1, }}; - SolPubkey skey = {.x = { 3, }}; - uint64_t pqty = 100; - pc_price_t sptr[1]; - sol_memset( sptr, 0, sizeof( pc_price_t ) ); - sptr->magic_ = PC_MAGIC; - sptr->ver_ = PC_VERSION; - sptr->type_ = PC_ACCTYPE_PRICE; - sptr->ptype_ = PC_PTYPE_PRICE; - 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 = &skey, - .lamports = &pqty, - .data_len = sizeof( pc_price_t ), - .data = (uint8_t*)sptr, - .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 - }; - - // Expect the instruction to fail, because the price account isn't rent exempt - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - - // Now give the price account enough lamports to be rent exempt - acc[1].lamports = &PRICE_ACCOUNT_LAMPORTS; - - cr_assert( SUCCESS == dispatch( &prm, acc ) ); - cr_assert( sptr->num_ == 1 ); - cr_assert( pc_pub_key_equal( &idata.pub_, &sptr->comp_[0].pub_ ) ); - // cant add twice - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - - // invalid params - sol_memset( sptr, 0, sizeof( pc_price_t ) ); - sptr->magic_ = PC_MAGIC; - sptr->ver_ = PC_VERSION; - sptr->type_ = PC_ACCTYPE_PRICE; - // bad price account - sptr->magic_ = 0; - cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) ); - sptr->magic_ = PC_MAGIC; - - // fill up price node - for( unsigned i = 0;; ++i ) { - idata.pub_.k8_[0] = 10 + i; - uint64_t rc = dispatch( &prm, acc ); - if ( rc != SUCCESS ) { - cr_assert( i == ( unsigned )(PC_COMP_SIZE) ); - break; - } - cr_assert( sptr->num_ == i + 1 ); - cr_assert( pc_pub_key_equal( &idata.pub_, &sptr->comp_[i].pub_ ) ); - cr_assert( rc == SUCCESS ); - } -} - Test(oracle, pc_size ) { cr_assert( sizeof( pc_pub_key_t ) == 32 ); cr_assert( sizeof( pc_map_table_t ) == diff --git a/program/rust/src/c_oracle_header.rs b/program/rust/src/c_oracle_header.rs index 18aab8997..f74e2c7d2 100644 --- a/program/rust/src/c_oracle_header.rs +++ b/program/rust/src/c_oracle_header.rs @@ -7,6 +7,7 @@ use bytemuck::{ Pod, Zeroable, }; +use solana_program::pubkey::Pubkey; use std::mem::size_of; //bindings.rs is generated by build.rs to include //things defined in bindings.h @@ -51,6 +52,15 @@ impl PythAccount for pc_price_t { const INITIAL_SIZE: u32 = PC_PRICE_T_COMP_OFFSET as u32; } +impl pc_pub_key_t { + pub fn new_unique() -> pc_pub_key_t { + let solana_unique = Pubkey::new_unique(); + pc_pub_key_t { + k1_: solana_unique.to_bytes(), + } + } +} + #[cfg(target_endian = "little")] unsafe impl Zeroable for pc_acc { diff --git a/program/rust/src/tests/mod.rs b/program/rust/src/tests/mod.rs index 2ce9259b3..42b869cde 100644 --- a/program/rust/src/tests/mod.rs +++ b/program/rust/src/tests/mod.rs @@ -1,5 +1,7 @@ mod test_add_mapping; +mod test_add_price; mod test_add_product; +mod test_add_publisher; mod test_init_mapping; mod test_set_min_pub; mod test_upd_product; diff --git a/program/rust/src/tests/test_add_price.rs b/program/rust/src/tests/test_add_price.rs new file mode 100644 index 000000000..dbb8e39fb --- /dev/null +++ b/program/rust/src/tests/test_add_price.rs @@ -0,0 +1,218 @@ +use crate::tests::test_utils::AccountSetup; +use bytemuck::bytes_of; +use solana_program::program_error::ProgramError; +use solana_program::pubkey::Pubkey; + +use crate::c_oracle_header::{ + cmd_add_price, + cmd_hdr_t, + command_t_e_cmd_add_price, + command_t_e_cmd_add_product, + pc_map_table_t, + pc_price_t, + pc_prod_t, + PC_VERSION, +}; +use crate::rust_oracle::{ + add_price, + add_product, + clear_account, + initialize_checked, + load_checked, + pubkey_equal, + pubkey_is_zero, +}; + +#[test] +fn test_add_price() { + let hdr_add_product = cmd_hdr_t { + ver_: PC_VERSION, + cmd_: command_t_e_cmd_add_product as i32, + }; + + let mut hdr_add_price = cmd_add_price { + ver_: PC_VERSION, + cmd_: command_t_e_cmd_add_price as i32, + expo_: 1, + ptype_: 1, + }; + let instruction_data_add_product = bytes_of::(&hdr_add_product); + let mut instruction_data_add_price = bytes_of::(&hdr_add_price); + + let program_id = Pubkey::new_unique(); + + let mut funding_setup = AccountSetup::new_funding(); + let funding_account = funding_setup.to_account_info(); + + let mut mapping_setup = AccountSetup::new::(&program_id); + let mapping_account = mapping_setup.to_account_info(); + initialize_checked::(&mapping_account, PC_VERSION).unwrap(); + + let mut product_setup = AccountSetup::new::(&program_id); + let product_account = product_setup.to_account_info(); + + let mut price_setup = AccountSetup::new::(&program_id); + let mut price_account = price_setup.to_account_info(); + + let mut price_setup_2 = AccountSetup::new::(&program_id); + let price_account_2 = price_setup_2.to_account_info(); + + assert!(add_product( + &program_id, + &[ + funding_account.clone(), + mapping_account.clone(), + product_account.clone() + ], + instruction_data_add_product + ) + .is_ok()); + + assert!(add_price( + &program_id, + &[ + funding_account.clone(), + product_account.clone(), + price_account.clone() + ], + instruction_data_add_price + ) + .is_ok()); + + { + let price_data = load_checked::(&price_account, PC_VERSION).unwrap(); + let product_data = load_checked::(&product_account, PC_VERSION).unwrap(); + assert_eq!(price_data.expo_, 1); + assert_eq!(price_data.ptype_, 1); + assert!(pubkey_equal( + &price_data.prod_, + &product_account.key.to_bytes() + )); + assert!(pubkey_is_zero(&price_data.next_)); + assert!(pubkey_equal( + &product_data.px_acc_, + &price_account.key.to_bytes() + )); + } + + assert!(add_price( + &program_id, + &[ + funding_account.clone(), + product_account.clone(), + price_account_2.clone() + ], + instruction_data_add_price + ) + .is_ok()); + + { + let price_data_2 = load_checked::(&price_account_2, PC_VERSION).unwrap(); + let product_data = load_checked::(&product_account, PC_VERSION).unwrap(); + assert_eq!(price_data_2.expo_, 1); + assert_eq!(price_data_2.ptype_, 1); + assert!(pubkey_equal( + &price_data_2.prod_, + &product_account.key.to_bytes() + )); + assert!(pubkey_equal( + &price_data_2.next_, + &price_account.key.to_bytes() + )); + assert!(pubkey_equal( + &product_data.px_acc_, + &price_account_2.key.to_bytes() + )); + } + + // Wrong number of accounts + assert_eq!( + add_price( + &program_id, + &[funding_account.clone(), product_account.clone()], + instruction_data_add_price + ), + Err(ProgramError::InvalidArgument) + ); + + // Price account is already initialized + assert_eq!( + add_price( + &program_id, + &[ + funding_account.clone(), + product_account.clone(), + price_account.clone() + ], + instruction_data_add_price + ), + Err(ProgramError::InvalidArgument) + ); + + clear_account(&price_account).unwrap(); + + // Wrong ptype + hdr_add_price = cmd_add_price { + ver_: PC_VERSION, + cmd_: command_t_e_cmd_add_price as i32, + expo_: 6, + ptype_: 0, + }; + instruction_data_add_price = bytes_of::(&hdr_add_price); + + + assert_eq!( + add_price( + &program_id, + &[ + funding_account.clone(), + product_account.clone(), + price_account.clone() + ], + instruction_data_add_price + ), + Err(ProgramError::InvalidArgument) + ); + + + //Price not signing + hdr_add_price = cmd_add_price { + ver_: PC_VERSION, + cmd_: command_t_e_cmd_add_price as i32, + expo_: 6, + ptype_: 1, + }; + instruction_data_add_price = bytes_of::(&hdr_add_price); + price_account.is_signer = false; + + assert_eq!( + add_price( + &program_id, + &[ + funding_account.clone(), + product_account.clone(), + price_account.clone() + ], + instruction_data_add_price + ), + Err(ProgramError::InvalidArgument) + ); + + // Fresh product account + price_account.is_signer = true; + clear_account(&product_account).unwrap(); + + + assert_eq!( + add_price( + &program_id, + &[ + funding_account.clone(), + product_account.clone(), + price_account.clone() + ], + instruction_data_add_price + ), + Err(ProgramError::InvalidArgument) + ); +} diff --git a/program/rust/src/tests/test_add_product.rs b/program/rust/src/tests/test_add_product.rs index 5f198766c..2aa629691 100644 --- a/program/rust/src/tests/test_add_product.rs +++ b/program/rust/src/tests/test_add_product.rs @@ -13,6 +13,7 @@ use crate::c_oracle_header::{ command_t_e_cmd_add_product, pc_map_table_t, pc_prod_t, + PythAccount, PC_ACCTYPE_PRODUCT, PC_MAGIC, PC_MAP_TABLE_SIZE, @@ -71,6 +72,7 @@ fn test_add_product() { assert_eq!(product_data.type_, PC_ACCTYPE_PRODUCT); assert_eq!(product_data.size_, size_of::() as u32); assert_eq!(mapping_data.num_, 1); + assert_eq!(mapping_data.size_, (pc_map_table_t::INITIAL_SIZE + 32)); assert!(pubkey_equal( &mapping_data.prod_[0], &product_account.key.to_bytes() @@ -90,6 +92,7 @@ fn test_add_product() { { let mapping_data = load_checked::(&mapping_account, PC_VERSION).unwrap(); assert_eq!(mapping_data.num_, 2); + assert_eq!(mapping_data.size_, (pc_map_table_t::INITIAL_SIZE + 2 * 32)); assert!(pubkey_equal( &mapping_data.prod_[1], &product_account_2.key.to_bytes() @@ -141,6 +144,10 @@ fn test_add_product() { ) .is_ok()); let mapping_data = load_checked::(&mapping_account, PC_VERSION).unwrap(); + assert_eq!( + mapping_data.size_, + pc_map_table_t::INITIAL_SIZE + (i + 1) * 32 + ); assert_eq!(mapping_data.num_, i + 1); } diff --git a/program/rust/src/tests/test_add_publisher.rs b/program/rust/src/tests/test_add_publisher.rs new file mode 100644 index 000000000..9d0591f34 --- /dev/null +++ b/program/rust/src/tests/test_add_publisher.rs @@ -0,0 +1,144 @@ +use crate::tests::test_utils::AccountSetup; +use bytemuck::bytes_of; +use solana_program::program_error::ProgramError; +use solana_program::pubkey::Pubkey; +use solana_program::rent::Rent; + +use crate::c_oracle_header::{ + cmd_add_publisher, + command_t_e_cmd_add_product, + pc_price_comp_t, + pc_price_t, + pc_pub_key_t, + PythAccount, + PC_COMP_SIZE, + PC_VERSION, +}; +use std::mem::size_of; + +use crate::rust_oracle::{ + add_publisher, + clear_account, + initialize_checked, + load_checked, + pubkey_equal, +}; + +#[test] +fn test_add_publisher() { + let program_id = Pubkey::new_unique(); + let publisher = pc_pub_key_t::new_unique(); + + let mut cmd = cmd_add_publisher { + ver_: PC_VERSION, + cmd_: command_t_e_cmd_add_product as i32, + pub_: publisher, + }; + let mut instruction_data = bytes_of::(&cmd); + + let mut funding_setup = AccountSetup::new_funding(); + let funding_account = funding_setup.to_account_info(); + + let mut price_setup = AccountSetup::new::(&program_id); + let price_account = price_setup.to_account_info(); + initialize_checked::(&price_account, PC_VERSION).unwrap(); + + + **price_account.try_borrow_mut_lamports().unwrap() = 100; + + // Expect the instruction to fail, because the price account isn't rent exempt + assert_eq!( + add_publisher( + &program_id, + &[funding_account.clone(), price_account.clone(),], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); + + // Now give the price account enough lamports to be rent exempt + **price_account.try_borrow_mut_lamports().unwrap() = + Rent::minimum_balance(&Rent::default(), pc_price_t::minimum_size()); + + + assert!(add_publisher( + &program_id, + &[funding_account.clone(), price_account.clone(),], + instruction_data + ) + .is_ok()); + + { + let price_data = load_checked::(&price_account, PC_VERSION).unwrap(); + assert_eq!(price_data.num_, 1); + assert_eq!( + price_data.size_, + pc_price_t::INITIAL_SIZE + (size_of::() as u32) + ); + assert!(pubkey_equal( + &price_data.comp_[0].pub_, + bytes_of(&publisher) + )); + } + + // Can't add twice + assert_eq!( + add_publisher( + &program_id, + &[funding_account.clone(), price_account.clone(),], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); + + clear_account(&price_account).unwrap(); + + // Bad price account + assert_eq!( + add_publisher( + &program_id, + &[funding_account.clone(), price_account.clone(),], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); + + initialize_checked::(&price_account, PC_VERSION).unwrap(); + + //Fill up price node + for i in 0..PC_COMP_SIZE { + cmd.pub_ = pc_pub_key_t::new_unique(); + instruction_data = bytes_of::(&cmd); + assert!(add_publisher( + &program_id, + &[funding_account.clone(), price_account.clone(),], + instruction_data + ) + .is_ok()); + + + { + let price_data = load_checked::(&price_account, PC_VERSION).unwrap(); + assert_eq!(price_data.num_, i + 1); + assert!(pubkey_equal( + &price_data.comp_[i as usize].pub_, + bytes_of(&cmd.pub_) + )); + assert_eq!( + price_data.size_, + pc_price_t::INITIAL_SIZE + (size_of::() as u32) * (i + 1) + ); + } + } + + cmd.pub_ = pc_pub_key_t::new_unique(); + instruction_data = bytes_of::(&cmd); + assert_eq!( + add_publisher( + &program_id, + &[funding_account.clone(), price_account.clone(),], + instruction_data + ), + Err(ProgramError::InvalidArgument) + ); +} diff --git a/program/rust/src/tests/test_set_min_pub.rs b/program/rust/src/tests/test_set_min_pub.rs index 0ce65bbe9..319743bb9 100644 --- a/program/rust/src/tests/test_set_min_pub.rs +++ b/program/rust/src/tests/test_set_min_pub.rs @@ -1,12 +1,8 @@ use std::mem::size_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 crate::c_oracle_header::{ cmd_set_min_pub_t, @@ -20,42 +16,21 @@ use crate::rust_oracle::{ load_checked, set_min_pub, }; +use crate::tests::test_utils::AccountSetup; #[test] fn test_set_min_pub() { let mut instruction_data = [0u8; size_of::()]; let program_id = Pubkey::new_unique(); - let funding_key = Pubkey::new_unique(); - let price_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 price_balance = Rent::minimum_balance(&Rent::default(), size_of::()); - let mut price_raw_data = [0u8; size_of::()]; - let price_account = AccountInfo::new( - &price_key, - true, - true, - &mut price_balance, - &mut price_raw_data, - &program_id, - false, - Epoch::default(), - ); + let mut funding_setup = AccountSetup::new_funding(); + let funding_account = funding_setup.to_account_info(); + let mut price_setup = AccountSetup::new::(&program_id); + let price_account = price_setup.to_account_info(); initialize_checked::(&price_account, PC_VERSION).unwrap(); + assert_eq!(get_min_pub(&price_account), Ok(0)); populate_instruction(&mut instruction_data, 10); diff --git a/program/rust/src/tests/test_upd_product.rs b/program/rust/src/tests/test_upd_product.rs index 7f2ba72eb..1fda8445f 100644 --- a/program/rust/src/tests/test_upd_product.rs +++ b/program/rust/src/tests/test_upd_product.rs @@ -10,6 +10,7 @@ use crate::c_oracle_header::{ cmd_upd_product_t, command_t_e_cmd_upd_product, pc_prod_t, + PythAccount, PC_PROD_ACC_SIZE, PC_VERSION, }; @@ -46,6 +47,11 @@ fn test_upd_product() { .is_ok()); assert!(account_has_key_values(&product_account, &kvs).unwrap_or(false)); + { + let product_data = load_checked::(&product_account, PC_VERSION).unwrap(); + assert_eq!(product_data.size_, pc_prod_t::INITIAL_SIZE + 9); + } + // bad size on the 1st string in the key-value pair list instruction_data[size_of::()] = 2; assert_eq!( @@ -67,6 +73,10 @@ fn test_upd_product() { ) .is_ok()); assert!(account_has_key_values(&product_account, &kvs).unwrap_or(false)); + { + let product_data = load_checked::(&product_account, PC_VERSION).unwrap(); + assert_eq!(product_data.size_, pc_prod_t::INITIAL_SIZE); + } // uneven number of keys and values let bad_kvs = ["foo", "bar", "baz"];