Implement account persistence

Accounts with data will now be persisted at the end of the program execution

Change-Id: I1dd29f521f5c659ced5758203acf532b645f3b44
This commit is contained in:
Hendrik Hofstadt 2021-06-11 17:14:21 +02:00
parent c3829b9266
commit b3b083b08a
7 changed files with 72 additions and 24 deletions

View File

@ -68,10 +68,10 @@ fn main() -> Result<(), ErrBox> {
payer: Signer(payer),
};
let init_args = types::BridgeConfig {
let init_args = bridge::instruction::Instruction::Initialize(types::BridgeConfig {
guardian_set_expiration_time: DEFAULT_GUARDIAN_SET_EXPIRATION_TIME,
fee: DEFAULT_MESSAGE_FEE,
};
});
let ix_data = init_args.try_to_vec()?;

View File

@ -96,6 +96,10 @@ impl<'a, 'b: 'a, 'c, T: DeserializePayload> Peel<'a, 'b, 'c> for PayloadMessage<
fn deps() -> Vec<Pubkey> {
Data::<'b, PostedMessage, { AccountState::Initialized }>::deps()
}
fn persist(&self, program_id: &Pubkey) -> Result<()> {
Data::persist(&self.0, program_id)
}
}
impl<'b, T: DeserializePayload> Deref for PayloadMessage<'b, T> {

View File

@ -80,7 +80,8 @@ pub use crate::{
};
/// Library name and version to print in entrypoint. Must be evaluated in this crate in order to do the right thing
pub const PKG_NAME_VERSION: &'static str = concat!(env!("CARGO_PKG_NAME"), " ", env!("CARGO_PKG_VERSION"));
pub const PKG_NAME_VERSION: &'static str =
concat!(env!("CARGO_PKG_NAME"), " ", env!("CARGO_PKG_VERSION"));
pub struct ExecutionContext<'a, 'b: 'a> {
/// A reference to the program_id of the current program.

View File

@ -41,7 +41,7 @@ macro_rules! solitaire {
Instruction::$row(ix_data) => {
let (mut accounts): ($row) = FromAccounts::from(p, &mut a.iter(), &()).unwrap();
$fn(&ExecutionContext{program_id: p, accounts: a}, &mut accounts, ix_data)?;
accounts.persist();
Persist::persist(&accounts, p)?;
Ok(())
}
)*
@ -128,6 +128,10 @@ macro_rules! data_wrapper {
fn deps() -> Vec<Pubkey> {
Data::<'_, $embed, { $state }>::deps()
}
fn persist(&self, program_id: &Pubkey) -> solitaire::Result<()> {
Data::<'_, $embed, { $state }>::persist(self, program_id)
}
}
impl<'b> solitaire::processors::seeded::Owned for $name<'b> {

View File

@ -26,6 +26,7 @@ use crate::{
Result,
SolitaireError,
};
use borsh::BorshSerialize;
/// Generic Peel trait. This provides a way to describe what each "peeled"
/// layer of our constraints should check.
@ -35,6 +36,8 @@ pub trait Peel<'a, 'b: 'a, 'c> {
Self: Sized;
fn deps() -> Vec<Pubkey>;
fn persist(&self, program_id: &Pubkey) -> Result<()>;
}
/// Peel a Derived Key
@ -49,9 +52,14 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>, const Seed: &'static str> Peel<'a, 'b,
_ => Err(SolitaireError::InvalidDerive(*ctx.info().key).into()),
}
}
fn deps() -> Vec<Pubkey> {
T::deps()
}
fn persist(&self, program_id: &Pubkey) -> Result<()> {
T::persist(self, program_id)
}
}
/// Peel a Signer.
@ -62,9 +70,14 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Signer<T> {
_ => Err(SolitaireError::InvalidSigner(*ctx.info().key).into()),
}
}
fn deps() -> Vec<Pubkey> {
T::deps()
}
fn persist(&self, program_id: &Pubkey) -> Result<()> {
T::persist(self, program_id)
}
}
/// Expicitly depend upon the System account.
@ -75,9 +88,14 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for System<T> {
_ => panic!(),
}
}
fn deps() -> Vec<Pubkey> {
T::deps()
}
fn persist(&self, program_id: &Pubkey) -> Result<()> {
T::persist(self, program_id)
}
}
/// Peel a Sysvar
@ -94,9 +112,14 @@ where
_ => Err(SolitaireError::InvalidSysvar(*ctx.info().key).into()),
}
}
fn deps() -> Vec<Pubkey> {
vec![]
}
fn persist(&self, _program_id: &Pubkey) -> Result<()> {
Ok(())
}
}
/// This is our structural recursion base case, the trait system will stop generating new nested
@ -108,12 +131,20 @@ impl<'a, 'b: 'a, 'c> Peel<'a, 'b, 'c> for Info<'b> {
fn deps() -> Vec<Pubkey> {
vec![]
}
fn persist(&self, _program_id: &Pubkey) -> Result<()> {
Ok(())
}
}
/// This is our structural recursion base case, the trait system will stop generating new nested
/// calls here.
impl<'a, 'b: 'a, 'c, T: BorshDeserialize + Owned + Default, const IsInitialized: AccountState>
Peel<'a, 'b, 'c> for Data<'b, T, IsInitialized>
impl<
'a,
'b: 'a,
'c,
T: BorshDeserialize + BorshSerialize + Owned + Default,
const IsInitialized: AccountState,
> Peel<'a, 'b, 'c> for Data<'b, T, IsInitialized>
{
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
let mut initialized = false;
@ -165,4 +196,19 @@ impl<'a, 'b: 'a, 'c, T: BorshDeserialize + Owned + Default, const IsInitialized:
vec![sysvar::rent::ID, system_program::ID]
}
fn persist(&self, program_id: &Pubkey) -> Result<()> {
// Only write to accounts owned by us
if self.0.owner != program_id {
return Ok(());
}
if !self.0.is_writable {
// TODO this needs to be checked properly
return Ok(());
}
self.1.serialize(&mut *self.0.data.borrow_mut())?;
Ok(())
}
}

