Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions program/src/processor/allocate.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use pinocchio::{
cpi::{Seed, Signer},
error::ProgramError,
sysvars::{rent::Rent, Sysvar},
AccountView, ProgramResult,
};
use pinocchio_system::instructions::{Allocate, Assign};
Expand Down Expand Up @@ -40,7 +39,8 @@ pub fn allocate(accounts: &mut [AccountView], instruction_data: &[u8]) -> Progra
// buffer
// - if pda, must have the correct derivation + seed; otherwise must be
// a signer (match the authority)
// - must be rent exempt (pre-funded account)
// - must have lamports (pre-funded account); the runtime will ensure
// that the account is rent exempt

let (is_pda, bump, canonical) = if buffer.address() == authority.address() {
// A keypair buffer does not require a `seed` value.
Expand Down Expand Up @@ -139,10 +139,9 @@ pub fn allocate(accounts: &mut [AccountView], instruction_data: &[u8]) -> Progra
_ => return Err(ProgramError::InvalidAccountData),
}

// `buffer` length is within the permitted limit.
let minimum_balance = Rent::get()?.minimum_balance_unchecked(buffer.data_len());

if buffer.lamports() < minimum_balance {
// The buffer account must have non-zero lamports. The runtime will then
// ensure that the account is rent exempt.
if buffer.lamports() == 0 {
return Err(ProgramError::AccountNotRentExempt);
}

Expand Down
22 changes: 5 additions & 17 deletions program/src/processor/extend.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
use core::mem::size_of;
use pinocchio::{
account::AccountView,
error::ProgramError,
sysvars::{rent::Rent, Sysvar},
ProgramResult, Resize,
};
use pinocchio::{account::AccountView, error::ProgramError, ProgramResult, Resize};

use crate::state::{buffer::Buffer, AccountDiscriminator};

Expand Down Expand Up @@ -38,8 +33,8 @@ pub fn extend(accounts: &mut [AccountView], instruction_data: &[u8]) -> ProgramR
// - authority must be a signer (validated by `validate_authority`)
// - must be a buffer or metadata account
// - must have a valid authority
// - must be rent exempt (pre-funded account) since we are reallocating the buffer
// account
// - must be rent exempt (pre-funded account) since we are reallocating the
// account (checked by the runtime)

if account.is_data_empty() {
return Err(ProgramError::InvalidAccountData);
Expand All @@ -62,18 +57,11 @@ pub fn extend(accounts: &mut [AccountView], instruction_data: &[u8]) -> ProgramR
}
}

// Reallocates the account size.

// The length of the data is never more than `10_000_000`; adding a `u16`
// will never overflow the `usize` limit.
let length = account.data_len() + extend_length as usize;

let minimum_balance = Rent::get()?.try_minimum_balance(length)?;

if account.lamports() < minimum_balance {
return Err(ProgramError::AccountNotRentExempt);
}

// Reallocates the account size.

// SAFETY: `account` is not borrowed at this point.
unsafe { account.resize_unchecked(length) }
}
16 changes: 8 additions & 8 deletions program/src/processor/initialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use pinocchio::{
cpi::{Seed, Signer},
error::ProgramError,
instruction::seeds,
sysvars::{rent::Rent, Sysvar},
AccountView, Address, ProgramResult,
};
use pinocchio_system::instructions::{Allocate, Assign};
Expand Down Expand Up @@ -63,6 +62,8 @@ pub fn initialize(accounts: &mut [AccountView], instruction_data: &[u8]) -> Prog
// the remaining instruction data is used as the metadata account data; OR be a
// pre-allocated buffer (i.e. `discriminator = 1`), in which case, no remaining
// instruction data is allowed as the data must already be written to the account
// - must have lamports (pre-funded account); the runtime will ensure that the
// account is rent exempt

let (derived_metadata, bump) = if canonical {
derive_program_address(&[program.address().as_array(), args.seed.as_ref()], &ID)
Expand Down Expand Up @@ -150,13 +151,6 @@ pub fn initialize(accounts: &mut [AccountView], instruction_data: &[u8]) -> Prog
}
.invoke_signed(signer)?;

// `space` is guranteed to be within the permitted limits.
let minimum_balance = Rent::get()?.minimum_balance_unchecked(space);

if metadata.lamports() < minimum_balance {
return Err(ProgramError::AccountNotRentExempt);
}

