From 9cd75bf2aefad0ce73f87eefd8fbde81224c7d06 Mon Sep 17 00:00:00 2001 From: ananas-block Date: Thu, 23 Jan 2025 19:00:36 +0000 Subject: [PATCH] chore: move rollover completely into batched crate --- .../src/rollover_address_tree.rs | 21 +++++- .../src/rollover_state_tree.rs | 75 ++++++++++++++++++- .../rollover_batched_address_merkle_tree.rs | 33 +++----- .../rollover_batched_state_merkle_tree.rs | 65 ++++------------ 4 files changed, 119 insertions(+), 75 deletions(-) diff --git a/program-libs/batched-merkle-tree/src/rollover_address_tree.rs b/program-libs/batched-merkle-tree/src/rollover_address_tree.rs index 67662474b..91cde55f0 100644 --- a/program-libs/batched-merkle-tree/src/rollover_address_tree.rs +++ b/program-libs/batched-merkle-tree/src/rollover_address_tree.rs @@ -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, @@ -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, +) -> Result { + 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. diff --git a/program-libs/batched-merkle-tree/src/rollover_state_tree.rs b/program-libs/batched-merkle-tree/src/rollover_state_tree.rs index 152378653..712609d3a 100644 --- a/program-libs/batched-merkle-tree/src/rollover_state_tree.rs +++ b/program-libs/batched-merkle-tree/src/rollover_state_tree.rs @@ -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, @@ -30,6 +30,77 @@ pub struct RolloverBatchStateTreeParams<'a> { pub network_fee: Option, } +/// 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, +) -> Result { + // 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. diff --git a/programs/account-compression/src/instructions/rollover_batched_address_merkle_tree.rs b/programs/account-compression/src/instructions/rollover_batched_address_merkle_tree.rs index 3717b1fbd..1328549fe 100644 --- a/programs/account-compression/src/instructions/rollover_batched_address_merkle_tree.rs +++ b/programs/account-compression/src/instructions/rollover_batched_address_merkle_tree.rs @@ -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::{ @@ -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>>, @@ -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(), diff --git a/programs/account-compression/src/instructions/rollover_batched_state_merkle_tree.rs b/programs/account-compression/src/instructions/rollover_batched_state_merkle_tree.rs index 564a834c1..44af14555 100644 --- a/programs/account-compression/src/instructions/rollover_batched_state_merkle_tree.rs +++ b/programs/account-compression/src/instructions/rollover_batched_state_merkle_tree.rs @@ -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::{ @@ -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>>, @@ -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(())