Improve sysvar and account state handling
Change-Id: Ic60433f921c14ce66f6039245a2964dee4f60e8f
This commit is contained in:
parent
b7c5e08117
commit
13c7e693c2
|
@ -183,12 +183,6 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-mac"
|
||||
version = "0.8.0"
|
||||
|
@ -212,17 +206,6 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
|
@ -277,15 +260,6 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da"
|
||||
|
||||
[[package]]
|
||||
name = "fixed-hash"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c"
|
||||
dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.4"
|
||||
|
@ -418,28 +392,6 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066"
|
||||
dependencies = [
|
||||
"derivative",
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
|
@ -452,16 +404,6 @@ version = "0.2.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "primitive-types"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2415937401cb030a2a0a4d922483f945fa068f52a7dbb22ce0fe5f2b6f6adace"
|
||||
dependencies = [
|
||||
"fixed-hash",
|
||||
"uint",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "0.1.5"
|
||||
|
@ -745,26 +687,6 @@ dependencies = [
|
|||
"solana-program",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spl-token"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbfa8fd791aeb4d7ad5fedb7872478de9f4e8b4fcb02dfd9e7f2f9ae3f3ddd73"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"num_enum",
|
||||
"solana-program",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.0"
|
||||
|
@ -811,20 +733,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "token-bridge"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"byteorder",
|
||||
"primitive-types",
|
||||
"rocksalt",
|
||||
"sha3",
|
||||
"solana-program",
|
||||
"solitaire",
|
||||
"spl-token",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.8"
|
||||
|
@ -840,18 +748,6 @@ version = "1.13.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
||||
|
||||
[[package]]
|
||||
name = "uint"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e11fe9a9348741cf134085ad57c249508345fe16411b3d7fb4ff2da2f1d6382e"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crunchy",
|
||||
"hex",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
|
|
|
@ -36,6 +36,9 @@ pub enum SolitaireError {
|
|||
/// Owner of the account is ambiguous
|
||||
AmbiguousOwner,
|
||||
|
||||
/// Account has already been initialized
|
||||
AlreadyInitialized(Pubkey),
|
||||
|
||||
Custom(u64),
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#![feature(const_generics)]
|
||||
#![feature(const_generics_defaults)]
|
||||
#![allow(warnings)]
|
||||
|
||||
pub use rocksalt::*;
|
||||
|
@ -124,8 +123,8 @@ impl<T, const Seed: &'static str> Wrap for Derive<T, Seed> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: BorshSerialize + Owned, const IsInitialized: bool, const Lazy: bool> Wrap
|
||||
for Data<'a, T, IsInitialized, Lazy>
|
||||
impl<'a, T: BorshSerialize + Owned + Default, const IsInitialized: AccountState> Wrap
|
||||
for Data<'a, T, IsInitialized>
|
||||
{
|
||||
fn wrap(&self) -> Vec<AccountMeta> {
|
||||
todo!()
|
||||
|
|
|
@ -84,10 +84,10 @@ macro_rules! solitaire {
|
|||
macro_rules! data_wrapper {
|
||||
($name:ident, $embed:ty) => {
|
||||
#[repr(transparent)]
|
||||
pub struct $name<'b>(Data<'b, $embed>);
|
||||
pub struct $name<'b>(Data<'b, $embed, { solitaire::AccountState::Uninitialized }>);
|
||||
|
||||
impl<'b> std::ops::Deref for $name<'b> {
|
||||
type Target = Data<'b, $embed>;
|
||||
type Target = Data<'b, $embed, { solitaire::AccountState::Uninitialized }>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
return &self.0;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
use solana_program::pubkey::Pubkey;
|
||||
use solana_program::{
|
||||
pubkey::Pubkey,
|
||||
sysvar::Sysvar as SolanaSysvar,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
processors::seeded::Owned,
|
||||
AccountState,
|
||||
Data,
|
||||
Derive,
|
||||
Info,
|
||||
|
@ -14,8 +18,8 @@ pub trait Keyed<'a, 'b: 'a> {
|
|||
fn info(&'a self) -> &Info<'b>;
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, T: Owned, const IsInitialized: bool, const Lazy: bool> Keyed<'a, 'b>
|
||||
for Data<'b, T, IsInitialized, Lazy>
|
||||
impl<'a, 'b: 'a, T: Owned + Default, const IsInitialized: AccountState> Keyed<'a, 'b>
|
||||
for Data<'b, T, IsInitialized>
|
||||
{
|
||||
fn info(&'a self) -> &'a Info<'b> {
|
||||
&self.0
|
||||
|
@ -31,12 +35,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, T, Var> Keyed<'a, 'b> for Sysvar<T, Var>
|
||||
where
|
||||
T: Keyed<'a, 'b>,
|
||||
{
|
||||
impl<'a, 'b: 'a, Var: SolanaSysvar> Keyed<'a, 'b> for Sysvar<'b, Var> {
|
||||
fn info(&'a self) -> &'a Info<'b> {
|
||||
self.0.info()
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,14 +70,16 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for System<T> {
|
|||
}
|
||||
|
||||
/// Peel a Sysvar
|
||||
impl<'a, 'b: 'a, 'c, T, Var> Peel<'a, 'b, 'c> for Sysvar<T, Var>
|
||||
impl<'a, 'b: 'a, 'c, Var> Peel<'a, 'b, 'c> for Sysvar<'b, Var>
|
||||
where
|
||||
T: Peel<'a, 'b, 'c>,
|
||||
Var: SolanaSysvar + SysvarId,
|
||||
Var: SolanaSysvar,
|
||||
{
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||
match <Var as SysvarId>::check_id(ctx.info().key) {
|
||||
true => T::peel(ctx).map(|v| Sysvar(v, PhantomData)),
|
||||
match Var::check_id(ctx.info().key) {
|
||||
true => Ok(Sysvar(
|
||||
ctx.info().clone(),
|
||||
Var::from_account_info(ctx.info())?,
|
||||
)),
|
||||
_ => Err(SolitaireError::InvalidSysvar(*ctx.info().key).into()),
|
||||
}
|
||||
}
|
||||
|
@ -93,19 +95,40 @@ impl<'a, 'b: 'a, 'c> Peel<'a, 'b, 'c> for Info<'b> {
|
|||
|
||||
/// 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, const IsInitialized: bool, const Lazy: bool>
|
||||
Peel<'a, 'b, 'c> for Data<'b, T, IsInitialized, Lazy>
|
||||
impl<'a, 'b: 'a, 'c, T: BorshDeserialize + 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;
|
||||
// If we're initializing the type, we should emit system/rent as deps.
|
||||
if !IsInitialized {
|
||||
ctx.deps.push(sysvar::rent::ID);
|
||||
ctx.deps.push(system_program::ID);
|
||||
}
|
||||
let data: T = match IsInitialized {
|
||||
AccountState::Uninitialized => {
|
||||
ctx.deps.push(sysvar::rent::ID);
|
||||
ctx.deps.push(system_program::ID);
|
||||
|
||||
let data = T::try_from_slice(&mut *ctx.info().data.borrow_mut())?;
|
||||
if **ctx.info().lamports.borrow() != 0 {
|
||||
return Err(SolitaireError::AlreadyInitialized(*ctx.info().key));
|
||||
}
|
||||
T::default()
|
||||
}
|
||||
AccountState::Initialized => {
|
||||
initialized = true;
|
||||
T::try_from_slice(&mut *ctx.info().data.borrow_mut())?
|
||||
}
|
||||
AccountState::MaybeInitialized => {
|
||||
ctx.deps.push(sysvar::rent::ID);
|
||||
ctx.deps.push(system_program::ID);
|
||||
|
||||
if IsInitialized {
|
||||
if **ctx.info().lamports.borrow() == 0 {
|
||||
T::default()
|
||||
} else {
|
||||
initialized = true;
|
||||
T::try_from_slice(&mut *ctx.info().data.borrow_mut())?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if initialized {
|
||||
match data.owner() {
|
||||
AccountOwner::This => {
|
||||
if ctx.info().owner != ctx.this {
|
||||
|
|
|
@ -2,6 +2,7 @@ use super::keyed::Keyed;
|
|||
use crate::{
|
||||
system_instruction,
|
||||
AccountInfo,
|
||||
AccountState,
|
||||
CreationLamports,
|
||||
Data,
|
||||
Deref,
|
||||
|
@ -15,7 +16,6 @@ use crate::{
|
|||
SolitaireError,
|
||||
System,
|
||||
Sysvar,
|
||||
Uninitialized,
|
||||
};
|
||||
use borsh::{
|
||||
BorshSchema,
|
||||
|
@ -48,8 +48,8 @@ pub trait Owned {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Owned, const IsInitialized: bool, const Lazy: bool> Owned
|
||||
for Data<'a, T, IsInitialized, Lazy>
|
||||
impl<'a, T: Owned + Default, const IsInitialized: AccountState> Owned
|
||||
for Data<'a, T, IsInitialized>
|
||||
{
|
||||
fn owner(&self) -> AccountOwner {
|
||||
self.1.owner()
|
||||
|
@ -83,7 +83,7 @@ pub trait Creatable<'a, I> {
|
|||
) -> Result<()>;
|
||||
}
|
||||
|
||||
impl<T: BorshSerialize + Owned, const IsInitialized: bool> AccountSize
|
||||
impl<T: BorshSerialize + Owned + Default, const IsInitialized: AccountState> AccountSize
|
||||
for Data<'_, T, IsInitialized>
|
||||
{
|
||||
fn size(&self) -> usize {
|
||||
|
@ -113,8 +113,8 @@ impl<'a, 'b: 'a, K, T: AccountSize + Seeded<K> + Keyed<'a, 'b> + Owned> Creatabl
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, const Seed: &'static str, T: BorshSerialize + Owned> Creatable<'a, Option<()>>
|
||||
for Derive<Data<'_, T, Uninitialized>, Seed>
|
||||
impl<'a, const Seed: &'static str, T: BorshSerialize + Owned + Default> Creatable<'a, Option<()>>
|
||||
for Derive<Data<'_, T, { AccountState::Uninitialized }>, Seed>
|
||||
{
|
||||
fn create(
|
||||
&'a self,
|
||||
|
|
|
@ -10,6 +10,7 @@ use solana_program::{
|
|||
program::invoke_signed,
|
||||
pubkey::Pubkey,
|
||||
system_instruction,
|
||||
sysvar::Sysvar as SolanaSysvar,
|
||||
};
|
||||
use std::ops::{
|
||||
Deref,
|
||||
|
@ -22,12 +23,18 @@ use crate::{
|
|||
Derive,
|
||||
ExecutionContext,
|
||||
Result,
|
||||
Uninitialized,
|
||||
};
|
||||
|
||||
/// A short alias for AccountInfo.
|
||||
pub type Info<'r> = AccountInfo<'r>;
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum AccountState {
|
||||
Initialized,
|
||||
Uninitialized,
|
||||
MaybeInitialized,
|
||||
}
|
||||
|
||||
/// An account that is known to contain serialized data.
|
||||
///
|
||||
/// Note on const generics:
|
||||
|
@ -36,17 +43,15 @@ pub type Info<'r> = AccountInfo<'r>;
|
|||
/// parameter assignments. But these DO work in the consumption side so a user can still happily
|
||||
/// use this type by writing for example:
|
||||
///
|
||||
/// Data<(), Uninitialized, Lazy>
|
||||
///
|
||||
/// But here, we must write `Lazy: bool = true` for now unfortunately.
|
||||
/// Data<(), { AccountState::Uninitialized }>
|
||||
#[rustfmt::skip]
|
||||
pub struct Data < 'r, T: Owned, const IsInitialized: bool = true, const Lazy: bool = false > (
|
||||
pub struct Data < 'r, T: Owned + Default + Default, const IsInitialized: AccountState> (
|
||||
pub Info<'r >,
|
||||
pub T,
|
||||
);
|
||||
|
||||
impl<'r, T: Owned, const IsInitialized: bool, const Lazy: bool> Deref
|
||||
for Data<'r, T, IsInitialized, Lazy>
|
||||
impl<'r, T: Owned + Default, const IsInitialized: AccountState> Deref
|
||||
for Data<'r, T, IsInitialized>
|
||||
{
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
@ -54,14 +59,30 @@ impl<'r, T: Owned, const IsInitialized: bool, const Lazy: bool> Deref
|
|||
}
|
||||
}
|
||||
|
||||
impl<'r, T: Owned, const IsInitialized: bool, const Lazy: bool> DerefMut
|
||||
for Data<'r, T, IsInitialized, Lazy>
|
||||
impl<'r, T: Owned + Default, const IsInitialized: AccountState> DerefMut
|
||||
for Data<'r, T, IsInitialized>
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.1
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r, T: Owned + Default, const IsInitialized: AccountState> Data<'r, T, IsInitialized> {
|
||||
/// Is the account already initialized / created
|
||||
pub fn is_initialized(&self) -> bool {
|
||||
**self.0.lamports.borrow() != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Sysvar<'b, Var: SolanaSysvar>(pub AccountInfo<'b>, pub Var);
|
||||
|
||||
impl<'b, Var: SolanaSysvar> Deref for Sysvar<'b, Var> {
|
||||
type Target = Var;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
impl<const Seed: &'static str> Derive<AccountInfo<'_>, Seed> {
|
||||
pub fn create(
|
||||
&self,
|
||||
|
@ -82,7 +103,9 @@ impl<const Seed: &'static str> Derive<AccountInfo<'_>, Seed> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<const Seed: &'static str, T: BorshSerialize + Owned> Derive<Data<'_, T, Uninitialized>, Seed> {
|
||||
impl<const Seed: &'static str, T: BorshSerialize + Owned + Default>
|
||||
Derive<Data<'_, T, { AccountState::Uninitialized }>, Seed>
|
||||
{
|
||||
pub fn create(
|
||||
&self,
|
||||
ctx: &ExecutionContext,
|
||||
|
|
|
@ -17,6 +17,7 @@ use std::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::Info;
|
||||
use borsh::{
|
||||
BorshDeserialize,
|
||||
BorshSerialize,
|
||||
|
@ -28,28 +29,9 @@ pub struct Signer<Next>(pub Next);
|
|||
#[repr(transparent)]
|
||||
pub struct System<Next>(pub Next);
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct Sysvar<Next, Var>(pub Next, pub PhantomData<Var>);
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct Derive<Next, const Seed: &'static str>(pub Next);
|
||||
|
||||
/// A tag for accounts that should be deserialized lazily.
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const Lazy: bool = true;
|
||||
|
||||
/// A tag for accounts that should be deserialized immediately (the default).
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const Strict: bool = false;
|
||||
|
||||
/// A tag for accounts that are expected to have already been initialized.
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const Initialized: bool = true;
|
||||
|
||||
/// A tag for accounts that must be uninitialized.
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const Uninitialized: bool = false;
|
||||
|
||||
// Several traits are required for types defined here, they cannot be defined in another file due
|
||||
// to orphan instance limitations.
|
||||
|
||||
|
@ -66,19 +48,6 @@ impl<T> DerefMut for Signer<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, Var> Deref for Sysvar<T, Var> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { std::mem::transmute(&self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Var> DerefMut for Sysvar<T, Var> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { std::mem::transmute(&mut self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for System<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
|
Loading…
Reference in New Issue