// SAFETY: scoped mutable borrow of `metadata` account data. The data is
// guaranteed to be allocated and assigned to the program.
let metadata_account_data = unsafe { metadata.borrow_unchecked_mut() };
Expand All @@ -179,6 +173,12 @@ pub fn initialize(accounts: &mut [AccountView], instruction_data: &[u8]) -> Prog
}
};

// The metadata account must have lamports. The runtime will
// then ensure that the account is rent exempt.
if metadata.lamports() == 0 {
return Err(ProgramError::AccountNotRentExempt);
}

// Initialize the metadata account.

// SAFETY: there are no other active borrows to `metadata` account data and
Expand Down
2 changes: 2 additions & 0 deletions program/src/processor/set_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ pub fn set_data(accounts: &mut [AccountView], instruction_data: &[u8]) -> Progra
// metadata
// - must be initialized
// - must be mutable
// - must be rent exempt (pre-funded account) since we are reallocating the
// account (checked by the runtime)

// SAFETY: Scoped immutable borrow of `metadata` account data for validation.
let metadata_account_data = unsafe { metadata.borrow_unchecked() };
Expand Down
16 changes: 3 additions & 13 deletions program/src/processor/write.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
use core::cmp::max;

use pinocchio::{
error::ProgramError,
sysvars::{rent::Rent, Sysvar},
AccountView, ProgramResult, Resize,
};
use pinocchio::{error::ProgramError, AccountView, ProgramResult, Resize};

use crate::state::{buffer::Buffer, header::Header, AccountDiscriminator};

Expand Down Expand Up @@ -35,8 +31,8 @@ pub fn write(accounts: &mut [AccountView], instruction_data: &[u8]) -> ProgramRe

// target_buffer
// - must be initialized
// - must be rent exempt (pre-funded account) since we are reallocating the buffer
// account
// - must be rent exempt (pre-funded account) since we are reallocating
// the account (checked by the runtime)
//
// source_buffer (if `args.data()` is empty)
// - must be initialized
Expand Down Expand Up @@ -95,12 +91,6 @@ pub fn write(accounts: &mut [AccountView], instruction_data: &[u8]) -> ProgramRe
(max(data.len(), offset + source_data.len()), source_data)
};

let minimum_balance = Rent::get()?.try_minimum_balance(required_length)?;

if target_buffer.lamports() < minimum_balance {
return Err(ProgramError::AccountNotRentExempt);
}

// Writes the source data to the buffer account.

// SAFETY: `target_buffer` account is not borrowed at this point.
Expand Down
25 changes: 0 additions & 25 deletions program/tests/extend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,31 +299,6 @@ fn fail_extend_with_wrong_authority() {
);
}

#[test]
fn fail_extend_without_rent_for_growth() {
let buffer_key = Pubkey::new_unique();
let buffer_account =
create_funded_account(minimum_balance_for(Buffer::LEN), system_program::ID);

process_instructions(
&[
(
&allocate(&buffer_key, &buffer_key, None, None, None),
&[Check::success()],
),
(
&extend(&buffer_key, &buffer_key, None, None, 1),
&[Check::err(ProgramError::AccountNotRentExempt)],
),
],
&[
(buffer_key, buffer_account),
(PROGRAM_ID, Account::default()),
keyed_account_for_system_program(),
],
);
}

#[test]
fn fail_extend_uninitialized_account() {
let account_key = Pubkey::new_unique();
Expand Down
2 changes: 1 addition & 1 deletion program/tests/initialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ fn fail_initialize_with_wrong_metadata_pda() {
}

#[test]
fn fail_initialize_without_rent_exemption() {
fn fail_initialize_unfunded_metadata() {
let authority_key = Pubkey::new_unique();

let program_data_key = Pubkey::new_unique();
Expand Down
25 changes: 0 additions & 25 deletions program/tests/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,28 +265,3 @@ fn fail_write_from_same_buffer() {
],
);
}

#[test]
fn fail_write_without_rent_for_growth() {
let buffer_key = Pubkey::new_unique();
let buffer_account =
create_funded_account(minimum_balance_for(Buffer::LEN), system_program::ID);

process_instructions(
&[
(
&allocate(&buffer_key, &buffer_key, None, None, None),
&[Check::success()],
),
(
&write(&buffer_key, &buffer_key, None, 0, &[1]),
&[Check::err(ProgramError::AccountNotRentExempt)],
),
],
&[
(buffer_key, buffer_account),
(PROGRAM_ID, Account::default()),
keyed_account_for_system_program(),
],
);
}
Loading