This reverts commit 7fe39c61ad
.
This commit is contained in:
parent
6984260330
commit
1ec9af7e21
|
@ -360,8 +360,6 @@ jobs:
|
||||||
path: tests/escrow
|
path: tests/escrow
|
||||||
- cmd: cd tests/pyth && anchor test --skip-lint && npx tsc --noEmit
|
- cmd: cd tests/pyth && anchor test --skip-lint && npx tsc --noEmit
|
||||||
path: tests/pyth
|
path: tests/pyth
|
||||||
- cmd: cd tests/realloc && anchor test --skip-lint && npx tsc --noEmit
|
|
||||||
path: tests/realloc
|
|
||||||
- cmd: cd tests/system-accounts && anchor test --skip-lint
|
- cmd: cd tests/system-accounts && anchor test --skip-lint
|
||||||
path: tests/system-accounts
|
path: tests/system-accounts
|
||||||
- cmd: cd tests/misc && anchor test --skip-lint && npx tsc --noEmit
|
- cmd: cd tests/misc && anchor test --skip-lint && npx tsc --noEmit
|
||||||
|
|
|
@ -12,7 +12,6 @@ The minor version will be incremented upon a breaking change and the patch versi
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* lang: Add `realloc`, `realloc::payer`, and `realloc::zero` as a new constraint group for program accounts ([#1943](https://github.com/project-serum/anchor/pull/1943)).
|
|
||||||
* lang: Add `PartialEq` and `Eq` for `anchor_lang::Error` ([#1544](https://github.com/project-serum/anchor/pull/1544)).
|
* lang: Add `PartialEq` and `Eq` for `anchor_lang::Error` ([#1544](https://github.com/project-serum/anchor/pull/1544)).
|
||||||
* cli: Add `--skip-build` to `anchor publish` ([#1786](https://github.
|
* cli: Add `--skip-build` to `anchor publish` ([#1786](https://github.
|
||||||
com/project-serum/anchor/pull/1841)).
|
com/project-serum/anchor/pull/1841)).
|
||||||
|
|
|
@ -44,7 +44,6 @@ use syn::parse_macro_input;
|
||||||
///
|
///
|
||||||
/// - [Normal Constraints](#normal-constraints)
|
/// - [Normal Constraints](#normal-constraints)
|
||||||
/// - [SPL Constraints](#spl-constraints)
|
/// - [SPL Constraints](#spl-constraints)
|
||||||
///
|
|
||||||
/// # Normal Constraints
|
/// # Normal Constraints
|
||||||
/// <table>
|
/// <table>
|
||||||
/// <thead>
|
/// <thead>
|
||||||
|
@ -419,44 +418,6 @@ use syn::parse_macro_input;
|
||||||
/// </code></pre>
|
/// </code></pre>
|
||||||
/// </td>
|
/// </td>
|
||||||
/// </tr>
|
/// </tr>
|
||||||
/// <tr>
|
|
||||||
/// <td>
|
|
||||||
/// <code>#[account(realloc = <space>, realloc::payer = <target>, realloc::zero = <bool>)]</code>
|
|
||||||
/// </td>
|
|
||||||
/// <td>
|
|
||||||
/// Used to <a href="https://docs.rs/solana-program/latest/solana_program/account_info/struct.AccountInfo.html#method.realloc" target = "_blank" rel = "noopener noreferrer">realloc</a>
|
|
||||||
/// program account space at the beginning of an instruction.
|
|
||||||
/// <br><br>
|
|
||||||
/// The account must be marked as <code>mut</code> and applied to either <code>Account</code> or <code>AccountLoader</code> types.
|
|
||||||
/// <br><br>
|
|
||||||
/// If the change in account data length is additive, lamports will be transferred from the <code>realloc::payer</code> into the
|
|
||||||
/// program account in order to maintain rent exemption. Likewise, if the change is subtractive, lamports will be transferred from
|
|
||||||
/// the program account back into the <code>realloc::payer</code>.
|
|
||||||
/// <br><br>
|
|
||||||
/// The <code>realloc::zero</code> constraint is required in order to determine whether the new memory should be zero initialized after
|
|
||||||
/// reallocation. Please read the documentation on the <code>AccountInfo::realloc</code> function linked above to understand the
|
|
||||||
/// caveats regarding compute units when providing <code>true</code or <code>false</code> to this flag.
|
|
||||||
/// <br><br>
|
|
||||||
/// Example:
|
|
||||||
/// <pre>
|
|
||||||
/// #[derive(Accounts)]
|
|
||||||
/// pub struct Example {
|
|
||||||
/// #[account(mut)]
|
|
||||||
/// pub payer: Signer<'info>,
|
|
||||||
/// #[account(
|
|
||||||
/// mut,
|
|
||||||
/// seeds = [b"example"],
|
|
||||||
/// bump,
|
|
||||||
/// realloc = 8 + std::mem::size_of::<MyType>() + 100,
|
|
||||||
/// realloc::payer = payer,
|
|
||||||
/// realloc::zero = false,
|
|
||||||
/// )]
|
|
||||||
/// pub acc: Account<'info, MyType>,
|
|
||||||
/// pub system_program: Program<'info, System>,
|
|
||||||
/// }
|
|
||||||
/// </pre>
|
|
||||||
/// </td>
|
|
||||||
/// </tr>
|
|
||||||
/// </tbody>
|
/// </tbody>
|
||||||
/// </table>
|
/// </table>
|
||||||
///
|
///
|
||||||
|
|
|
@ -59,7 +59,6 @@ pub fn linearize(c_group: &ConstraintGroup) -> Vec<Constraint> {
|
||||||
associated_token,
|
associated_token,
|
||||||
token_account,
|
token_account,
|
||||||
mint,
|
mint,
|
||||||
realloc,
|
|
||||||
} = c_group.clone();
|
} = c_group.clone();
|
||||||
|
|
||||||
let mut constraints = Vec::new();
|
let mut constraints = Vec::new();
|
||||||
|
@ -70,9 +69,6 @@ pub fn linearize(c_group: &ConstraintGroup) -> Vec<Constraint> {
|
||||||
if let Some(c) = init {
|
if let Some(c) = init {
|
||||||
constraints.push(Constraint::Init(c));
|
constraints.push(Constraint::Init(c));
|
||||||
}
|
}
|
||||||
if let Some(c) = realloc {
|
|
||||||
constraints.push(Constraint::Realloc(c));
|
|
||||||
}
|
|
||||||
if let Some(c) = seeds {
|
if let Some(c) = seeds {
|
||||||
constraints.push(Constraint::Seeds(c));
|
constraints.push(Constraint::Seeds(c));
|
||||||
}
|
}
|
||||||
|
@ -134,7 +130,6 @@ fn generate_constraint(f: &Field, c: &Constraint) -> proc_macro2::TokenStream {
|
||||||
Constraint::AssociatedToken(c) => generate_constraint_associated_token(f, c),
|
Constraint::AssociatedToken(c) => generate_constraint_associated_token(f, c),
|
||||||
Constraint::TokenAccount(c) => generate_constraint_token_account(f, c),
|
Constraint::TokenAccount(c) => generate_constraint_token_account(f, c),
|
||||||
Constraint::Mint(c) => generate_constraint_mint(f, c),
|
Constraint::Mint(c) => generate_constraint_mint(f, c),
|
||||||
Constraint::Realloc(c) => generate_constraint_realloc(f, c),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,46 +320,6 @@ pub fn generate_constraint_rent_exempt(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_constraint_realloc(f: &Field, c: &ConstraintReallocGroup) -> proc_macro2::TokenStream {
|
|
||||||
let field = &f.ident;
|
|
||||||
let new_space = &c.space;
|
|
||||||
let payer = &c.payer;
|
|
||||||
let zero = &c.zero;
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
let __anchor_rent = Rent::get()?;
|
|
||||||
let __field_info = #field.to_account_info();
|
|
||||||
let __additive = #new_space > __field_info.data_len();
|
|
||||||
|
|
||||||
let __delta_space = if __additive {
|
|
||||||
#new_space.checked_sub(__field_info.data_len()).unwrap()
|
|
||||||
} else {
|
|
||||||
__field_info.data_len().checked_sub(#new_space).unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
if __delta_space > 0 {
|
|
||||||
if __additive {
|
|
||||||
anchor_lang::system_program::transfer(
|
|
||||||
anchor_lang::context::CpiContext::new(
|
|
||||||
system_program.to_account_info(),
|
|
||||||
anchor_lang::system_program::Transfer {
|
|
||||||
from: #payer.to_account_info(),
|
|
||||||
to: __field_info.clone(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
__anchor_rent.minimum_balance(#new_space).checked_sub(__field_info.lamports()).unwrap(),
|
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
let __lamport_amt = __field_info.lamports().checked_sub(__anchor_rent.minimum_balance(#new_space)).unwrap();
|
|
||||||
**#payer.to_account_info().lamports.borrow_mut() = #payer.to_account_info().lamports().checked_add(__lamport_amt).unwrap();
|
|
||||||
**__field_info.lamports.borrow_mut() = __field_info.lamports().checked_sub(__lamport_amt).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#field.to_account_info().realloc(#new_space, #zero)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_constraint_init_group(f: &Field, c: &ConstraintInitGroup) -> proc_macro2::TokenStream {
|
fn generate_constraint_init_group(f: &Field, c: &ConstraintInitGroup) -> proc_macro2::TokenStream {
|
||||||
let field = &f.ident;
|
let field = &f.ident;
|
||||||
let name_str = f.ident.to_string();
|
let name_str = f.ident.to_string();
|
||||||
|
|
|
@ -635,7 +635,6 @@ pub struct ConstraintGroup {
|
||||||
associated_token: Option<ConstraintAssociatedToken>,
|
associated_token: Option<ConstraintAssociatedToken>,
|
||||||
token_account: Option<ConstraintTokenAccountGroup>,
|
token_account: Option<ConstraintTokenAccountGroup>,
|
||||||
mint: Option<ConstraintTokenMintGroup>,
|
mint: Option<ConstraintTokenMintGroup>,
|
||||||
realloc: Option<ConstraintReallocGroup>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstraintGroup {
|
impl ConstraintGroup {
|
||||||
|
@ -679,7 +678,6 @@ pub enum Constraint {
|
||||||
Address(ConstraintAddress),
|
Address(ConstraintAddress),
|
||||||
TokenAccount(ConstraintTokenAccountGroup),
|
TokenAccount(ConstraintTokenAccountGroup),
|
||||||
Mint(ConstraintTokenMintGroup),
|
Mint(ConstraintTokenMintGroup),
|
||||||
Realloc(ConstraintReallocGroup),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constraint token is a single keyword in a `#[account(<TOKEN>)]` attribute.
|
// Constraint token is a single keyword in a `#[account(<TOKEN>)]` attribute.
|
||||||
|
@ -711,9 +709,6 @@ pub enum ConstraintToken {
|
||||||
MintDecimals(Context<ConstraintMintDecimals>),
|
MintDecimals(Context<ConstraintMintDecimals>),
|
||||||
Bump(Context<ConstraintTokenBump>),
|
Bump(Context<ConstraintTokenBump>),
|
||||||
ProgramSeed(Context<ConstraintProgramSeed>),
|
ProgramSeed(Context<ConstraintProgramSeed>),
|
||||||
Realloc(Context<ConstraintRealloc>),
|
|
||||||
ReallocPayer(Context<ConstraintReallocPayer>),
|
|
||||||
ReallocZero(Context<ConstraintReallocZero>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for ConstraintToken {
|
impl Parse for ConstraintToken {
|
||||||
|
@ -738,28 +733,6 @@ pub struct ConstraintMut {
|
||||||
pub error: Option<Expr>,
|
pub error: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ConstraintReallocGroup {
|
|
||||||
pub payer: Expr,
|
|
||||||
pub space: Expr,
|
|
||||||
pub zero: Expr,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ConstraintRealloc {
|
|
||||||
pub space: Expr,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ConstraintReallocPayer {
|
|
||||||
pub target: Expr,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ConstraintReallocZero {
|
|
||||||
pub zero: Expr,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ConstraintSigner {
|
pub struct ConstraintSigner {
|
||||||
pub error: Option<Expr>,
|
pub error: Option<Expr>,
|
||||||
|
|
|
@ -196,47 +196,6 @@ pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"realloc" => {
|
|
||||||
if stream.peek(Token![=]) {
|
|
||||||
stream.parse::<Token![=]>()?;
|
|
||||||
let span = ident
|
|
||||||
.span()
|
|
||||||
.join(stream.span())
|
|
||||||
.unwrap_or_else(|| ident.span());
|
|
||||||
ConstraintToken::Realloc(Context::new(
|
|
||||||
span,
|
|
||||||
ConstraintRealloc {
|
|
||||||
space: stream.parse()?,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
stream.parse::<Token![:]>()?;
|
|
||||||
stream.parse::<Token![:]>()?;
|
|
||||||
let kw = stream.call(Ident::parse_any)?.to_string();
|
|
||||||
stream.parse::<Token![=]>()?;
|
|
||||||
|
|
||||||
let span = ident
|
|
||||||
.span()
|
|
||||||
.join(stream.span())
|
|
||||||
.unwrap_or_else(|| ident.span());
|
|
||||||
|
|
||||||
match kw.as_str() {
|
|
||||||
"payer" => ConstraintToken::ReallocPayer(Context::new(
|
|
||||||
span,
|
|
||||||
ConstraintReallocPayer {
|
|
||||||
target: stream.parse()?,
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
"zero" => ConstraintToken::ReallocZero(Context::new(
|
|
||||||
span,
|
|
||||||
ConstraintReallocZero {
|
|
||||||
zero: stream.parse()?,
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
_ => return Err(ParseError::new(ident.span(), "Invalid attribute. realloc::payer and realloc::zero are the only valid attributes")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
stream.parse::<Token![=]>()?;
|
stream.parse::<Token![=]>()?;
|
||||||
let span = ident
|
let span = ident
|
||||||
|
@ -354,9 +313,6 @@ pub struct ConstraintGroupBuilder<'ty> {
|
||||||
pub mint_decimals: Option<Context<ConstraintMintDecimals>>,
|
pub mint_decimals: Option<Context<ConstraintMintDecimals>>,
|
||||||
pub bump: Option<Context<ConstraintTokenBump>>,
|
pub bump: Option<Context<ConstraintTokenBump>>,
|
||||||
pub program_seed: Option<Context<ConstraintProgramSeed>>,
|
pub program_seed: Option<Context<ConstraintProgramSeed>>,
|
||||||
pub realloc: Option<Context<ConstraintRealloc>>,
|
|
||||||
pub realloc_payer: Option<Context<ConstraintReallocPayer>>,
|
|
||||||
pub realloc_zero: Option<Context<ConstraintReallocZero>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ty> ConstraintGroupBuilder<'ty> {
|
impl<'ty> ConstraintGroupBuilder<'ty> {
|
||||||
|
@ -388,9 +344,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
||||||
mint_decimals: None,
|
mint_decimals: None,
|
||||||
bump: None,
|
bump: None,
|
||||||
program_seed: None,
|
program_seed: None,
|
||||||
realloc: None,
|
|
||||||
realloc_payer: None,
|
|
||||||
realloc_zero: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,22 +439,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Realloc.
|
|
||||||
if let Some(r) = &self.realloc {
|
|
||||||
if self.realloc_payer.is_none() {
|
|
||||||
return Err(ParseError::new(
|
|
||||||
r.span(),
|
|
||||||
"realloc::payer must be provided when using realloc",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self.realloc_zero.is_none() {
|
|
||||||
return Err(ParseError::new(
|
|
||||||
r.span(),
|
|
||||||
"realloc::zero must be provided when using realloc",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zero.
|
// Zero.
|
||||||
if let Some(z) = &self.zeroed {
|
if let Some(z) = &self.zeroed {
|
||||||
match self.mutable {
|
match self.mutable {
|
||||||
|
@ -589,9 +526,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
||||||
mint_decimals,
|
mint_decimals,
|
||||||
bump,
|
bump,
|
||||||
program_seed,
|
program_seed,
|
||||||
realloc,
|
|
||||||
realloc_payer,
|
|
||||||
realloc_zero,
|
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
// Converts Option<Context<T>> -> Option<T>.
|
// Converts Option<Context<T>> -> Option<T>.
|
||||||
|
@ -710,11 +644,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})).transpose()?,
|
})).transpose()?,
|
||||||
realloc: realloc.as_ref().map(|r| ConstraintReallocGroup {
|
|
||||||
payer: into_inner!(realloc_payer).unwrap().target,
|
|
||||||
space: r.space.clone(),
|
|
||||||
zero: into_inner!(realloc_zero).unwrap().zero,
|
|
||||||
}),
|
|
||||||
zeroed: into_inner!(zeroed),
|
zeroed: into_inner!(zeroed),
|
||||||
mutable: into_inner!(mutable),
|
mutable: into_inner!(mutable),
|
||||||
signer: into_inner!(signer),
|
signer: into_inner!(signer),
|
||||||
|
@ -761,9 +690,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
||||||
ConstraintToken::MintDecimals(c) => self.add_mint_decimals(c),
|
ConstraintToken::MintDecimals(c) => self.add_mint_decimals(c),
|
||||||
ConstraintToken::Bump(c) => self.add_bump(c),
|
ConstraintToken::Bump(c) => self.add_bump(c),
|
||||||
ConstraintToken::ProgramSeed(c) => self.add_program_seed(c),
|
ConstraintToken::ProgramSeed(c) => self.add_program_seed(c),
|
||||||
ConstraintToken::Realloc(c) => self.add_realloc(c),
|
|
||||||
ConstraintToken::ReallocPayer(c) => self.add_realloc_payer(c),
|
|
||||||
ConstraintToken::ReallocZero(c) => self.add_realloc_zero(c),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,56 +757,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_realloc(&mut self, c: Context<ConstraintRealloc>) -> ParseResult<()> {
|
|
||||||
if !matches!(self.f_ty, Some(Ty::Account(_)))
|
|
||||||
&& !matches!(self.f_ty, Some(Ty::AccountLoader(_)))
|
|
||||||
{
|
|
||||||
return Err(ParseError::new(
|
|
||||||
c.span(),
|
|
||||||
"realloc must be on an Account or AccountLoader",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self.mutable.is_none() {
|
|
||||||
return Err(ParseError::new(
|
|
||||||
c.span(),
|
|
||||||
"mut must be provided before realloc",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self.realloc.is_some() {
|
|
||||||
return Err(ParseError::new(c.span(), "realloc already provided"));
|
|
||||||
}
|
|
||||||
self.realloc.replace(c);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_realloc_payer(&mut self, c: Context<ConstraintReallocPayer>) -> ParseResult<()> {
|
|
||||||
if self.realloc.is_none() {
|
|
||||||
return Err(ParseError::new(
|
|
||||||
c.span(),
|
|
||||||
"realloc must be provided before realloc::payer",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self.realloc_payer.is_some() {
|
|
||||||
return Err(ParseError::new(c.span(), "realloc::payer already provided"));
|
|
||||||
}
|
|
||||||
self.realloc_payer.replace(c);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_realloc_zero(&mut self, c: Context<ConstraintReallocZero>) -> ParseResult<()> {
|
|
||||||
if self.realloc.is_none() {
|
|
||||||
return Err(ParseError::new(
|
|
||||||
c.span(),
|
|
||||||
"realloc must be provided before realloc::zero",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if self.realloc_zero.is_some() {
|
|
||||||
return Err(ParseError::new(c.span(), "realloc::zero already provided"));
|
|
||||||
}
|
|
||||||
self.realloc_zero.replace(c);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_close(&mut self, c: Context<ConstraintClose>) -> ParseResult<()> {
|
fn add_close(&mut self, c: Context<ConstraintClose>) -> ParseResult<()> {
|
||||||
if !matches!(self.f_ty, Some(Ty::ProgramAccount(_)))
|
if !matches!(self.f_ty, Some(Ty::ProgramAccount(_)))
|
||||||
&& !matches!(self.f_ty, Some(Ty::Account(_)))
|
&& !matches!(self.f_ty, Some(Ty::Account(_)))
|
||||||
|
|
|
@ -55,7 +55,7 @@ fn constraints_cross_checks(fields: &[AccountField]) -> ParseResult<()> {
|
||||||
init_fields[0].ident.span(),
|
init_fields[0].ident.span(),
|
||||||
"the init constraint requires \
|
"the init constraint requires \
|
||||||
the system_program field to exist in the account \
|
the system_program field to exist in the account \
|
||||||
validation struct. Use the Program type to add \
|
validation struct. Use the program type to add \
|
||||||
the system_program field to your validation struct.",
|
the system_program field to your validation struct.",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ fn constraints_cross_checks(fields: &[AccountField]) -> ParseResult<()> {
|
||||||
init_fields[0].ident.span(),
|
init_fields[0].ident.span(),
|
||||||
"the init constraint requires \
|
"the init constraint requires \
|
||||||
the token_program field to exist in the account \
|
the token_program field to exist in the account \
|
||||||
validation struct. Use the Program type to add \
|
validation struct. Use the program type to add \
|
||||||
the token_program field to your validation struct.",
|
the token_program field to your validation struct.",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ fn constraints_cross_checks(fields: &[AccountField]) -> ParseResult<()> {
|
||||||
init_fields[0].ident.span(),
|
init_fields[0].ident.span(),
|
||||||
"the init constraint requires \
|
"the init constraint requires \
|
||||||
the associated_token_program field to exist in the account \
|
the associated_token_program field to exist in the account \
|
||||||
validation struct. Use the Program type to add \
|
validation struct. Use the program type to add \
|
||||||
the associated_token_program field to your validation struct.",
|
the associated_token_program field to your validation struct.",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -141,61 +141,6 @@ fn constraints_cross_checks(fields: &[AccountField]) -> ParseResult<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// REALLOC
|
|
||||||
let realloc_fields: Vec<&Field> = fields
|
|
||||||
.iter()
|
|
||||||
.filter_map(|f| match f {
|
|
||||||
AccountField::Field(field) if field.constraints.realloc.is_some() => Some(field),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if !realloc_fields.is_empty() {
|
|
||||||
// realloc needs system program.
|
|
||||||
if fields.iter().all(|f| f.ident() != "system_program") {
|
|
||||||
return Err(ParseError::new(
|
|
||||||
realloc_fields[0].ident.span(),
|
|
||||||
"the realloc constraint requires \
|
|
||||||
the system_program field to exist in the account \
|
|
||||||
validation struct. Use the Program type to add \
|
|
||||||
the system_program field to your validation struct.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
for field in realloc_fields {
|
|
||||||
// Get allocator for realloc-ed account
|
|
||||||
let associated_payer_name = match field.constraints.realloc.clone().unwrap().payer {
|
|
||||||
// composite allocator, check not supported
|
|
||||||
Expr::Field(_) => continue,
|
|
||||||
field_name => field_name.to_token_stream().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check allocator is mutable
|
|
||||||
let associated_payer_field = fields.iter().find_map(|f| match f {
|
|
||||||
AccountField::Field(field) if *f.ident() == associated_payer_name => Some(field),
|
|
||||||
_ => None,
|
|
||||||
});
|
|
||||||
|
|
||||||
match associated_payer_field {
|
|
||||||
Some(associated_payer_field) => {
|
|
||||||
if !associated_payer_field.constraints.is_mutable() {
|
|
||||||
return Err(ParseError::new(
|
|
||||||
field.ident.span(),
|
|
||||||
"the realloc::payer specified for an realloc constraint must be mutable.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(ParseError::new(
|
|
||||||
field.ident.span(),
|
|
||||||
"the realloc::payer specified does not exist.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
"permissioned-markets",
|
"permissioned-markets",
|
||||||
"pda-derivation",
|
"pda-derivation",
|
||||||
"pyth",
|
"pyth",
|
||||||
"realloc",
|
|
||||||
"spl/token-proxy",
|
"spl/token-proxy",
|
||||||
"swap",
|
"swap",
|
||||||
"system-accounts",
|
"system-accounts",
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
[features]
|
|
||||||
seeds = false
|
|
||||||
|
|
||||||
[programs.localnet]
|
|
||||||
realloc = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
|
||||||
|
|
||||||
[registry]
|
|
||||||
url = "https://anchor.projectserum.com"
|
|
||||||
|
|
||||||
[provider]
|
|
||||||
cluster = "localnet"
|
|
||||||
wallet = "~/.config/solana/id.json"
|
|
||||||
|
|
||||||
[scripts]
|
|
||||||
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
|
|
|
@ -1,4 +0,0 @@
|
||||||
[workspace]
|
|
||||||
members = [
|
|
||||||
"programs/*"
|
|
||||||
]
|
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"name": "realloc",
|
|
||||||
"version": "0.24.2",
|
|
||||||
"license": "(MIT OR Apache-2.0)",
|
|
||||||
"homepage": "https://github.com/project-serum/anchor#readme",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/project-serum/anchor/issues"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/project-serum/anchor.git"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=11"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "anchor test"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "realloc"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Created with Anchor"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
crate-type = ["cdylib", "lib"]
|
|
||||||
name = "realloc"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
no-entrypoint = []
|
|
||||||
no-idl = []
|
|
||||||
no-log-ix-name = []
|
|
||||||
cpi = ["no-entrypoint"]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
overflow-checks = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anchor-lang = { path = "../../../../lang" }
|
|
|
@ -1,2 +0,0 @@
|
||||||
[target.bpfel-unknown-unknown.dependencies.std]
|
|
||||||
features = []
|
|
|
@ -1,70 +0,0 @@
|
||||||
use anchor_lang::prelude::*;
|
|
||||||
|
|
||||||
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
|
|
||||||
|
|
||||||
#[program]
|
|
||||||
pub mod realloc {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
|
|
||||||
ctx.accounts.sample.data = vec![0];
|
|
||||||
ctx.accounts.sample.bump = *ctx.bumps.get("sample").unwrap();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn realloc(ctx: Context<Realloc>, len: u8) -> Result<()> {
|
|
||||||
ctx.accounts
|
|
||||||
.sample
|
|
||||||
.data
|
|
||||||
.resize_with(len as usize, Default::default);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Accounts)]
|
|
||||||
pub struct Initialize<'info> {
|
|
||||||
#[account(mut)]
|
|
||||||
pub authority: Signer<'info>,
|
|
||||||
|
|
||||||
#[account(
|
|
||||||
init,
|
|
||||||
payer = authority,
|
|
||||||
seeds = [b"sample"],
|
|
||||||
bump,
|
|
||||||
space = Sample::space(1),
|
|
||||||
)]
|
|
||||||
pub sample: Account<'info, Sample>,
|
|
||||||
|
|
||||||
pub system_program: Program<'info, System>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Accounts)]
|
|
||||||
#[instruction(len: u8)]
|
|
||||||
pub struct Realloc<'info> {
|
|
||||||
#[account(mut)]
|
|
||||||
pub authority: Signer<'info>,
|
|
||||||
|
|
||||||
#[account(
|
|
||||||
mut,
|
|
||||||
seeds = [b"sample"],
|
|
||||||
bump = sample.bump,
|
|
||||||
realloc = Sample::space(len as usize),
|
|
||||||
realloc::payer = authority,
|
|
||||||
realloc::zero = false,
|
|
||||||
)]
|
|
||||||
pub sample: Account<'info, Sample>,
|
|
||||||
|
|
||||||
pub system_program: Program<'info, System>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[account]
|
|
||||||
pub struct Sample {
|
|
||||||
pub data: Vec<u8>,
|
|
||||||
pub bump: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sample {
|
|
||||||
pub fn space(len: usize) -> usize {
|
|
||||||
8 + (4 + len) + 1
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
import * as anchor from "@project-serum/anchor";
|
|
||||||
import { Program } from "@project-serum/anchor";
|
|
||||||
import { assert } from "chai";
|
|
||||||
import { Realloc } from "../target/types/realloc";
|
|
||||||
|
|
||||||
describe("realloc", () => {
|
|
||||||
// Configure the client to use the local cluster.
|
|
||||||
anchor.setProvider(anchor.AnchorProvider.env());
|
|
||||||
|
|
||||||
const program = anchor.workspace.Realloc as Program<Realloc>;
|
|
||||||
const authority = (program.provider as any).wallet
|
|
||||||
.payer as anchor.web3.Keypair;
|
|
||||||
|
|
||||||
let sample: anchor.web3.PublicKey;
|
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
[sample] = await anchor.web3.PublicKey.findProgramAddress(
|
|
||||||
[Buffer.from("sample")],
|
|
||||||
program.programId
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Is initialized!", async () => {
|
|
||||||
await program.methods
|
|
||||||
.initialize()
|
|
||||||
.accounts({ authority: authority.publicKey, sample })
|
|
||||||
.rpc();
|
|
||||||
|
|
||||||
const s = await program.account.sample.fetch(sample);
|
|
||||||
assert.lengthOf(s.data, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("realloc additive", async () => {
|
|
||||||
await program.methods
|
|
||||||
.realloc(5)
|
|
||||||
.accounts({ authority: authority.publicKey, sample })
|
|
||||||
.rpc();
|
|
||||||
|
|
||||||
const s = await program.account.sample.fetch(sample);
|
|
||||||
assert.lengthOf(s.data, 5);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("realloc substractive", async () => {
|
|
||||||
await program.methods
|
|
||||||
.realloc(1)
|
|
||||||
.accounts({ authority: authority.publicKey, sample })
|
|
||||||
.rpc();
|
|
||||||
|
|
||||||
const s = await program.account.sample.fetch(sample);
|
|
||||||
assert.lengthOf(s.data, 1);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"types": ["mocha", "chai"],
|
|
||||||
"typeRoots": ["./node_modules/@types"],
|
|
||||||
"lib": ["es2015"],
|
|
||||||
"module": "commonjs",
|
|
||||||
"target": "es6",
|
|
||||||
"esModuleInterop": true
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue