Optimize account copies and use RefCell to handle duplicate accounts in BPF programs (#7958)

This commit is contained in:
Jack May 2020-01-24 10:54:26 -08:00 committed by GitHub
parent d400a64b9a
commit 34ed93d57c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 339 additions and 169 deletions

View File

@ -0,0 +1,57 @@
/**
* @brief Example C-based BPF program that exercises duplicate keyed ka
* passed to it
*/
#include <solana_sdk.h>
/**
* 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, &params, 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;
}

View File

@ -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");

View File

@ -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
}

View File

@ -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);
}
}
}

View File

@ -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<u8> = Vec::new();
v.write_u64::<LittleEndian>(keyed_accounts.len() as u64)
.unwrap();
for keyed_account in keyed_accounts.iter() {
v.write_u64::<LittleEndian>(keyed_account.signer_key().is_some() as u64)
.unwrap();
v.write_all(keyed_account.unsigned_key().as_ref()).unwrap();
v.write_u64::<LittleEndian>(keyed_account.lamports()?)
.unwrap();
v.write_u64::<LittleEndian>(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::<LittleEndian>(keyed_account.signer_key().is_some() as u64)
.unwrap();
v.write_all(keyed_account.unsigned_key().as_ref()).unwrap();
v.write_u64::<LittleEndian>(keyed_account.lamports()?)
.unwrap();
v.write_u64::<LittleEndian>(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::<LittleEndian>(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::<Pubkey>());
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<Pubkey, (Hash, bool)> = 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::<u64>();
let mut start = mem::size_of::<u64>(); // number of accounts
for keyed_account in keyed_accounts.iter() {
start += mem::size_of::<u64>() // signer_key boolean
+ mem::size_of::<Pubkey>(); // pubkey
let lamports = LittleEndian::read_u64(&buffer[start..]);
start += mem::size_of::<u64>() // lamports
+ mem::size_of::<u64>(); // 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::<u64>(); // is_signer
start += mem::size_of::<Pubkey>(); // pubkey
keyed_account.try_account_ref_mut()?.lamports =
LittleEndian::read_u64(&buffer[start..]);
start += mem::size_of::<u64>() // lamports
+ mem::size_of::<u64>(); // 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::<Pubkey>(); // owner
}
start += keyed_account.data_len()? // data
+ mem::size_of::<Pubkey>(); // owner
}
Ok(())
}

View File

@ -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;

View File

@ -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<RefCell<AccountInfoMut<'a>>>,
/// 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<Ref<AccountInfoMut>, u32> {
self.try_borrow()
}
pub fn try_account_ref_mut(&'a self) -> Result<RefMut<'a, AccountInfoMut>, u32> {
self.try_borrow_mut()
}
fn try_borrow(&self) -> Result<Ref<AccountInfoMut>, u32> {
self.m.try_borrow().map_err(|_| std::u32::MAX)
}
fn try_borrow_mut(&self) -> Result<RefMut<'a, AccountInfoMut>, 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<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
bincode::deserialize(&self.data)
bincode::deserialize(&self.m.borrow().data)
}
pub fn serialize_data<T: serde::Serialize>(&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<AccountInfo<'a>> {
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()
}

View File

@ -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<AccountInfo<'a
let mut accounts = Vec::with_capacity(num_accounts);
for _ in 0..num_accounts {
let is_signer = {
let dup_info = *(input.add(offset) as *const u8) as usize;
offset += size_of::<u8>();
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::<u64>();
let key: &Pubkey = &*(input.add(offset) as *const Pubkey);
offset += size_of::<Pubkey>();
#[allow(clippy::cast_ptr_alignment)]
let is_signer_val = *(input.add(offset) as *const u64);
(is_signer_val != 0)
};
offset += size_of::<u64>();
let lamports = &mut *(input.add(offset) as *mut u64);
offset += size_of::<u64>();
let key: &Pubkey = &*(input.add(offset) as *const Pubkey);
offset += size_of::<Pubkey>();
#[allow(clippy::cast_ptr_alignment)]
let data_length = *(input.add(offset) as *const u64) as usize;
offset += size_of::<u64>();
#[allow(clippy::cast_ptr_alignment)]
let lamports = &mut *(input.add(offset) as *mut u64);
offset += size_of::<u64>();
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::<u64>();
let owner: &Pubkey = &*(input.add(offset) as *const Pubkey);
offset += size_of::<Pubkey>();
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::<Pubkey>();
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

View File

@ -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;

View File

@ -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();
}

View File

@ -71,10 +71,10 @@ pub trait Sysvar:
bincode::serialize_into(&mut account.data[..], self).ok()
}
fn from_account_info(account_info: &AccountInfo) -> Option<Self> {
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<Self, InstructionError> {
if !Self::check_id(keyed_account.unsigned_key()) {