Skip to content

Commit

Permalink
lang: new internal writer to use bpf mem syscalls (#1589)
Browse files Browse the repository at this point in the history
  • Loading branch information
callensm authored Mar 12, 2022
1 parent 2529b06 commit ad8aec2
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ incremented for features.

* cli: Add `anchor clean` command that's the same as `cargo clean` but preserves keypairs inside `target/deploy` ([#1470](https://github.com/project-serum/anchor/issues/1470)).
* lang: Add new `AccountSysvarMismatch` error code and test cases for sysvars ([#1535](https://github.com/project-serum/anchor/pull/1535)).
* lang: Replace `std::io::Cursor` with a custom `Write` impl that uses the Solana mem syscalls ([#1589](https://github.com/project-serum/anchor/pull/1589)).
* spl: Add support for revoke instruction ([#1493](https://github.com/project-serum/anchor/pull/1493)).
* ts: Add provider parameter to `Spl.token` factory method ([#1597](https://github.com/project-serum/anchor/pull/1597)).

Expand Down
5 changes: 3 additions & 2 deletions lang/src/accounts/account.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Account container that checks ownership on deserialization.
use crate::bpf_writer::BpfWriter;
use crate::error::ErrorCode;
use crate::*;
use solana_program::account_info::AccountInfo;
Expand Down Expand Up @@ -333,8 +334,8 @@ impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> AccountsEx
let info = self.to_account_info();
let mut data = info.try_borrow_mut_data()?;
let dst: &mut [u8] = &mut data;
let mut cursor = std::io::Cursor::new(dst);
self.account.try_serialize(&mut cursor)?;
let mut writer = BpfWriter::new(dst);
self.account.try_serialize(&mut writer)?;
}
Ok(())
}
Expand Down
5 changes: 3 additions & 2 deletions lang/src/accounts/account_loader.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Type facilitating on demand zero copy deserialization.
use crate::bpf_writer::BpfWriter;
use crate::error::ErrorCode;
use crate::{
Accounts, AccountsClose, AccountsExit, Owner, Result, ToAccountInfo, ToAccountInfos,
Expand Down Expand Up @@ -225,8 +226,8 @@ impl<'info, T: ZeroCopy + Owner> AccountsExit<'info> for AccountLoader<'info, T>
fn exit(&self, _program_id: &Pubkey) -> Result<()> {
let mut data = self.acc_info.try_borrow_mut_data()?;
let dst: &mut [u8] = &mut data;
let mut cursor = std::io::Cursor::new(dst);
cursor.write_all(&T::discriminator()).unwrap();
let mut writer = BpfWriter::new(dst);
writer.write_all(&T::discriminator()).unwrap();
Ok(())
}
}
Expand Down
5 changes: 3 additions & 2 deletions lang/src/accounts/loader.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::bpf_writer::BpfWriter;
use crate::error::ErrorCode;
use crate::{
Accounts, AccountsClose, AccountsExit, Result, ToAccountInfo, ToAccountInfos, ToAccountMetas,
Expand Down Expand Up @@ -168,8 +169,8 @@ impl<'info, T: ZeroCopy> AccountsExit<'info> for Loader<'info, T> {
fn exit(&self, _program_id: &Pubkey) -> Result<()> {
let mut data = self.acc_info.try_borrow_mut_data()?;
let dst: &mut [u8] = &mut data;
let mut cursor = std::io::Cursor::new(dst);
cursor.write_all(&T::discriminator()).unwrap();
let mut writer = BpfWriter::new(dst);
writer.write_all(&T::discriminator()).unwrap();
Ok(())
}
}
Expand Down
5 changes: 3 additions & 2 deletions lang/src/accounts/program_account.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#[allow(deprecated)]
use crate::accounts::cpi_account::CpiAccount;
use crate::bpf_writer::BpfWriter;
use crate::error::ErrorCode;
use crate::{
AccountDeserialize, AccountSerialize, Accounts, AccountsClose, AccountsExit, Result,
Expand Down Expand Up @@ -98,8 +99,8 @@ impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AccountsExit<'info
let info = self.to_account_info();
let mut data = info.try_borrow_mut_data()?;
let dst: &mut [u8] = &mut data;
let mut cursor = std::io::Cursor::new(dst);
self.inner.account.try_serialize(&mut cursor)?;
let mut writer = BpfWriter::new(dst);
self.inner.account.try_serialize(&mut writer)?;
Ok(())
}
}
Expand Down
5 changes: 3 additions & 2 deletions lang/src/accounts/state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#[allow(deprecated)]
use crate::accounts::cpi_account::CpiAccount;
use crate::bpf_writer::BpfWriter;
use crate::error::ErrorCode;
use crate::{
AccountDeserialize, AccountSerialize, Accounts, AccountsExit, Result, ToAccountInfo,
Expand Down Expand Up @@ -148,8 +149,8 @@ impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AccountsExit<'info
let info = self.to_account_info();
let mut data = info.try_borrow_mut_data()?;
let dst: &mut [u8] = &mut data;
let mut cursor = std::io::Cursor::new(dst);
self.inner.account.try_serialize(&mut cursor)?;
let mut writer = BpfWriter::new(dst);
self.inner.account.try_serialize(&mut writer)?;
Ok(())
}
}
Expand Down
46 changes: 46 additions & 0 deletions lang/src/bpf_writer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use solana_program::program_memory::sol_memcpy;
use std::cmp;
use std::io::{self, Write};

#[derive(Debug, Default)]
pub struct BpfWriter<T> {
inner: T,
pos: u64,
}

impl<T> BpfWriter<T> {
pub fn new(inner: T) -> Self {
Self { inner, pos: 0 }
}
}

impl Write for BpfWriter<&mut [u8]> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.pos >= self.inner.len() as u64 {
return Ok(0);
}

let amt = cmp::min(
self.inner.len().saturating_sub(self.pos as usize),
buf.len(),
);
sol_memcpy(&mut self.inner[(self.pos as usize)..], buf, amt);
self.pos += amt as u64;
Ok(amt)
}

fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
if self.write(buf)? == buf.len() {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to write whole buffer",
))
}
}

fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
5 changes: 3 additions & 2 deletions lang/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::bpf_writer::BpfWriter;
use crate::error::ErrorCode;
use crate::prelude::error;
use crate::Result;
Expand All @@ -14,8 +15,8 @@ pub fn close<'info>(info: AccountInfo<'info>, sol_destination: AccountInfo<'info
// Mark the account discriminator as closed.
let mut data = info.try_borrow_mut_data()?;
let dst: &mut [u8] = &mut data;
let mut cursor = std::io::Cursor::new(dst);
cursor
let mut writer = BpfWriter::new(dst);
writer
.write_all(&crate::__private::CLOSED_ACCOUNT_DISCRIMINATOR)
.map_err(|_| error!(ErrorCode::AccountDidNotSerialize))
}
1 change: 1 addition & 0 deletions lang/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use std::io::Write;
mod account_meta;
pub mod accounts;
mod bpf_upgradeable_state;
mod bpf_writer;
mod common;
pub mod context;
mod ctor;
Expand Down

0 comments on commit ad8aec2

Please sign in to comment.