light_compressed_pda/invoke/
processor.rs1use anchor_lang::{prelude::*, Bumps};
2use light_heap::{bench_sbf_end, bench_sbf_start};
3use light_verifier::CompressedProof as CompressedVerifierProof;
4
5use crate::{
6 errors::CompressedPdaError,
7 invoke::{
8 address::{derive_new_addresses, insert_addresses_into_address_merkle_tree_queue},
9 append_state::insert_output_compressed_accounts_into_state_merkle_tree,
10 emit_event::emit_state_transition_event,
11 nullify_state::insert_nullifiers,
12 sol_compression::compression_lamports,
13 verify_state_proof::{
14 fetch_roots, fetch_roots_address_merkle_tree, hash_input_compressed_accounts,
15 sum_check, verify_state_proof,
16 },
17 },
18 sdk::accounts::{InvokeAccounts, SignerAccounts},
19 InstructionDataInvoke,
20};
21
22#[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize)]
24pub struct CompressedProof {
25 pub a: [u8; 32],
26 pub b: [u8; 64],
27 pub c: [u8; 32],
28}
29
30impl Default for CompressedProof {
31 fn default() -> Self {
32 Self {
33 a: [0; 32],
34 b: [0; 64],
35 c: [0; 32],
36 }
37 }
38}
39
40pub fn process<
41 'a,
42 'b,
43 'c: 'info,
44 'info,
45 A: InvokeAccounts<'info> + SignerAccounts<'info> + Bumps,
46>(
47 inputs: InstructionDataInvoke,
48 invoking_program: Option<Pubkey>,
49 ctx: Context<'a, 'b, 'c, 'info, A>,
50) -> Result<()> {
51 bench_sbf_start!("cpda_sum_check");
54 sum_check(
55 &inputs.input_compressed_accounts_with_merkle_context,
56 &inputs.output_compressed_accounts,
57 &inputs.relay_fee,
58 &inputs.compression_lamports,
59 &inputs.is_compress,
60 )?;
61 bench_sbf_end!("cpda_sum_check");
62 bench_sbf_start!("cpda_process_compression");
64 if inputs.compression_lamports.is_some() {
65 compression_lamports(&inputs, &ctx)?;
66 }
67 bench_sbf_end!("cpda_process_compression");
68
69 let mut input_compressed_account_hashes =
70 vec![[0u8; 32]; inputs.input_compressed_accounts_with_merkle_context.len()];
71 let mut input_compressed_account_addresses: Vec<Option<[u8; 32]>> =
72 vec![None; inputs.input_compressed_accounts_with_merkle_context.len()];
73
74 let mut output_leaf_indices = vec![0u32; inputs.output_compressed_accounts.len()];
75 let mut output_compressed_account_hashes =
76 vec![[0u8; 32]; inputs.output_compressed_accounts.len()];
77 let mut hashed_pubkeys =
79 Vec::<(Pubkey, [u8; 32])>::with_capacity(ctx.remaining_accounts.len() + 1);
80
81 if !inputs
83 .input_compressed_accounts_with_merkle_context
84 .is_empty()
85 || !inputs.new_address_params.is_empty()
86 {
87 bench_sbf_start!("cpda_hash_input_compressed_accounts");
89 if !inputs
90 .input_compressed_accounts_with_merkle_context
91 .is_empty()
92 {
93 hash_input_compressed_accounts(
94 ctx.remaining_accounts,
95 &inputs,
96 &mut input_compressed_account_hashes,
97 &mut input_compressed_account_addresses,
98 &mut hashed_pubkeys,
99 )?;
100 }
101
102 bench_sbf_end!("cpda_hash_input_compressed_accounts");
103 let mut new_addresses = vec![[0u8; 32]; inputs.new_address_params.len()];
104 if !new_addresses.is_empty() {
106 derive_new_addresses(
107 &inputs,
108 &ctx,
109 &mut input_compressed_account_addresses,
110 &mut new_addresses,
111 );
112 insert_addresses_into_address_merkle_tree_queue(
113 &ctx,
114 &new_addresses,
115 &inputs.new_address_params,
116 &invoking_program,
117 )?;
118 }
119 bench_sbf_start!("cpda_verify_state_proof");
120 let mut new_address_roots = vec![[0u8; 32]; inputs.new_address_params.len()];
121 fetch_roots_address_merkle_tree(&inputs.new_address_params, &ctx, &mut new_address_roots)?;
123 let mut roots = vec![[0u8; 32]; inputs.input_compressed_accounts_with_merkle_context.len()];
124 fetch_roots(&inputs, &ctx, &mut roots)?;
125 let proof = match &inputs.proof {
126 Some(proof) => proof,
127 None => return err!(CompressedPdaError::ProofIsNone),
128 };
129 let compressed_verifier_proof = CompressedVerifierProof {
130 a: proof.a,
131 b: proof.b,
132 c: proof.c,
133 };
134 match verify_state_proof(
135 &roots,
136 &input_compressed_account_hashes,
137 &new_address_roots,
138 new_addresses.as_slice(),
139 &compressed_verifier_proof,
140 ) {
141 Ok(_) => anchor_lang::Result::Ok(()),
142 Err(e) => {
143 msg!(
144 "input_compressed_accounts_with_merkle_context: {:?}",
145 inputs.input_compressed_accounts_with_merkle_context
146 );
147 Err(e)
148 }
149 }?;
150 bench_sbf_end!("cpda_verify_state_proof");
151 bench_sbf_start!("cpda_nullifiers");
153 insert_nullifiers(
154 &inputs,
155 &ctx,
156 &input_compressed_account_hashes,
157 &invoking_program,
158 )?;
159 bench_sbf_end!("cpda_nullifiers");
160 } else if inputs.proof.is_some() {
161 msg!("Proof is some but no input compressed accounts or new addresses provided.");
162 return err!(CompressedPdaError::ProofIsSome);
163 }
164 bench_sbf_end!("cpda_nullifiers");
165
166 const ITER_SIZE: usize = 28;
167 if !inputs.output_compressed_accounts.is_empty() {
169 let mut i = 0;
170 for _ in inputs.output_compressed_accounts.iter().step_by(ITER_SIZE) {
171 bench_sbf_start!("cpda_append");
172 insert_output_compressed_accounts_into_state_merkle_tree::<ITER_SIZE, A>(
173 &inputs,
174 &ctx,
175 &mut output_leaf_indices,
176 &mut output_compressed_account_hashes,
177 &mut input_compressed_account_addresses,
178 &mut i,
179 &invoking_program,
180 &mut hashed_pubkeys,
181 )?;
182 bench_sbf_end!("cpda_append");
183 }
184 }
185 bench_sbf_start!("emit_state_transition_event");
186
187 bench_sbf_start!("emit_state_transition_event");
189 emit_state_transition_event(
190 inputs,
191 &ctx,
192 input_compressed_account_hashes,
193 output_compressed_account_hashes,
194 output_leaf_indices,
195 )?;
196 bench_sbf_end!("emit_state_transition_event");
197
198 Ok(())
199}
200
201