View File

@ -1,3 +1,5 @@
use solana_program::pubkey::Pubkey;
pub trait Persist {
fn persist(self);
fn persist(&self, program_id: &Pubkey) -> crate::Result<()>;
}

View File

@ -129,15 +129,16 @@ pub fn derive_from_accounts(input: TokenStream) -> TokenStream {
fn deps() -> Vec<solana_program::pubkey::Pubkey> {
#deps_method
}
fn persist(&self, program_id: &solana_program::pubkey::Pubkey) -> solitaire::Result<()> {
solitaire::Persist::persist(self, program_id)
}
}
/// Macro generated implementation of Persist by Solitaire.
impl #type_impl_g solitaire::Persist for #name #type_g {
fn persist(self) {
use borsh::BorshSerialize;
//self.guardian_set.serialize(
// &mut *self.guardian_set.0.data.borrow_mut()
//);
fn persist(&self, program_id: &solana_program::pubkey::Pubkey) -> solitaire::Result<()> {
#persist_method
}
}
};
@ -256,24 +257,14 @@ fn generate_persist(name: &syn::Ident, data: &Data) -> TokenStream2 {
let ty = &f.ty;
quote! {
let #name: #ty = Peel::peel(&mut solitaire::Context::new(
pid,
iter,
data,
))?;
Peel::persist(&self.#name, program_id)?;
}
});
let names = fields.named.iter().map(|f| {
let name = &f.ident;
quote!(#name)
});
// Write out our iterator and return the filled structure.
quote! {
use solana_program::account_info::next_account_info;
#(#recurse;)*
Ok(#name { #(#names,)* })
Ok(())
}
}