Skip to content
Open
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
66 changes: 66 additions & 0 deletions programs/system/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,71 @@
#![no_std]

use pinocchio::{
account_info::AccountInfo,
instruction::Signer,
pubkey::Pubkey,
sysvars::{rent::Rent, Sysvar},
ProgramResult,
};

use crate::instructions::{Assign, CreateAccount, Transfer};

pub mod instructions;

pinocchio_pubkey::declare_id!("11111111111111111111111111111111");

/// Create an account with a minimal balance to be rent-exempt.
///
/// The account will be funded by the `payer` if its current lamports
/// are insufficient for rent-exemption.
#[inline(always)]
pub fn create_account_with_minimal_balance(
account: &AccountInfo,
space: usize,
owner: &Pubkey,
payer: &AccountInfo,
signers: &[Signer],
rent_sysvar: Option<&AccountInfo>,
) -> ProgramResult {
let lamports = if let Some(rent_sysvar) = rent_sysvar {
let rent = Rent::from_account_info(rent_sysvar)?;
rent.minimum_balance(space)
} else {
Rent::get()?.minimum_balance(space)
};

if account.lamports() == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you think about using hints from pinocchio::hint module?

i expect account is not exist, in the majority of cases

Suggested change
if account.lamports() == 0 {
if likely(account.lamports() == 0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you think about using hints from pinocchio::hint module?

i expect account is not exist, in the majority of cases

It made no difference in my tests. Also, I had a look at the asm and it seems the compiler is doing the right thing already. Did you notice a difference?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same for the lib (i didn't test it in the real app).
As a part of library it compiles in the expected instructions.
Just wanted to make extra sure this logic won't be miscompiled in the large program.

// Create the account if it does not exist.
CreateAccount {
from: payer,
to: account,
lamports,
space: space as u64,
owner,
}
.invoke_signed(signers)
} else {
let required_lamports = lamports.saturating_sub(account.lamports());

// Transfer lamports from `payer` to `account` if needed.
if required_lamports > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same here can be applied, i believe.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here, no difference.

Transfer {
from: payer,
to: account,
lamports: required_lamports,
}
.invoke()?;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make this .invoke_signed(signers)?; to support the case a PDA acts as the funding account for the transfer?

}

// Assign the account to the specified owner.
Assign { account, owner }.invoke_signed(signers)?;

// Allocate the required space for the account.
//
// SAFETY: There are no active borrows of the `account`.
// This was checked by the `Assign` CPI above.
unsafe { account.resize_unchecked(space)? };

Ok(())
}
}