Skip to content

Commit

Permalink
chore: move rollover completely into batched crate
Browse files Browse the repository at this point in the history
  • Loading branch information
ananas-block committed Jan 23, 2025
1 parent dfc2ef8 commit 9cd75bf
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 75 deletions.
21 changes: 20 additions & 1 deletion program-libs/batched-merkle-tree/src/rollover_address_tree.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use light_merkle_tree_metadata::utils::if_equals_none;
use light_utils::pubkey::Pubkey;
use light_utils::{account::check_account_balance_is_rent_exempt, pubkey::Pubkey};
use solana_program::account_info::AccountInfo;

use crate::{
errors::BatchedMerkleTreeError,
Expand All @@ -10,6 +11,24 @@ use crate::{
rollover_state_tree::batched_tree_is_ready_for_rollover,
};

pub fn rollover_batched_address_tree_from_account_info<'a>(
old_account: &AccountInfo<'a>,
new_account: &AccountInfo<'a>,
network_fee: Option<u64>,
) -> Result<u64, BatchedMerkleTreeError> {
let new_mt_rent = check_account_balance_is_rent_exempt(&new_account, old_account.data_len())?;
let mut old_merkle_tree = BatchedMerkleTreeAccount::address_from_account_info(old_account)?;
let mut new_mt_data = new_account.try_borrow_mut_data()?;
rollover_batched_address_tree(
&mut old_merkle_tree,
&mut new_mt_data,
new_mt_rent,
(*new_account.key).into(),
network_fee,
)?;
Ok(new_mt_rent)
}

/// Rollover an almost full batched address tree,
/// ie create a new batched Merkle tree account
/// with the same parameters, and mark the old account as rolled over.
Expand Down
75 changes: 73 additions & 2 deletions program-libs/batched-merkle-tree/src/rollover_state_tree.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use light_merkle_tree_metadata::{errors::MerkleTreeMetadataError, utils::if_equals_none};
use light_utils::pubkey::Pubkey;
use solana_program::msg;
use light_utils::{account::check_account_balance_is_rent_exempt, pubkey::Pubkey};
use solana_program::{account_info::AccountInfo, msg};

use crate::{
errors::BatchedMerkleTreeError,
Expand Down Expand Up @@ -30,6 +30,77 @@ pub struct RolloverBatchStateTreeParams<'a> {
pub network_fee: Option<u64>,
}

/// Rollover an almost full batched state tree,
/// ie create a new batched Merkle tree and output queue
/// with the same parameters, and mark the old accounts as rolled over.
/// The old tree and queue can be used until these are completely full.
///
/// 1. Check Merkle tree account discriminator, tree type, and program ownership.
/// 2. Check Queue account discriminator, and program ownership.
/// 3. Check that new Merkle tree account is exactly rent exempt.
/// 4. Check that new Queue account is exactly rent exempt.
/// 5. Rollover the old Merkle tree and queue to new Merkle tree and queue.
///
/// Note, reimbursed rent for additional bytes is calculated from old Merkle tree accounts
/// additional bytes since those are the basis for the old trees rollover fee.
/// If new additional_bytes is greater than old additional_bytes additional
/// rent reimbursements need to be calculated outside of this function.
pub fn rollover_batched_state_tree_from_account_info<'a>(
old_state_merkle_tree: &AccountInfo<'a>,
new_state_merkle_tree: &AccountInfo<'a>,
old_output_queue: &AccountInfo<'a>,
new_output_queue: &AccountInfo<'a>,
additional_bytes: u64,
network_fee: Option<u64>,
) -> Result<u64, BatchedMerkleTreeError> {
// 1. Check Merkle tree account discriminator, tree type, and program ownership.
let old_merkle_tree_account =
&mut BatchedMerkleTreeAccount::state_from_account_info(&old_state_merkle_tree)?;

// 2. Check Queue account discriminator, and program ownership.
let old_output_queue_account =
&mut BatchedQueueAccount::output_from_account_info(&old_output_queue)?;

// 3. Check that new Merkle tree account is exactly rent exempt.
let merkle_tree_rent = check_account_balance_is_rent_exempt(
&new_state_merkle_tree,
old_state_merkle_tree.data_len(),
)?;
// 4. Check that new Queue account is exactly rent exempt.
let queue_rent =
check_account_balance_is_rent_exempt(&new_output_queue, old_output_queue.data_len())?;

use solana_program::sysvar::Sysvar;
let additional_bytes_rent = solana_program::rent::Rent::get()?.minimum_balance(
old_output_queue_account
.metadata
.rollover_metadata
.additional_bytes as usize,
);

let new_mt_data = &mut new_state_merkle_tree.try_borrow_mut_data()?;
let params = RolloverBatchStateTreeParams {
old_merkle_tree: old_merkle_tree_account,
old_mt_pubkey: (*old_state_merkle_tree.key).into(),
new_mt_data,
new_mt_rent: merkle_tree_rent,
new_mt_pubkey: (*new_state_merkle_tree.key).into(),
old_output_queue: old_output_queue_account,
old_queue_pubkey: (*old_output_queue.key).into(),
new_output_queue_data: &mut new_output_queue.try_borrow_mut_data()?,
new_output_queue_rent: queue_rent,
new_output_queue_pubkey: (*new_output_queue.key).into(),
additional_bytes_rent,
additional_bytes,
network_fee,
};

// 5. Rollover the old Merkle tree and queue to new Merkle tree and queue.
rollover_batched_state_tree(params)?;
let rent = merkle_tree_rent + queue_rent + additional_bytes_rent;
Ok(rent)
}

