diff --git a/programs/bpf/c/src/dup_accounts/dup_accounts.c b/programs/bpf/c/src/dup_accounts/dup_accounts.c new file mode 100644 index 0000000000..cce0a7195b --- /dev/null +++ b/programs/bpf/c/src/dup_accounts/dup_accounts.c @@ -0,0 +1,57 @@ +/** + * @brief Example C-based BPF program that exercises duplicate keyed ka + * passed to it + */ +#include + +/** + * Custom error for when input serialization fails + */ + +extern uint32_t entrypoint(const uint8_t *input) { + #define FAILURE 1 + #define INVALID_INPUT 2 + + SolKeyedAccount ka[4]; + SolParameters params = (SolParameters) { .ka = ka }; + + if (!sol_deserialize(input, ¶ms, SOL_ARRAY_SIZE(ka))) { + return INVALID_INPUT; + } + + switch (params.data[0]) { + case(1): + sol_log("modify first account userdata"); + ka[2].userdata[0] = 1; + break; + case(2): + sol_log("modify first account userdata"); + ka[3].userdata[0] = 2; + break; + case(3): + sol_log("modify both account userdata"); + ka[2].userdata[0] += 1; + ka[3].userdata[0] += 2; + break; + case(4): + sol_log("modify first account lamports"); + *ka[1].lamports -= 1; + *ka[2].lamports += 1; + break; + case(5): + sol_log("modify first account lamports"); + *ka[1].lamports -= 2; + *ka[3].lamports += 2; + break; + case(6): + sol_log("modify both account lamports"); + *ka[1].lamports -= 3; + *ka[2].lamports += 1; + *ka[3].lamports += 2; + break; + default: + sol_log("Unrecognized command"); + return FAILURE; + } + return SUCCESS; +} diff --git a/programs/bpf/rust/dup_accounts/src/lib.rs b/programs/bpf/rust/dup_accounts/src/lib.rs index f0d621ecc7..257826c337 100644 --- a/programs/bpf/rust/dup_accounts/src/lib.rs +++ b/programs/bpf/rust/dup_accounts/src/lib.rs @@ -12,32 +12,32 @@ fn process_instruction(_program_id: &Pubkey, accounts: &mut [AccountInfo], data: match data[0] { 1 => { info!("modify first account data"); - accounts[2].data[0] = 1; + accounts[2].m.borrow_mut().data[0] = 1; } 2 => { info!("modify first account data"); - accounts[3].data[0] = 2; + accounts[3].m.borrow_mut().data[0] = 2; } 3 => { - info!("modify both account data, should fail"); - accounts[2].data[0] = 1; - accounts[3].data[0] = 2; + info!("modify both account data"); + accounts[2].m.borrow_mut().data[0] += 1; + accounts[3].m.borrow_mut().data[0] += 2; } 4 => { info!("modify first account lamports"); - *accounts[1].lamports -= 1; - *accounts[2].lamports += 1; + *accounts[1].m.borrow_mut().lamports -= 1; + *accounts[2].m.borrow_mut().lamports += 1; } 5 => { info!("modify first account lamports"); - *accounts[1].lamports -= 2; - *accounts[3].lamports += 2; + *accounts[1].m.borrow_mut().lamports -= 2; + *accounts[3].m.borrow_mut().lamports += 2; } 6 => { - info!("modify both account lamports, should fail"); - *accounts[1].lamports -= 1; - *accounts[2].lamports += 1; - *accounts[3].lamports += 2; + info!("modify both account lamports"); + *accounts[1].m.borrow_mut().lamports -= 3; + *accounts[2].m.borrow_mut().lamports += 1; + *accounts[3].m.borrow_mut().lamports += 2; } _ => { info!("Unrecognized command"); diff --git a/programs/bpf/rust/external_spend/src/lib.rs b/programs/bpf/rust/external_spend/src/lib.rs index b7861a9889..9350ef5854 100644 --- a/programs/bpf/rust/external_spend/src/lib.rs +++ b/programs/bpf/rust/external_spend/src/lib.rs @@ -8,7 +8,7 @@ fn process_instruction(_program_id: &Pubkey, accounts: &mut [AccountInfo], _data // account 0 is the mint and not owned by this program, any debit of its lamports // should result in a failed program execution. Test to ensure that this debit // is seen by the runtime and fails as expected - *accounts[0].lamports -= 1; + *accounts[0].m.borrow_mut().lamports -= 1; SUCCESS } diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 7554e9830a..84edcd35d9 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -27,10 +27,14 @@ mod bpf { mod bpf_c { use super::*; use solana_runtime::loader_utils::create_invoke_instruction; + use solana_sdk::account::Account; use solana_sdk::bpf_loader; use solana_sdk::client::SyncClient; + use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::signature::KeypairUtil; use std::io::Read; + use std::sync::Arc; + use solana_sdk::pubkey::Pubkey; #[test] fn test_program_bpf_c() { @@ -72,6 +76,81 @@ mod bpf { } } } + + #[test] + fn test_program_bpf_c_duplicate_accounts() { + solana_logger::setup(); + + let filename = create_bpf_path("dup_accounts"); + let mut file = File::open(filename).unwrap(); + let mut elf = Vec::new(); + file.read_to_end(&mut elf).unwrap(); + + let GenesisConfigInfo { + genesis_config, + mint_keypair, + .. + } = create_genesis_config(50); + + let bank = Arc::new(Bank::new(&genesis_config)); + let bank_client = BankClient::new_shared(&bank); + let program_id = load_program(&bank_client, &mint_keypair, &bpf_loader::id(), elf); + + let payee_account = Account::new(10, 1, &program_id); + let payee_pubkey = Pubkey::new_rand(); + bank.store_account(&payee_pubkey, &payee_account); + + let account = Account::new(10, 1, &program_id); + let pubkey = Pubkey::new_rand(); + let account_metas = vec![ + AccountMeta::new(mint_keypair.pubkey(), true), + AccountMeta::new(payee_pubkey, false), + AccountMeta::new(pubkey, false), + AccountMeta::new(pubkey, false), + ]; + + bank.store_account(&pubkey, &account); + let instruction = Instruction::new(program_id, &1u8, account_metas.clone()); + let result = bank_client.send_instruction(&mint_keypair, instruction); + let data = bank_client.get_account_data(&pubkey).unwrap().unwrap(); + assert!(result.is_ok()); + assert_eq!(data[0], 1); + + bank.store_account(&pubkey, &account); + let instruction = Instruction::new(program_id, &2u8, account_metas.clone()); + let result = bank_client.send_instruction(&mint_keypair, instruction); + let data = bank_client.get_account_data(&pubkey).unwrap().unwrap(); + assert!(result.is_ok()); + assert_eq!(data[0], 2); + + bank.store_account(&pubkey, &account); + let instruction = Instruction::new(program_id, &3u8, account_metas.clone()); + let result = bank_client.send_instruction(&mint_keypair, instruction); + let data = bank_client.get_account_data(&pubkey).unwrap().unwrap(); + assert!(result.is_ok()); + assert_eq!(data[0], 3); + + bank.store_account(&pubkey, &account); + let instruction = Instruction::new(program_id, &4u8, account_metas.clone()); + let result = bank_client.send_instruction(&mint_keypair, instruction); + let lamports = bank_client.get_balance(&pubkey).unwrap(); + assert!(result.is_ok()); + assert_eq!(lamports, 11); + + bank.store_account(&pubkey, &account); + let instruction = Instruction::new(program_id, &5u8, account_metas.clone()); + let result = bank_client.send_instruction(&mint_keypair, instruction); + let lamports = bank_client.get_balance(&pubkey).unwrap(); + assert!(result.is_ok()); + assert_eq!(lamports, 12); + + bank.store_account(&pubkey, &account); + let instruction = Instruction::new(program_id, &6u8, account_metas.clone()); + let result = bank_client.send_instruction(&mint_keypair, instruction); + let lamports = bank_client.get_balance(&pubkey).unwrap(); + assert!(result.is_ok()); + assert_eq!(lamports, 13); + } } #[cfg(feature = "bpf_rust")] @@ -193,7 +272,9 @@ mod bpf { bank.store_account(&pubkey, &account); let instruction = Instruction::new(program_id, &3u8, account_metas.clone()); let result = bank_client.send_instruction(&mint_keypair, instruction); - assert!(!result.is_ok()); + let data = bank_client.get_account_data(&pubkey).unwrap().unwrap(); + assert!(result.is_ok()); + assert_eq!(data[0], 3); bank.store_account(&pubkey, &account); let instruction = Instruction::new(program_id, &4u8, account_metas.clone()); @@ -212,7 +293,9 @@ mod bpf { bank.store_account(&pubkey, &account); let instruction = Instruction::new(program_id, &6u8, account_metas.clone()); let result = bank_client.send_instruction(&mint_keypair, instruction); - assert!(!result.is_ok()); + let lamports = bank_client.get_balance(&pubkey).unwrap(); + assert!(result.is_ok()); + assert_eq!(lamports, 13); } } } diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 0ae59262fa..f52bfdfa6f 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -8,7 +8,6 @@ use log::*; use solana_rbpf::{memory_region::MemoryRegion, EbpfVm}; use solana_sdk::{ account::KeyedAccount, - hash::{Hash, Hasher}, instruction::InstructionError, instruction_processor_utils::{is_executable, limited_deserialize, next_keyed_account}, loader_instruction::LoaderInstruction, @@ -16,7 +15,6 @@ use solana_sdk::{ sysvar::rent, }; use std::{ - collections::HashMap, convert::TryFrom, io::{prelude::*, Error}, mem, @@ -46,6 +44,16 @@ pub fn check_elf(prog: &[u8]) -> Result<(), Error> { Ok(()) } +/// Look for a duplicate account and return its position if found +pub fn is_dup(accounts: &[KeyedAccount], keyed_account: &KeyedAccount) -> (bool, usize) { + for (i, account) in accounts.iter().enumerate() { + if account == keyed_account { + return (true, i); + } + } + (false, 0) +} + pub fn serialize_parameters( program_id: &Pubkey, keyed_accounts: &[KeyedAccount], @@ -56,16 +64,22 @@ pub fn serialize_parameters( let mut v: Vec = Vec::new(); v.write_u64::(keyed_accounts.len() as u64) .unwrap(); - for keyed_account in keyed_accounts.iter() { - v.write_u64::(keyed_account.signer_key().is_some() as u64) - .unwrap(); - v.write_all(keyed_account.unsigned_key().as_ref()).unwrap(); - v.write_u64::(keyed_account.lamports()?) - .unwrap(); - v.write_u64::(keyed_account.data_len()? as u64) - .unwrap(); - v.write_all(&keyed_account.try_account_ref()?.data).unwrap(); - v.write_all(keyed_account.owner()?.as_ref()).unwrap(); + for (i, keyed_account) in keyed_accounts.iter().enumerate() { + let (is_dup, position) = is_dup(&keyed_accounts[..i], keyed_account); + if is_dup { + v.write_u8(position as u8).unwrap(); + } else { + v.write_u8(0).unwrap(); + v.write_u64::(keyed_account.signer_key().is_some() as u64) + .unwrap(); + v.write_all(keyed_account.unsigned_key().as_ref()).unwrap(); + v.write_u64::(keyed_account.lamports()?) + .unwrap(); + v.write_u64::(keyed_account.data_len()? as u64) + .unwrap(); + v.write_all(&keyed_account.try_account_ref()?.data).unwrap(); + v.write_all(keyed_account.owner()?.as_ref()).unwrap(); + } } v.write_u64::(data.len() as u64).unwrap(); v.write_all(data).unwrap(); @@ -79,63 +93,25 @@ pub fn deserialize_parameters( ) -> Result<(), InstructionError> { assert_eq!(32, mem::size_of::()); - let calculate_hash = |lamports: u64, data: &[u8]| -> Hash { - let mut hasher = Hasher::default(); - let mut buf = [0u8; 8]; - LittleEndian::write_u64(&mut buf[..], lamports); - hasher.hash(&buf); - hasher.hash(data); - hasher.result() - }; - - // remember any duplicate accounts - let mut map: HashMap = HashMap::new(); - for (i, keyed_account) in keyed_accounts.iter().enumerate() { - if keyed_accounts[i + 1..].contains(keyed_account) - && !map.contains_key(keyed_account.unsigned_key()) - { - let hash = calculate_hash( - keyed_account.lamports()?, - &keyed_account.try_account_ref()?.data, - ); - map.insert(*keyed_account.unsigned_key(), (hash, false)); - } - } - - let mut start = mem::size_of::(); + let mut start = mem::size_of::(); // number of accounts for keyed_account in keyed_accounts.iter() { - start += mem::size_of::() // signer_key boolean - + mem::size_of::(); // pubkey - let lamports = LittleEndian::read_u64(&buffer[start..]); - start += mem::size_of::() // lamports - + mem::size_of::(); // length tag - let end = start + keyed_account.data_len()?; - let data_start = start; - let data_end = end; - - // if duplicate, modified, and dirty, then bail - let mut do_update = true; - if let Some((hash, is_dirty)) = map.get_mut(keyed_account.unsigned_key()) { - let new_hash = calculate_hash(lamports, &buffer[data_start..data_end]); - if *hash != new_hash { - if *is_dirty { - return Err(InstructionError::DuplicateAccountOutOfSync); - } - *is_dirty = true; // fail if modified again - } else { - do_update = false; // no changes, don't need to update account - } - } - if do_update { - keyed_account.try_account_ref_mut()?.lamports = lamports; + let duplicate = buffer[start] != 0; // duplicate info + start += 1; + if !duplicate { + start += mem::size_of::(); // is_signer + start += mem::size_of::(); // pubkey + keyed_account.try_account_ref_mut()?.lamports = + LittleEndian::read_u64(&buffer[start..]); + start += mem::size_of::() // lamports + + mem::size_of::(); // data length + let end = start + keyed_account.data_len()?; keyed_account .try_account_ref_mut()? .data - .clone_from_slice(&buffer[data_start..data_end]); + .clone_from_slice(&buffer[start..end]); + start += keyed_account.data_len()? // data + + mem::size_of::(); // owner } - - start += keyed_account.data_len()? // data - + mem::size_of::(); // owner } Ok(()) } diff --git a/programs/bpf_loader/test_elfs/noop.so b/programs/bpf_loader/test_elfs/noop.so index 751dc72c8b..6081fb9252 100755 Binary files a/programs/bpf_loader/test_elfs/noop.so and b/programs/bpf_loader/test_elfs/noop.so differ diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index fadf26aba5..4b107d8e0a 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -226,31 +226,42 @@ SOL_FN_PREFIX bool sol_deserialize( return false; } params->ka_num = *(uint64_t *) input; - if (ka_num < *(uint64_t *) input) { + input += sizeof(uint64_t); + if (ka_num < params->ka_num) { return false; } - input += sizeof(uint64_t); for (int i = 0; i < params->ka_num; i++) { - // key - params->ka[i].is_signer = *(uint64_t *) input != 0; - input += sizeof(uint64_t); - params->ka[i].key = (SolPubkey *) input; - input += sizeof(SolPubkey); + uint8_t dup_info = input[0]; + input += sizeof(uint8_t); + if (dup_info == 0) { + // key + params->ka[i].is_signer = *(uint64_t *) input != 0; + input += sizeof(uint64_t); + params->ka[i].key = (SolPubkey *) input; + input += sizeof(SolPubkey); - // lamports - params->ka[i].lamports = (uint64_t *) input; - input += sizeof(uint64_t); + // lamports + params->ka[i].lamports = (uint64_t *) input; + input += sizeof(uint64_t); - // account userdata - params->ka[i].userdata_len = *(uint64_t *) input; - input += sizeof(uint64_t); - params->ka[i].userdata = (uint8_t *) input; - input += params->ka[i].userdata_len; + // account userdata + params->ka[i].userdata_len = *(uint64_t *) input; + input += sizeof(uint64_t); + params->ka[i].userdata = (uint8_t *) input; + input += params->ka[i].userdata_len; - // owner - params->ka[i].owner = (SolPubkey *) input; - input += sizeof(SolPubkey); + // owner + params->ka[i].owner = (SolPubkey *) input; + input += sizeof(SolPubkey); + } else { + params->ka[i].is_signer = params->ka[dup_info].is_signer; + params->ka[i].key = params->ka[dup_info].key; + params->ka[i].lamports = params->ka[dup_info].lamports; + params->ka[i].userdata_len = params->ka[dup_info].userdata_len; + params->ka[i].userdata = params->ka[dup_info].userdata; + params->ka[i].owner = params->ka[dup_info].owner; + } } params->data_len = *(uint64_t *) input; diff --git a/sdk/src/account_info.rs b/sdk/src/account_info.rs index 7b7bc30fb4..468439eee4 100644 --- a/sdk/src/account_info.rs +++ b/sdk/src/account_info.rs @@ -1,33 +1,46 @@ use crate::{account::Account, pubkey::Pubkey}; -use std::{cmp, fmt}; +use std::{ + cell::{Ref, RefCell, RefMut}, + cmp, fmt, + rc::Rc, +}; -/// AccountInfo -pub struct AccountInfo<'a> { - /// Public key of the account - pub key: &'a Pubkey, - /// Was the transaction signed by this account's public key? - pub is_signer: bool, +/// Account information that is mutable by a program +pub struct AccountInfoMut<'a> { /// Number of lamports owned by this account pub lamports: &'a mut u64, /// On-chain data within this account pub data: &'a mut [u8], +} +/// Account information +#[derive(Clone)] +pub struct AccountInfo<'a> { + /// Public key of the account + pub key: &'a Pubkey, + // Was the transaction signed by this account's public key? + pub is_signer: bool, + /// Account members that are mutable by the program + pub m: Rc>>, /// Program that owns this account pub owner: &'a Pubkey, } impl<'a> fmt::Debug for AccountInfo<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let data_len = cmp::min(64, self.data.len()); + let data_len = cmp::min(64, self.m.borrow().data.len()); let data_str = if data_len > 0 { - format!(" data: {}", hex::encode(self.data[..data_len].to_vec())) + format!( + " data: {}", + hex::encode(self.m.borrow().data[..data_len].to_vec()) + ) } else { "".to_string() }; write!( f, "AccountInfo {{ lamports: {} data.len: {} owner: {} {} }}", - self.lamports, - self.data.len(), + self.m.borrow().lamports, + self.m.borrow().data.len(), self.owner, data_str, ) @@ -47,6 +60,22 @@ impl<'a> AccountInfo<'a> { self.key } + pub fn try_account_ref(&'a self) -> Result, u32> { + self.try_borrow() + } + + pub fn try_account_ref_mut(&'a self) -> Result, u32> { + self.try_borrow_mut() + } + + fn try_borrow(&self) -> Result, u32> { + self.m.try_borrow().map_err(|_| std::u32::MAX) + } + + fn try_borrow_mut(&self) -> Result, u32> { + self.m.try_borrow_mut().map_err(|_| std::u32::MAX) + } + pub fn new( key: &'a Pubkey, is_signer: bool, @@ -57,57 +86,56 @@ impl<'a> AccountInfo<'a> { Self { key, is_signer, - lamports, - data, + m: Rc::new(RefCell::new(AccountInfoMut { lamports, data })), owner, } } pub fn deserialize_data(&self) -> Result { - bincode::deserialize(&self.data) + bincode::deserialize(&self.m.borrow().data) } pub fn serialize_data(&mut self, state: &T) -> Result<(), bincode::Error> { - if bincode::serialized_size(state)? > self.data.len() as u64 { + if bincode::serialized_size(state)? > self.m.borrow().data.len() as u64 { return Err(Box::new(bincode::ErrorKind::SizeLimit)); } - bincode::serialize_into(&mut self.data[..], state) + bincode::serialize_into(&mut self.m.borrow_mut().data[..], state) } } impl<'a> From<(&'a Pubkey, &'a mut Account)> for AccountInfo<'a> { fn from((key, account): (&'a Pubkey, &'a mut Account)) -> Self { - Self { + Self::new( key, - is_signer: false, - lamports: &mut account.lamports, - data: &mut account.data, - owner: &account.owner, - } + false, + &mut account.lamports, + &mut account.data, + &account.owner, + ) } } impl<'a> From<(&'a Pubkey, bool, &'a mut Account)> for AccountInfo<'a> { fn from((key, is_signer, account): (&'a Pubkey, bool, &'a mut Account)) -> Self { - Self { + Self::new( key, is_signer, - lamports: &mut account.lamports, - data: &mut account.data, - owner: &account.owner, - } + &mut account.lamports, + &mut account.data, + &account.owner, + ) } } impl<'a> From<&'a mut (Pubkey, Account)> for AccountInfo<'a> { fn from((key, account): &'a mut (Pubkey, Account)) -> Self { - Self { + Self::new( key, - is_signer: false, - lamports: &mut account.lamports, - data: &mut account.data, - owner: &account.owner, - } + false, + &mut account.lamports, + &mut account.data, + &account.owner, + ) } } @@ -120,12 +148,14 @@ pub fn create_is_signer_account_infos<'a>( ) -> Vec> { accounts .iter_mut() - .map(|(key, is_signer, account)| AccountInfo { - key, - is_signer: *is_signer, - lamports: &mut account.lamports, - data: &mut account.data, - owner: &account.owner, + .map(|(key, is_signer, account)| { + AccountInfo::new( + key, + *is_signer, + &mut account.lamports, + &mut account.data, + &account.owner, + ) }) .collect() } diff --git a/sdk/src/entrypoint.rs b/sdk/src/entrypoint.rs index 900d32bd06..3e84aa6ca6 100644 --- a/sdk/src/entrypoint.rs +++ b/sdk/src/entrypoint.rs @@ -4,10 +4,15 @@ extern crate alloc; -use crate::{account_info::AccountInfo, pubkey::Pubkey}; +use crate::{ + account_info::{AccountInfo, AccountInfoMut}, + pubkey::Pubkey, +}; use alloc::vec::Vec; use core::mem::size_of; use core::slice::{from_raw_parts, from_raw_parts_mut}; +use std::cell::RefCell; +use std::rc::Rc; /// User implemented program entrypoint /// @@ -15,7 +20,7 @@ use core::slice::{from_raw_parts, from_raw_parts_mut}; /// accounts: Accounts passed as part of the instruction /// data: Instruction data pub type ProcessInstruction = - fn(program_id: &Pubkey, accounts: &mut [AccountInfo], data: &[u8]) -> bool; + fn(program_id: &Pubkey, accounts: &mut [AccountInfo], data: &[u8]) -> u32; /// Programs indicate success with a return value of 0 pub const SUCCESS: u32 = 0; @@ -57,37 +62,45 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec(); + if dup_info == 0 { + let is_signer = { + #[allow(clippy::cast_ptr_alignment)] + let is_signer_val = *(input.add(offset) as *const u64); + (is_signer_val != 0) + }; + offset += size_of::(); + + let key: &Pubkey = &*(input.add(offset) as *const Pubkey); + offset += size_of::(); + #[allow(clippy::cast_ptr_alignment)] - let is_signer_val = *(input.add(offset) as *const u64); - (is_signer_val != 0) - }; - offset += size_of::(); + let lamports = &mut *(input.add(offset) as *mut u64); + offset += size_of::(); - let key: &Pubkey = &*(input.add(offset) as *const Pubkey); - offset += size_of::(); + #[allow(clippy::cast_ptr_alignment)] + let data_length = *(input.add(offset) as *const u64) as usize; + offset += size_of::(); - #[allow(clippy::cast_ptr_alignment)] - let lamports = &mut *(input.add(offset) as *mut u64); - offset += size_of::(); + let data = { from_raw_parts_mut(input.add(offset), data_length) }; + offset += data_length; - #[allow(clippy::cast_ptr_alignment)] - let data_length = *(input.add(offset) as *const u64) as usize; - offset += size_of::(); + let owner: &Pubkey = &*(input.add(offset) as *const Pubkey); + offset += size_of::(); - let data = { from_raw_parts_mut(input.add(offset), data_length) }; - offset += data_length; + let m = Rc::new(RefCell::new(AccountInfoMut { lamports, data })); - let owner: &Pubkey = &*(input.add(offset) as *const Pubkey); - offset += size_of::(); - - accounts.push(AccountInfo { - key, - is_signer, - lamports, - data, - owner, - }); + accounts.push(AccountInfo { + key, + is_signer, + m, + owner, + }); + } else { + // Duplicate account, clone the original + accounts.push(accounts[dup_info].clone()); + } } // Instruction data diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index b26b85b328..00b6e3c4df 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -2,7 +2,6 @@ extern crate self as solana_sdk; pub mod account; -pub mod account_info; pub mod account_utils; pub mod bpf_loader; pub mod clock; @@ -56,6 +55,7 @@ pub mod timing; pub use solana_sdk_macro::declare_id; // On-chain program specific modules +pub mod account_info; pub mod entrypoint; pub mod log; diff --git a/sdk/src/log.rs b/sdk/src/log.rs index d08e2699bd..bd01d5d7e8 100644 --- a/sdk/src/log.rs +++ b/sdk/src/log.rs @@ -89,9 +89,9 @@ pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) { sol_log("- Key"); account.key.log(); sol_log("- Lamports"); - sol_log_64(0, 0, 0, 0, *account.lamports); + sol_log_64(0, 0, 0, 0, *account.m.borrow().lamports); sol_log("- Account data length"); - sol_log_64(0, 0, 0, 0, account.data.len() as u64); + sol_log_64(0, 0, 0, 0, account.m.borrow().data.len() as u64); sol_log("- Owner"); account.owner.log(); } diff --git a/sdk/src/sysvar/mod.rs b/sdk/src/sysvar/mod.rs index b1b58ac001..c0743b69cf 100644 --- a/sdk/src/sysvar/mod.rs +++ b/sdk/src/sysvar/mod.rs @@ -71,10 +71,10 @@ pub trait Sysvar: bincode::serialize_into(&mut account.data[..], self).ok() } fn from_account_info(account_info: &AccountInfo) -> Option { - bincode::deserialize(&account_info.data).ok() + bincode::deserialize(&account_info.m.borrow().data).ok() } fn to_account_info(&self, account_info: &mut AccountInfo) -> Option<()> { - bincode::serialize_into(&mut account_info.data[..], self).ok() + bincode::serialize_into(&mut account_info.m.borrow_mut().data[..], self).ok() } fn from_keyed_account(keyed_account: &KeyedAccount) -> Result { if !Self::check_id(keyed_account.unsigned_key()) {