1use anchor_lang::{
26 prelude::*,
27 solana_program::sysvar::{clock::Clock, rent::Rent},
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::{
44 check_canopy_bytes, check_canopy_no_nodes_to_right_of_index, check_canopy_root,
45 fill_in_proof_from_canopy, set_canopy_leaf_nodes, update_canopy,
46};
47use crate::concurrent_tree_wrapper::*;
48pub use crate::error::AccountCompressionError;
49pub use crate::events::{AccountCompressionEvent, ChangeLogEvent};
50use crate::noop::wrap_event;
51use crate::state::{
52 merkle_tree_get_size, ConcurrentMerkleTreeHeader, CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1,
53};
54
55pub use spl_concurrent_merkle_tree::{
57 concurrent_merkle_tree::{ConcurrentMerkleTree, FillEmptyOrAppendArgs},
58 error::ConcurrentMerkleTreeError,
59 node::Node,
60 node::EMPTY,
61};
62
63declare_id!("hcmtvP1ACESumHKeVGwBciai2LXtRHp1Yz2JQAEvQnZ");
64
65#[derive(Accounts)]
67pub struct Initialize<'info> {
68 #[account(zero)]
69 pub merkle_tree: UncheckedAccount<'info>,
71
72 pub authority: Signer<'info>,
75
76 pub noop: Program<'info, Noop>,
78}
79
80#[derive(Accounts)]
86pub struct Modify<'info> {
87 #[account(mut)]
88 pub merkle_tree: UncheckedAccount<'info>,
90
91 pub authority: Signer<'info>,
94
95 pub noop: Program<'info, Noop>,
97}
98
99#[derive(Accounts)]
102pub struct VerifyLeaf<'info> {
103 pub merkle_tree: UncheckedAccount<'info>,
105}
106
107#[derive(Accounts)]
109pub struct TransferAuthority<'info> {
110 #[account(mut)]
111 pub merkle_tree: UncheckedAccount<'info>,
113
114 pub authority: Signer<'info>,
117}
118
119#[derive(Accounts)]
121pub struct CloseTree<'info> {
122 #[account(mut)]
123 pub merkle_tree: AccountInfo<'info>,
125
126 pub authority: Signer<'info>,
128
129 #[account(mut)]
131 pub recipient: AccountInfo<'info>,
132}
133
134#[program]
135pub mod spl_account_compression {
136 use super::*;
137
138 pub fn init_empty_merkle_tree(
151 ctx: Context<Initialize>,
152 max_depth: u32,
153 max_buffer_size: u32,
154 ) -> Result<()> {
155 require_eq!(
156 *ctx.accounts.merkle_tree.owner,
157 crate::id(),
158 AccountCompressionError::IncorrectAccountOwner
159 );
160 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
161
162 let (mut header_bytes, rest) =
163 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
164
165 let mut header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
166 header.initialize(
167 max_depth,
168 max_buffer_size,
169 &ctx.accounts.authority.key(),
170 Clock::get()?.slot,
171 );
172 header.serialize(&mut header_bytes)?;
173
174 let merkle_tree_size = merkle_tree_get_size(&header)?;
175 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
176 let id = ctx.accounts.merkle_tree.key();
177
178 let change_log_event = merkle_tree_initialize_empty(&header, id, tree_bytes)?;
179
180 wrap_event(
181 &AccountCompressionEvent::ChangeLog(*change_log_event),
182 &ctx.accounts.noop,
183 )?;
184 update_canopy(canopy_bytes, header.get_max_depth(), None)
185 }
186
187 pub fn prepare_batch_merkle_tree(
204 ctx: Context<Initialize>,
205 max_depth: u32,
206 max_buffer_size: u32,
207 ) -> Result<()> {
208 require_eq!(
209 *ctx.accounts.merkle_tree.owner,
210 crate::id(),
211 AccountCompressionError::IncorrectAccountOwner
212 );
213 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
214
215 let (mut header_bytes, rest) =
216 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
217
218 let mut header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
219 header.initialize_batched(
220 max_depth,
221 max_buffer_size,
222 &ctx.accounts.authority.key(),
223 Clock::get()?.slot,
224 );
225 header.serialize(&mut header_bytes)?;
226 let merkle_tree_size = merkle_tree_get_size(&header)?;
227 let (_tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
228 check_canopy_bytes(canopy_bytes)
229 }
230
231 pub fn append_canopy_nodes(
246 ctx: Context<Modify>,
247 start_index: u32,
248 canopy_nodes: Vec<[u8; 32]>,
249 ) -> Result<()> {
250 require_eq!(
251 *ctx.accounts.merkle_tree.owner,
252 crate::id(),
253 AccountCompressionError::IncorrectAccountOwner
254 );
255 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
256
257 let (header_bytes, rest) =
258 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
259
260 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
261 header.assert_valid_authority(&ctx.accounts.authority.key())?;
262 header.assert_is_batch_initialized()?;
263 let merkle_tree_size = merkle_tree_get_size(&header)?;
266 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
267 require!(
269 tree_bytes_uninitialized(tree_bytes),
270 AccountCompressionError::TreeAlreadyInitialized
271 );
272 set_canopy_leaf_nodes(
273 canopy_bytes,
274 header.get_max_depth(),
275 start_index,
276 &canopy_nodes,
277 )
278 }
279
280 pub fn init_prepared_tree_with_root(
290 ctx: Context<Modify>,
291 root: [u8; 32],
292 rightmost_leaf: [u8; 32],
293 rightmost_index: u32,
294 ) -> Result<()> {
295 require_eq!(
296 *ctx.accounts.merkle_tree.owner,
297 crate::id(),
298 AccountCompressionError::IncorrectAccountOwner
299 );
300 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
301
302 let (header_bytes, rest) =
303 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
304 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
306 header.assert_valid_authority(&ctx.accounts.authority.key())?;
307 header.assert_is_batch_initialized()?;
308 let merkle_tree_size = merkle_tree_get_size(&header)?;
309 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
310 check_canopy_root(canopy_bytes, &root, header.get_max_depth())?;
312 check_canopy_no_nodes_to_right_of_index(
314 canopy_bytes,
315 header.get_max_depth(),
316 rightmost_index,
317 )?;
318
319 let mut proof = vec![];
321 for node in ctx.remaining_accounts.iter() {
322 proof.push(node.key().to_bytes());
323 }
324 fill_in_proof_from_canopy(
325 canopy_bytes,
326 header.get_max_depth(),
327 rightmost_index,
328 &mut proof,
329 )?;
330 assert_eq!(proof.len(), header.get_max_depth() as usize);
331
332 let id = ctx.accounts.merkle_tree.key();
333 let args = &InitializeWithRootArgs {
335 root,
336 rightmost_leaf,
337 proof_vec: proof,
338 index: rightmost_index,
339 };
340 let change_log = merkle_tree_initialize_with_root(&header, id, tree_bytes, args)?;
341 update_canopy(canopy_bytes, header.get_max_depth(), Some(&change_log))?;
342 wrap_event(
343 &AccountCompressionEvent::ChangeLog(*change_log),
344 &ctx.accounts.noop,
345 )
346 }
347
348 pub fn replace_leaf(
352 ctx: Context<Modify>,
353 root: [u8; 32],
354 previous_leaf: [u8; 32],
355 new_leaf: [u8; 32],
356 index: u32,
357 ) -> Result<()> {
358 require_eq!(
359 *ctx.accounts.merkle_tree.owner,
360 crate::id(),
361 AccountCompressionError::IncorrectAccountOwner
362 );
363 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
364 let (header_bytes, rest) =
365 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
366
367 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
368 header.assert_valid_authority(&ctx.accounts.authority.key())?;
369 header.assert_valid_leaf_index(index)?;
370
371 let merkle_tree_size = merkle_tree_get_size(&header)?;
372 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
373
374 let mut proof = vec![];
375 for node in ctx.remaining_accounts.iter() {
376 proof.push(node.key().to_bytes());
377 }
378 fill_in_proof_from_canopy(canopy_bytes, header.get_max_depth(), index, &mut proof)?;
379 let id = ctx.accounts.merkle_tree.key();
380 let args = &SetLeafArgs {
382 current_root: root,
383 previous_leaf,
384 new_leaf,
385 proof_vec: proof,
386 index,
387 };
388 let change_log_event = merkle_tree_set_leaf(&header, id, tree_bytes, args)?;
389
390 update_canopy(
391 canopy_bytes,
392 header.get_max_depth(),
393 Some(&change_log_event),
394 )?;
395 wrap_event(
396 &AccountCompressionEvent::ChangeLog(*change_log_event),
397 &ctx.accounts.noop,
398 )
399 }
400
401 pub fn transfer_authority(
404 ctx: Context<TransferAuthority>,
405 new_authority: Pubkey,
406 ) -> Result<()> {
407 require_eq!(
408 *ctx.accounts.merkle_tree.owner,
409 crate::id(),
410 AccountCompressionError::IncorrectAccountOwner
411 );
412 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
413 let (mut header_bytes, _) =
414 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
415
416 let mut header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
417 header.assert_valid_authority(&ctx.accounts.authority.key())?;
418
419 header.set_new_authority(&new_authority);
420 header.serialize(&mut header_bytes)?;
421
422 Ok(())
423 }
424
425 pub fn verify_leaf(
428 ctx: Context<VerifyLeaf>,
429 root: [u8; 32],
430 leaf: [u8; 32],
431 index: u32,
432 ) -> Result<()> {
433 require_eq!(
434 *ctx.accounts.merkle_tree.owner,
435 crate::id(),
436 AccountCompressionError::IncorrectAccountOwner
437 );
438 let merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_data()?;
439 let (header_bytes, rest) =
440 merkle_tree_bytes.split_at(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
441
442 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
443 header.assert_valid()?;
444 header.assert_valid_leaf_index(index)?;
445
446 let merkle_tree_size = merkle_tree_get_size(&header)?;
447 let (tree_bytes, canopy_bytes) = rest.split_at(merkle_tree_size);
448
449 let mut proof = vec![];
450 for node in ctx.remaining_accounts.iter() {
451 proof.push(node.key().to_bytes());
452 }
453 fill_in_proof_from_canopy(canopy_bytes, header.get_max_depth(), index, &mut proof)?;
454 let id = ctx.accounts.merkle_tree.key();
455
456 let args = &ProveLeafArgs {
457 current_root: root,
458 leaf,
459 proof_vec: proof,
460 index,
461 };
462 merkle_tree_prove_leaf(&header, id, tree_bytes, args)?;
463
464 Ok(())
465 }
466
467 pub fn append(ctx: Context<Modify>, leaf: [u8; 32]) -> Result<()> {
474 require_eq!(
475 *ctx.accounts.merkle_tree.owner,
476 crate::id(),
477 AccountCompressionError::IncorrectAccountOwner
478 );
479 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
480 let (header_bytes, rest) =
481 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
482
483 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
484 header.assert_valid_authority(&ctx.accounts.authority.key())?;
485
486 let id = ctx.accounts.merkle_tree.key();
487 let merkle_tree_size = merkle_tree_get_size(&header)?;
488 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
489 let change_log_event = merkle_tree_append_leaf(&header, id, tree_bytes, &leaf)?;
490 update_canopy(
491 canopy_bytes,
492 header.get_max_depth(),
493 Some(&change_log_event),
494 )?;
495 wrap_event(
496 &AccountCompressionEvent::ChangeLog(*change_log_event),
497 &ctx.accounts.noop,
498 )
499 }
500
501 pub fn insert_or_append(
506 ctx: Context<Modify>,
507 root: [u8; 32],
508 leaf: [u8; 32],
509 index: u32,
510 ) -> Result<()> {
511 require_eq!(
512 *ctx.accounts.merkle_tree.owner,
513 crate::id(),
514 AccountCompressionError::IncorrectAccountOwner
515 );
516 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
517 let (header_bytes, rest) =
518 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
519
520 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
521 header.assert_valid_authority(&ctx.accounts.authority.key())?;
522 header.assert_valid_leaf_index(index)?;
523
524 let merkle_tree_size = merkle_tree_get_size(&header)?;
525 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
526
527 let mut proof = vec![];
528 for node in ctx.remaining_accounts.iter() {
529 proof.push(node.key().to_bytes());
530 }
531 fill_in_proof_from_canopy(canopy_bytes, header.get_max_depth(), index, &mut proof)?;
532 let id = ctx.accounts.merkle_tree.key();
534 let args = &FillEmptyOrAppendArgs {
535 current_root: root,
536 leaf,
537 proof_vec: proof,
538 index,
539 };
540 let change_log_event = merkle_tree_fill_empty_or_append(&header, id, tree_bytes, args)?;
541
542 update_canopy(
543 canopy_bytes,
544 header.get_max_depth(),
545 Some(&change_log_event),
546 )?;
547 wrap_event(
548 &AccountCompressionEvent::ChangeLog(*change_log_event),
549 &ctx.accounts.noop,
550 )
551 }
552
553 pub fn close_empty_tree(ctx: Context<CloseTree>) -> Result<()> {
554 require_eq!(
555 *ctx.accounts.merkle_tree.owner,
556 crate::id(),
557 AccountCompressionError::IncorrectAccountOwner
558 );
559 let mut merkle_tree_bytes = ctx.accounts.merkle_tree.try_borrow_mut_data()?;
560 let (header_bytes, rest) =
561 merkle_tree_bytes.split_at_mut(CONCURRENT_MERKLE_TREE_HEADER_SIZE_V1);
562
563 let header = ConcurrentMerkleTreeHeader::try_from_slice(header_bytes)?;
564 header.assert_valid_authority(&ctx.accounts.authority.key())?;
565
566 let merkle_tree_size = merkle_tree_get_size(&header)?;
567 let (tree_bytes, canopy_bytes) = rest.split_at_mut(merkle_tree_size);
568
569 let id = ctx.accounts.merkle_tree.key();
570 assert_tree_is_empty(&header, id, tree_bytes)?;
571
572 let dest_starting_lamports = ctx.accounts.recipient.lamports();
575 **ctx.accounts.recipient.lamports.borrow_mut() = dest_starting_lamports
576 .checked_add(ctx.accounts.merkle_tree.lamports())
577 .unwrap();
578 **ctx.accounts.merkle_tree.lamports.borrow_mut() = 0;
579
580 header_bytes.fill(0);
582 tree_bytes.fill(0);
583 canopy_bytes.fill(0);
584
585 Ok(())
586 }
587}