/// Rollover an almost full batched state tree,
/// ie create a new batched Merkle tree and output queue
/// with the same parameters, and mark the old accounts as rolled over.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use anchor_lang::{prelude::*, solana_program::pubkey::Pubkey};
use light_batched_merkle_tree::{
merkle_tree::BatchedMerkleTreeAccount, rollover_address_tree::rollover_batched_address_tree,
merkle_tree::BatchedMerkleTreeAccount,
rollover_address_tree::rollover_batched_address_tree_from_account_info,
};
use light_utils::account::check_account_balance_is_rent_exempt;

use crate::{
utils::{
Expand Down Expand Up @@ -41,9 +41,9 @@ impl<'info> GroupAccounts<'info> for RolloverBatchedAddressMerkleTree<'info> {
/// Rollover the old address Merkle tree to the new address Merkle tree.
/// 1. Check Merkle tree account discriminator, tree type, and program ownership.
/// 2. Check that signer is registered or authority.
/// 3. Check that new address Merkle tree account is exactly rent exempt.
/// 4. Rollover the old address Merkle tree to the new address Merkle tree.
/// 5. Transfer rent exemption for new Merkle tree
/// 3. Rollover the old address Merkle tree to the new address Merkle tree.
/// 3.1. Check that new address Merkle tree account is exactly rent exempt.
/// 4. Transfer rent exemption for new Merkle tree
/// from old address Merkle tree to fee payer.
pub fn process_rollover_batched_address_merkle_tree<'a, 'b, 'c: 'info, 'info>(
ctx: Context<'a, 'b, 'c, 'info, RolloverBatchedAddressMerkleTree<'info>>,
Expand All @@ -60,27 +60,16 @@ pub fn process_rollover_batched_address_merkle_tree<'a, 'b, 'c: 'info, 'info>(
BatchedMerkleTreeAccount,
>(&ctx, old_merkle_tree_account)?;

// 3. Check that new address Merkle tree account is exactly rent exempt.
let merkle_tree_rent = check_account_balance_is_rent_exempt(
&ctx.accounts.new_address_merkle_tree.to_account_info(),
ctx.accounts
.old_address_merkle_tree
.to_account_info()
.data_len(),
)
.map_err(ProgramError::from)?;
// 4. Rollover the old address Merkle tree to the new address Merkle tree.
let new_mt_data = &mut ctx.accounts.new_address_merkle_tree.try_borrow_mut_data()?;
rollover_batched_address_tree(
old_merkle_tree_account,
new_mt_data,
merkle_tree_rent,
ctx.accounts.new_address_merkle_tree.key().into(),
// 3. Rollover the old address Merkle tree to the new address Merkle tree.
// 3.1. Check that new address Merkle tree account is exactly rent exempt.
let merkle_tree_rent = rollover_batched_address_tree_from_account_info(
&ctx.accounts.old_address_merkle_tree,
&ctx.accounts.new_address_merkle_tree,
network_fee,
)
.map_err(ProgramError::from)?;

// 5. Transfer rent exemption for new Merkle tree
// 4. Transfer rent exemption for new Merkle tree
// from old address Merkle tree to fee payer.
transfer_lamports(
&ctx.accounts.old_address_merkle_tree.to_account_info(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use anchor_lang::{prelude::*, solana_program::pubkey::Pubkey};
use light_batched_merkle_tree::{
merkle_tree::BatchedMerkleTreeAccount,
queue::BatchedQueueAccount,
rollover_state_tree::{rollover_batched_state_tree, RolloverBatchStateTreeParams},
rollover_state_tree::rollover_batched_state_tree_from_account_info,
};
use light_utils::account::check_account_balance_is_rent_exempt;

use crate::{
utils::{
Expand Down Expand Up @@ -49,12 +47,9 @@ impl<'info> GroupAccounts<'info> for RolloverBatchedStateMerkleTree<'info> {
/// Rollover the old state Merkle tree and output queue to
/// new state Merkle tree and output queue.
/// 1. Check Merkle tree account discriminator, tree type, and program ownership.
/// 2. Check Queue account discriminator, and program ownership.
/// 3. Check that signer is registered or authority.
/// 4. Check that new Merkle tree account is exactly rent exempt.
/// 5. Check that new Queue account is exactly rent exempt.
/// 6. Rollover the old Merkle tree and queue to new Merkle tree and queue.
/// 7. Transfer rent exemption for new accounts
/// 2. Check that signer is registered or authority.
/// 3. Rollover the old Merkle tree and queue to new Merkle tree and queue.
/// 4. Transfer rent exemption for new accounts
/// from old output queue to fee payer.
pub fn process_rollover_batched_state_merkle_tree<'a, 'b, 'c: 'info, 'info>(
ctx: Context<'a, 'b, 'c, 'info, RolloverBatchedStateMerkleTree<'info>>,
Expand All @@ -66,59 +61,29 @@ pub fn process_rollover_batched_state_merkle_tree<'a, 'b, 'c: 'info, 'info>(
&mut BatchedMerkleTreeAccount::state_from_account_info(&ctx.accounts.old_state_merkle_tree)
.map_err(ProgramError::from)?;

// 2. Check Queue account discriminator, and program ownership.
let old_output_queue =
&mut BatchedQueueAccount::output_from_account_info(&ctx.accounts.old_output_queue)
.map_err(ProgramError::from)?;

// 3. Check that signer is registered or authority.
// 2. Check that signer is registered or authority.
check_signer_is_registered_or_authority::<
RolloverBatchedStateMerkleTree,
BatchedMerkleTreeAccount,
>(&ctx, old_merkle_tree_account)?;

// 4. Check that new Merkle tree account is exactly rent exempt.
let merkle_tree_rent = check_account_balance_is_rent_exempt(
&ctx.accounts.new_state_merkle_tree.to_account_info(),
ctx.accounts
.old_state_merkle_tree
.to_account_info()
.data_len(),
)
.map_err(ProgramError::from)?;
// 5. Check that new Queue account is exactly rent exempt.
let queue_rent = check_account_balance_is_rent_exempt(
&ctx.accounts.new_output_queue.to_account_info(),
ctx.accounts.old_output_queue.to_account_info().data_len(),
)
.map_err(ProgramError::from)?;
let additional_bytes_rent = Rent::get()?.minimum_balance(additional_bytes as usize);
let new_mt_data = &mut ctx.accounts.new_state_merkle_tree.try_borrow_mut_data()?;
let params = RolloverBatchStateTreeParams {
old_merkle_tree: old_merkle_tree_account,
old_mt_pubkey: ctx.accounts.old_state_merkle_tree.key().into(),
new_mt_data,
new_mt_rent: merkle_tree_rent,
new_mt_pubkey: ctx.accounts.new_state_merkle_tree.key().into(),
old_output_queue,
old_queue_pubkey: ctx.accounts.old_output_queue.key().into(),
new_output_queue_data: &mut ctx.accounts.new_output_queue.try_borrow_mut_data()?,
new_output_queue_rent: queue_rent,
new_output_queue_pubkey: ctx.accounts.new_output_queue.key().into(),
additional_bytes_rent,
// 3. Rollover the old Merkle tree and queue to new Merkle tree and queue.
let rent = rollover_batched_state_tree_from_account_info(
&ctx.accounts.old_state_merkle_tree,
&ctx.accounts.new_state_merkle_tree,
&ctx.accounts.old_output_queue,
&ctx.accounts.new_output_queue,
additional_bytes,
network_fee,
};

// 6. Rollover the old Merkle tree and queue to new Merkle tree and queue.
rollover_batched_state_tree(params).map_err(ProgramError::from)?;
)
.map_err(ProgramError::from)?;

// 7. Transfer rent exemption for new accounts
// 4. Transfer rent exemption for new accounts
// from old output queue to fee payer.
transfer_lamports(
&ctx.accounts.old_output_queue.to_account_info(),
&ctx.accounts.fee_payer.to_account_info(),
merkle_tree_rent + queue_rent + additional_bytes_rent,
rent,
)?;

Ok(())
Expand Down

0 comments on commit 9cd75bf

Please sign in to comment.