Implement Seeded trait and account creation

Change-Id: I355b88e07b872f8b4869fa9b7fa8dcae4806527d
This commit is contained in:
Hendrik Hofstadt 2021-06-02 12:40:18 +02:00
parent e2195c9b17
commit 88a94a9129
2 changed files with 173 additions and 18 deletions

View File

@ -2,6 +2,9 @@
#![feature(const_generics_defaults)]
#![allow(warnings)]
pub mod seeded;
pub use seeded::*;
pub use rocksalt::*;
// Lacking:
@ -32,6 +35,7 @@ pub use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
account_info::next_account_info,
instruction::AccountMeta,
program::invoke_signed,
program_error::ProgramError,
program_pack::Pack,
rent::Rent,
@ -297,9 +301,57 @@ impl<T, const Seed: &'static str> DerefMut for Derive<T, Seed> {
}
}
impl<T, const Seed: &'static str> Seeded for Derive<T, Seed> {
fn seeds(self) -> Vec<Vec<Vec<u8>>> {
vec![vec![Seed.try_to_vec().unwrap()]]
pub trait Keyed {
fn pubkey(&self) -> &Pubkey;
}
impl<'r, T, const IsInitialized: bool, const Lazy: bool> Keyed
for Data<'r, T, IsInitialized, Lazy>
{
fn pubkey(&self) -> &Pubkey {
self.0.key
}
}
impl<T> Keyed for Signer<T>
where
T: Keyed,
{
fn pubkey(&self) -> &Pubkey {
self.0.pubkey()
}
}
impl<T, Var> Keyed for Sysvar<T, Var>
where
T: Keyed,
{
fn pubkey(&self) -> &Pubkey {
self.0.pubkey()
}
}
impl<T> Keyed for System<T>
where
T: Keyed,
{
fn pubkey(&self) -> &Pubkey {
self.0.pubkey()
}
}
impl<T, const Seed: &'static str> Keyed for Derive<T, Seed>
where
T: Keyed,
{
fn pubkey(&self) -> &Pubkey {
self.0.pubkey()
}
}
impl<'r> Keyed for Info<'r> {
fn pubkey(&self) -> &Pubkey {
self.key
}
}
@ -335,7 +387,7 @@ impl<const Seed: &'static str> Derive<AccountInfo<'_>, Seed> {
space as u64,
owner,
);
invoke_signed(&ix, ctx.accounts, &[&[Seed.as_bytes()]])
Ok(invoke_signed(&ix, ctx.accounts, &[&[Seed.as_bytes()]])?)
}
}
@ -355,7 +407,7 @@ impl<const Seed: &'static str, T: BorshSerialize> Derive<Data<'_, T, Uninitializ
size as u64,
ctx.program_id,
);
invoke_signed(&ix, ctx.accounts, &[&[Seed.as_bytes()]])
Ok(invoke_signed(&ix, ctx.accounts, &[&[Seed.as_bytes()]])?)
}
}
@ -455,6 +507,7 @@ impl<T> Wrap for Signer<T> {
todo!()
}
}
impl<T, const Seed: &'static str> Wrap for Derive<T, Seed> {
fn wrap(&self) -> Vec<AccountMeta> {
todo!()
@ -470,7 +523,7 @@ impl<'a, T: BorshSerialize, const IsInitialized: bool, const Lazy: bool> Wrap
}
pub trait InstructionContext<'a> {
fn verify(&self) -> Result<()> {
fn verify(&self, program_id: &Pubkey) -> Result<()> {
Ok(())
}

View File

@ -0,0 +1,102 @@
use crate::{
system_instruction,
AccountInfo,
CreationLamports,
Data,
Deref,
Derive,
ExecutionContext,
FromAccounts,
Info,
Keyed,
Peel,
Result,
Signer,
SolitaireError,
System,
Sysvar,
Uninitialized,
};
use borsh::{BorshSchema, BorshSerialize};
use solana_program::{program::invoke_signed, pubkey::Pubkey};
pub trait AccountSize {
fn size(&self) -> usize;
}
pub trait Seeded<I> {
fn seeds(&self, accs: I) -> Vec<Vec<Vec<u8>>>;
fn verify_derivation(&self, program_id: &Pubkey, accs: I) -> Result<()>
where
Self: Keyed,
{
let seeds = self.seeds(accs);
let (derived, bump) = Pubkey::find_program_address(&[], program_id); //TODO
if &derived == self.pubkey() {
Ok(())
} else {
Err(SolitaireError::InvalidDerive(*self.pubkey()))
}
}
}
pub trait Creatable<I> {
fn create(
&self,
accs: I,
ctx: &ExecutionContext,
payer: &Pubkey,
lamports: CreationLamports,
) -> Result<()>;
}
impl<T: BorshSerialize, const IsInitialized: bool> AccountSize for Data<'_, T, IsInitialized> {
fn size(&self) -> usize {
self.1.try_to_vec().unwrap().len()
}
}
impl<'a, 'b: 'a, K, T: AccountSize + Seeded<K> + Keyed> Creatable<K> for T {
fn create(
&self,
accs: K,
ctx: &ExecutionContext<'_, '_>,
payer: &Pubkey,
lamports: CreationLamports,
) -> Result<()> {
let seeds = self.seeds(accs);
let size = self.size();
let ix = system_instruction::create_account(
payer,
self.pubkey(),
lamports.amount(size),
size as u64,
ctx.program_id,
);
Ok(invoke_signed(&ix, ctx.accounts, &[])?) // TODO use seeds
}
}
impl<const Seed: &'static str, T: BorshSerialize> Creatable<Option<()>>
for Derive<Data<'_, T, Uninitialized>, Seed>
{
fn create(
&self,
_: Option<()>,
ctx: &ExecutionContext,
payer: &Pubkey,
lamports: CreationLamports,
) -> Result<()> {
// Get serialized struct size
let size = self.0.try_to_vec().unwrap().len();
let ix = system_instruction::create_account(
payer,
self.0 .0.key,
lamports.amount(size),
size as u64,
ctx.program_id,
);
Ok(invoke_signed(&ix, ctx.accounts, &[&[Seed.as_bytes()]])?)
}
}