1use anchor_lang::{
26 prelude::*,
27 solana_program::{clock::Clock, program_error::ProgramError},
28};
29use borsh::{BorshDeserialize, BorshSerialize};
30
31pub mod canopy;
32pub mod concurrent_tree_wrapper;
33pub mod error;
34pub mod events;
35#[macro_use]
36pub mod macros;
37mod noop;
38pub mod state;
39pub mod zero_copy;
40
41pub use crate::noop::{wrap_application_data_v1, Noop};
42
43use crate::canopy::{fill_in_proof_from_canopy, update_canopy};
44use crate::concurrent_tree_wrapper::*;
45pub use crate::error::AccountCompressionError;
46pub use crate::events::{AccountCompressionEvent, ChangeLogEvent};
47use crate::noop::wrap_event;
48use crate::state::{
49 merkle_tree_get_size, CompressionAccountType, ConcurrentMerkleTreeHeader,
50 CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1,
51};
52
53pub use spl_concurrent_merkle_tree::{
55 concurrent_merkle_tree::{ConcurrentMerkleTree, FillEmptyOrAppendArgs},
56 error::ConcurrentMerkleTreeError,
57 node::Node,
58};
59
60declare_id!("mcmt6YrQEMKw8Mw43FmpRLmf7BqRnFMKmAcbxE3xkAW");
61
62#[derive(Accounts)]
64pub struct Initialize<'info> {
65 #[account(mut)]
66 pub merkle_tree: UncheckedAccount<'info>,
68
69 pub authority: Signer<'info>,
72
73 pub noop: Program<'info, Noop>,
75}
76
77#[derive(Accounts)]
82pub struct Modify<'info> {
83 #[account(mut)]
84 pub merkle_tree: UncheckedAccount<'info>,
86
87 pub authority: Signer<'info>,
90
91 pub noop: Program<'info, Noop>,
93}
94
95#[derive(Accounts)]
98pub struct VerifyLeaf<'info> {
99 pub merkle_tree: UncheckedAccount<'info>,
101}
102
103#[derive(Accounts)]
105pub struct TransferAuthority<'info> {
106 #[account(mut)]
107 pub merkle_tree: UncheckedAccount<'info>,
109
110 pub authority: Signer<'info>,
113}
114
115#[derive(Accounts)]
117pub struct CloseTree<'info> {
118 #[account(mut)]
119 pub merkle_tree: AccountInfo<'info>,
121
122 pub authority: Signer<'info>,
124
125 #[account(mut)]
127 pub recipient: AccountInfo<'info>,
128}
129
130#[program]
131pub mod mpl_account_compression {
132 use super::*;
133
134 pub fn init_empty_merkle_tree(
147 ctx: Context<Initialize>,
148 max_depth: u32,
149 max_buffer_size: u32,
150 ) -> Result<()> {
151 require_eq!(
152 *ctx.accounts.merkle_tree.owner,
153 crate::id(),
154 AccountCompressionError::IncorrectAccountOwner
155 );
156 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
157 if merkle_tree_bytes.len() < CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1 {
158 return Err(ProgramError::InvalidAccountData.into());
159 }
160 require!(
161 merkle_tree_bytes.iter().all(|byte| *byte == 0),
162 AccountCompressionError::IncorrectAccountType
163 );
164
165 let (mut header_bytes, rest) =
166 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
167
168 let mut header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
169 require_eq!(
170 header.account_type,
171 CompressionAccountType::Uninitialized,
172 AccountCompressionError::IncorrectAccountType
173 );
174 require_eq!(
175 header.get_max_depth(),
176 0,
177 AccountCompressionError::IncorrectAccountType
178 );
179 require_eq!(
180 header.get_max_buffer_size(),
181 0,
182 AccountCompressionError::IncorrectAccountType
183 );
184 header.initialize(
185 max_depth,
186 max_buffer_size,
187 &ctx.accounts.authority.key(),
188 Clock::get()?.slot,
189 );
190 header.serialize(&mut header_bytes)?;
191
192 let merkle_tree_size = merkle_tree_get_size(&header)?;
193 if rest.len() < merkle_tree_size {
194 return Err(ProgramError::InvalidAccountData.into());
195 }
196 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
197 let id = ctx.accounts.merkle_tree.key();
198
199 let change_log_event = merkle_tree_initialize_empty(&header, id, tree_bytes)?;
200
201 wrap_event(
202 &AccountCompressionEvent::ChangeLog(*change_log_event),
203 &ctx.accounts.noop,
204 )?;
205 update_canopy(canopy_bytes, header.get_max_depth(), None)
206 }
207
208 pub fn replace_leaf(
276 ctx: Context<Modify>,
277 root: [u8; 32],
278 previous_leaf: [u8; 32],
279 new_leaf: [u8; 32],
280 index: u32,
281 ) -> Result<()> {
282 require_eq!(
283 *ctx.accounts.merkle_tree.owner,
284 crate::id(),
285 AccountCompressionError::IncorrectAccountOwner
286 );
287 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
288 let (header_bytes, rest) =
289 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
290
291 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
292 header.assert_valid_authority(&ctx.accounts.authority.key())?;
293 header.assert_valid_leaf_index(index)?;
294
295 let merkle_tree_size = merkle_tree_get_size(&header)?;
296 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
297
298 let mut proof = vec![];
299 for node in ctx.remaining_accounts.iter() {
300 proof.push(node.key().to_bytes());
301 }
302 fill_in_proof_from_canopy(canopy_bytes, header.get_max_depth(), index, &mut proof)?;
303 let id = ctx.accounts.merkle_tree.key();
304 let args = &SetLeafArgs {
306 current_root: root,
307 previous_leaf,
308 new_leaf,
309 proof_vec: proof,
310 index,
311 };
312 let change_log_event = merkle_tree_set_leaf(&header, id, tree_bytes, args)?;
313
314 update_canopy(
315 canopy_bytes,
316 header.get_max_depth(),
317 Some(&change_log_event),
318 )?;
319 wrap_event(
320 &AccountCompressionEvent::ChangeLog(*change_log_event),
321 &ctx.accounts.noop,
322 )
323 }
324
325 pub fn transfer_authority(
328 ctx: Context<TransferAuthority>,
329 new_authority: Pubkey,
330 ) -> Result<()> {
331 require_eq!(
332 *ctx.accounts.merkle_tree.owner,
333 crate::id(),
334 AccountCompressionError::IncorrectAccountOwner
335 );
336 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
337 let (mut header_bytes, _) =
338 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
339
340 let mut header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
341 header.assert_valid_authority(&ctx.accounts.authority.key())?;
342
343 header.set_new_authority(&new_authority);
344 header.serialize(&mut header_bytes)?;
345
346 Ok(())
347 }
348
349 pub fn verify_leaf(
352 ctx: Context<VerifyLeaf>,
353 root: [u8; 32],
354 leaf: [u8; 32],
355 index: u32,
356 ) -> Result<()> {
357 require_eq!(
358 *ctx.accounts.merkle_tree.owner,
359 crate::id(),
360 AccountCompressionError::IncorrectAccountOwner
361 );
362 let merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_data()?;
363 let (header_bytes, rest) =
364 merkle_tree_bytes.split_at(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
365
366 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
367 header.assert_valid()?;
368 header.assert_valid_leaf_index(index)?;
369
370 let merkle_tree_size = merkle_tree_get_size(&header)?;
371 let (tree_bytes, canopy_bytes) = rest.split_at(merkle_tree_size);
372
373 let mut proof = vec![];
374 for node in ctx.remaining_accounts.iter() {
375 proof.push(node.key().to_bytes());
376 }
377 fill_in_proof_from_canopy(canopy_bytes, header.get_max_depth(), index, &mut proof)?;
378 let id = ctx.accounts.merkle_tree.key();
379
380 let args = &ProveLeafArgs {
381 current_root: root,
382 leaf,
383 proof_vec: proof,
384 index,
385 };
386 merkle_tree_prove_leaf(&header, id, tree_bytes, args)?;
387
388 Ok(())
389 }
390
391 pub fn append(ctx: Context<Modify>, leaf: [u8; 32]) -> Result<()> {
398 require_eq!(
399 *ctx.accounts.merkle_tree.owner,
400 crate::id(),
401 AccountCompressionError::IncorrectAccountOwner
402 );
403 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
404 let (header_bytes, rest) =
405 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
406
407 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
408 header.assert_valid_authority(&ctx.accounts.authority.key())?;
409
410 let id = ctx.accounts.merkle_tree.key();
411 let merkle_tree_size = merkle_tree_get_size(&header)?;
412 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
413 let change_log_event = merkle_tree_append_leaf(&header, id, tree_bytes, &leaf)?;
414 update_canopy(
415 canopy_bytes,
416 header.get_max_depth(),
417 Some(&change_log_event),
418 )?;
419 wrap_event(
420 &AccountCompressionEvent::ChangeLog(*change_log_event),
421 &ctx.accounts.noop,
422 )
423 }
424
425 pub fn insert_or_append(
430 ctx: Context<Modify>,
431 root: [u8; 32],
432 leaf: [u8; 32],
433 index: u32,
434 ) -> Result<()> {
435 require_eq!(
436 *ctx.accounts.merkle_tree.owner,
437 crate::id(),
438 AccountCompressionError::IncorrectAccountOwner
439 );
440 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
441 let (header_bytes, rest) =
442 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
443
444 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
445 header.assert_valid_authority(&ctx.accounts.authority.key())?;
446 header.assert_valid_leaf_index(index)?;
447
448 let merkle_tree_size = merkle_tree_get_size(&header)?;
449 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
450
451 let mut proof = vec![];
452 for node in ctx.remaining_accounts.iter() {
453 proof.push(node.key().to_bytes());
454 }
455 fill_in_proof_from_canopy(canopy_bytes, header.get_max_depth(), index, &mut proof)?;
456 let id = ctx.accounts.merkle_tree.key();
458 let args = &FillEmptyOrAppendArgs {
459 current_root: root,
460 leaf,
461 proof_vec: proof,
462 index,
463 };
464 let change_log_event = merkle_tree_fill_empty_or_append(&header, id, tree_bytes, args)?;
465
466 update_canopy(
467 canopy_bytes,
468 header.get_max_depth(),
469 Some(&change_log_event),
470 )?;
471 wrap_event(
472 &AccountCompressionEvent::ChangeLog(*change_log_event),
473 &ctx.accounts.noop,
474 )
475 }
476
477 pub fn close_empty_tree(ctx: Context<CloseTree>) -> Result<()> {
478 require_eq!(
479 *ctx.accounts.merkle_tree.owner,
480 crate::id(),
481 AccountCompressionError::IncorrectAccountOwner
482 );
483 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
484 let (header_bytes, rest) =
485 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
486
487 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
488 header.assert_valid_authority(&ctx.accounts.authority.key())?;
489
490 let merkle_tree_size = merkle_tree_get_size(&header)?;
491 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
492
493 let id = ctx.accounts.merkle_tree.key();
494 merkle_tree_prove_tree_is_empty(&header, id, tree_bytes)?;
495
496 let dest_starting_lamports = ctx.accounts.recipient.lamports();
499 **ctx.accounts.recipient.lamports.borrow_mut() = dest_starting_lamports
500 .checked_add(ctx.accounts.merkle_tree.lamports())
501 .unwrap();
502 **ctx.accounts.merkle_tree.lamports.borrow_mut() = 0;
503
504 header_bytes.fill(0);
506 tree_bytes.fill(0);
507 canopy_bytes.fill(0);
508
509 Ok(())
510 }
511}