Add peel mutability checks for accounts.
Change-Id: Ic6a6fadd13a2b41d60a0c98f3b5d80d23ac263a6
This commit is contained in:
parent
72951531f6
commit
76066c8cc6
|
@ -12,6 +12,9 @@ pub type ErrBox = Box<dyn std::error::Error>;
|
||||||
/// There are several places in Solitaire that might fail, we want descriptive errors.
|
/// There are several places in Solitaire that might fail, we want descriptive errors.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SolitaireError {
|
pub enum SolitaireError {
|
||||||
|
/// The AccountInfo parser expected a mutable key where a readonly was found, or vice versa.
|
||||||
|
InvalidMutability(Pubkey),
|
||||||
|
|
||||||
/// The AccountInfo parser expected a Signer, but the account did not sign.
|
/// The AccountInfo parser expected a Signer, but the account did not sign.
|
||||||
InvalidSigner(Pubkey),
|
InvalidSigner(Pubkey),
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,26 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>, const Seed: &'static str> Peel<'a, 'b,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Peel a Mutable key.
|
||||||
|
impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Mut<T>
|
||||||
|
{
|
||||||
|
fn peel<I>(mut ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||||
|
ctx.immutable = false;
|
||||||
|
match ctx.info().is_writable {
|
||||||
|
true => T::peel(ctx).map(|v| Mut(v)),
|
||||||
|
_ => Err(SolitaireError::InvalidMutability(*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.
|
/// Peel a Signer.
|
||||||
impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Signer<T> {
|
impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Signer<T> {
|
||||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||||
|
@ -126,6 +146,10 @@ where
|
||||||
/// calls here.
|
/// calls here.
|
||||||
impl<'a, 'b: 'a, 'c> Peel<'a, 'b, 'c> for Info<'b> {
|
impl<'a, 'b: 'a, 'c> Peel<'a, 'b, 'c> for Info<'b> {
|
||||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||||
|
if ctx.immutable && ctx.info().is_writable {
|
||||||
|
return Err(SolitaireError::InvalidMutability(*ctx.info().key).into());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ctx.info().clone())
|
Ok(ctx.info().clone())
|
||||||
}
|
}
|
||||||
fn deps() -> Vec<Pubkey> {
|
fn deps() -> Vec<Pubkey> {
|
||||||
|
@ -147,6 +171,10 @@ impl<
|
||||||
> Peel<'a, 'b, 'c> for Data<'b, T, IsInitialized>
|
> Peel<'a, 'b, 'c> for Data<'b, T, IsInitialized>
|
||||||
{
|
{
|
||||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||||
|
if ctx.immutable && ctx.info().is_writable {
|
||||||
|
return Err(SolitaireError::InvalidMutability(*ctx.info().key).into());
|
||||||
|
}
|
||||||
|
|
||||||
// If we're initializing the type, we should emit system/rent as deps.
|
// If we're initializing the type, we should emit system/rent as deps.
|
||||||
let (initialized, data): (bool, T) = match IsInitialized {
|
let (initialized, data): (bool, T) = match IsInitialized {
|
||||||
AccountState::Uninitialized => {
|
AccountState::Uninitialized => {
|
||||||
|
|
|
@ -14,22 +14,29 @@ pub struct Context<'a, 'b: 'a, 'c, T> {
|
||||||
/// A reference to the program_id of the current program.
|
/// A reference to the program_id of the current program.
|
||||||
pub this: &'a Pubkey,
|
pub this: &'a Pubkey,
|
||||||
|
|
||||||
|
/// A reference to the instructions account list, one or more keys may be extracted during
|
||||||
|
/// the peeling process.
|
||||||
pub iter: &'c mut Iter<'a, AccountInfo<'b>>,
|
pub iter: &'c mut Iter<'a, AccountInfo<'b>>,
|
||||||
|
|
||||||
/// This is a reference to the instruction data we are processing this
|
/// Reference to the data passed to the current instruction.
|
||||||
/// account for.
|
|
||||||
pub data: &'a T,
|
pub data: &'a T,
|
||||||
|
|
||||||
|
/// An optional account info for this Peelable item, some fields may be other structures that
|
||||||
|
/// do not themselves have an account info associated with the field.
|
||||||
pub info: Option<&'a AccountInfo<'b>>,
|
pub info: Option<&'a AccountInfo<'b>>,
|
||||||
|
|
||||||
|
/// Whether to enforce immutability.
|
||||||
|
pub immutable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b: 'a, 'c, T> Context<'a, 'b, 'c, T> {
|
impl<'a, 'b: 'a, 'c, T> Context<'a, 'b, 'c, T> {
|
||||||
pub fn new(program: &'a Pubkey, iter: &'c mut Iter<'a, AccountInfo<'b>>, data: &'a T) -> Self {
|
pub fn new(program: &'a Pubkey, iter: &'c mut Iter<'a, AccountInfo<'b>>, data: &'a T) -> Self {
|
||||||
Context {
|
Context {
|
||||||
this: program,
|
this: program,
|
||||||
|
info: None,
|
||||||
|
immutable: true,
|
||||||
iter,
|
iter,
|
||||||
data,
|
data,
|
||||||
info: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ use borsh::{
|
||||||
BorshSerialize,
|
BorshSerialize,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Mut<Next>(pub Next);
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Signer<Next>(pub Next);
|
pub struct Signer<Next>(pub Next);
|
||||||
|
|
||||||
|
@ -48,6 +51,19 @@ impl<T> DerefMut for Signer<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for Mut<T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { std::mem::transmute(&self.0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for Mut<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { std::mem::transmute(&mut self.0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Deref for System<T> {
|
impl<T> Deref for System<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
|
Loading…
Reference in New Issue