spl_account_compression/
canopy.rs1use crate::error::AccountCompressionError;
20use crate::events::ChangeLogEvent;
21use anchor_lang::prelude::*;
22use bytemuck::{cast_slice, cast_slice_mut};
23use spl_concurrent_merkle_tree::node::{empty_node_cached, Node, EMPTY};
24use std::mem::size_of;
25
26#[inline(always)]
27pub fn check_canopy_bytes(canopy_bytes: &[u8]) -> Result<()> {
28 if canopy_bytes.len() % size_of::<Node>() != 0 {
29 msg!(
30 "Canopy byte length {} is not a multiple of {}",
31 canopy_bytes.len(),
32 size_of::<Node>()
33 );
34 err!(AccountCompressionError::CanopyLengthMismatch)
35 } else {
36 Ok(())
37 }
38}
39
40#[inline(always)]
41fn get_cached_path_length(canopy: &[Node], max_depth: u32) -> Result<u32> {
42 let closest_power_of_2 = (canopy.len() + 2) as u32;
45 if closest_power_of_2 & (closest_power_of_2 - 1) == 0 {
47 if closest_power_of_2 > (1 << (max_depth + 1)) {
51 msg!(
52 "Canopy size is too large. Size: {}. Max size: {}",
53 closest_power_of_2 - 2,
54 (1 << (max_depth + 1)) - 2
55 );
56 return err!(AccountCompressionError::CanopyLengthMismatch);
57 }
58 } else {
59 msg!(
60 "Canopy length {} is not 2 less than a power of 2",
61 canopy.len()
62 );
63 return err!(AccountCompressionError::CanopyLengthMismatch);
64 }
65 Ok(closest_power_of_2.trailing_zeros() - 1)
67}
68
69pub fn update_canopy(
70 canopy_bytes: &mut [u8],
71 max_depth: u32,
72 change_log: Option<&ChangeLogEvent>,
73) -> Result<()> {
74 check_canopy_bytes(canopy_bytes)?;
75 let canopy = cast_slice_mut::<u8, Node>(canopy_bytes);
76 let path_len = get_cached_path_length(canopy, max_depth)?;
77 if let Some(cl_event) = change_log {
78 match &*cl_event {
79 ChangeLogEvent::V1(cl) => {
80 for path_node in cl.path.iter().rev().skip(1).take(path_len as usize) {
82 canopy[(path_node.index - 2) as usize] = path_node.node;
84 }
85 }
86 }
87 }
88 Ok(())
89}
90
91pub fn fill_in_proof_from_canopy(
92 canopy_bytes: &[u8],
93 max_depth: u32,
94 index: u32,
95 proof: &mut Vec<Node>,
96) -> Result<()> {
97 let mut empty_node_cache = Box::new([EMPTY; 30]);
99 check_canopy_bytes(canopy_bytes)?;
100 let canopy = cast_slice::<u8, Node>(canopy_bytes);
101 let path_len = get_cached_path_length(canopy, max_depth)?;
102
103 let mut node_idx = ((1 << max_depth) + index) >> (max_depth - path_len);
106 let mut inferred_nodes = vec![];
107 while node_idx > 1 {
108 let shifted_index = node_idx as usize - 2;
110 let cached_idx = if shifted_index % 2 == 0 {
111 shifted_index + 1
112 } else {
113 shifted_index - 1
114 };
115 if canopy[cached_idx] == EMPTY {
116 let level = max_depth - (31 - node_idx.leading_zeros());
117 let empty_node = empty_node_cached::<30>(level, &mut empty_node_cache);
118 inferred_nodes.push(empty_node);
119 } else {
120 inferred_nodes.push(canopy[cached_idx]);
121 }
122 node_idx >>= 1;
123 }
124 let overlap = (proof.len() + inferred_nodes.len()).saturating_sub(max_depth as usize);
128 proof.extend(inferred_nodes.iter().skip(overlap));
129 Ok(())
130}