light_system_program/invoke/
processor.rs1use account_compression::utils::transfer_lamports::transfer_lamports_cpi;
2use anchor_lang::{prelude::*, Bumps};
3use light_heap::{bench_sbf_end, bench_sbf_start};
4use light_verifier::CompressedProof as CompressedVerifierProof;
5
6use crate::{
7 errors::SystemProgramError,
8 invoke::{
9 address::{derive_new_addresses, insert_addresses_into_address_merkle_tree_queue},
10 append_state::insert_output_compressed_accounts_into_state_merkle_tree,
11 emit_event::emit_state_transition_event,
12 nullify_state::insert_nullifiers,
13 sol_compression::compress_or_decompress_lamports,
14 sum_check::sum_check,
15 verify_state_proof::{
16 fetch_input_compressed_account_roots, fetch_roots_address_merkle_tree,
17 hash_input_compressed_accounts, verify_state_proof,
18 },
19 },
20 sdk::accounts::{InvokeAccounts, SignerAccounts},
21 InstructionDataInvoke,
22};
23
24#[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize)]
26pub struct CompressedProof {
27 pub a: [u8; 32],
28 pub b: [u8; 64],
29 pub c: [u8; 32],
30}
31
32impl Default for CompressedProof {
33 fn default() -> Self {
34 Self {
35 a: [0; 32],
36 b: [0; 64],
37 c: [0; 32],
38 }
39 }
40}
41
42pub fn process<
50 'a,
51 'b,
52 'c: 'info,
53 'info,
54 A: InvokeAccounts<'info> + SignerAccounts<'info> + Bumps,
55>(
56 mut inputs: InstructionDataInvoke,
57 invoking_program: Option<Pubkey>,
58 ctx: Context<'a, 'b, 'c, 'info, A>,
59 cpi_context_inputs: usize,
60) -> Result<()> {
61 if inputs.relay_fee.is_some() {
62 unimplemented!("Relay fee is not implemented yet.");
63 }
64 bench_sbf_start!("cpda_sum_check");
66 sum_check(
67 &inputs.input_compressed_accounts_with_merkle_context,
68 &inputs.output_compressed_accounts,
69 &inputs.relay_fee,
70 &inputs.compress_or_decompress_lamports,
71 &inputs.is_compress,
72 )?;
73 bench_sbf_end!("cpda_sum_check");
74 bench_sbf_start!("cpda_process_compression");
76 if inputs.compress_or_decompress_lamports.is_some() {
77 if inputs.is_compress && ctx.accounts.get_decompression_recipient().is_some() {
78 return err!(SystemProgramError::DecompressionRecipientDefined);
79 }
80 compress_or_decompress_lamports(&inputs, &ctx)?;
81 } else if ctx.accounts.get_decompression_recipient().is_some() {
82 return err!(SystemProgramError::DecompressionRecipientDefined);
83 } else if ctx.accounts.get_sol_pool_pda().is_some() {
84 return err!(SystemProgramError::SolPoolPdaDefined);
85 }
86 bench_sbf_end!("cpda_process_compression");
87
88 let num_input_compressed_accounts = inputs.input_compressed_accounts_with_merkle_context.len();
90 let num_new_addresses = inputs.new_address_params.len();
91 let num_output_compressed_accounts = inputs.output_compressed_accounts.len();
92 let mut input_compressed_account_hashes = vec![[0u8; 32]; num_input_compressed_accounts];
93
94 let mut compressed_account_addresses: Vec<Option<[u8; 32]>> =
95 vec![None; num_input_compressed_accounts + num_new_addresses];
96 let mut output_leaf_indices = vec![0u32; num_output_compressed_accounts];
97 let mut output_compressed_account_hashes = vec![[0u8; 32]; num_output_compressed_accounts];
98 let hashed_pubkeys_capacity =
102 1 + ctx.remaining_accounts.len() + num_output_compressed_accounts + cpi_context_inputs;
103 let mut hashed_pubkeys = Vec::<(Pubkey, [u8; 32])>::with_capacity(hashed_pubkeys_capacity);
104
105 if !inputs
107 .input_compressed_accounts_with_merkle_context
108 .is_empty()
109 || !inputs.new_address_params.is_empty()
110 {
111 let mut new_address_roots = vec![[0u8; 32]; num_new_addresses];
113 let mut input_compressed_account_roots = vec![[0u8; 32]; num_input_compressed_accounts];
114 bench_sbf_start!("cpda_hash_input_compressed_accounts");
116 if !inputs
117 .input_compressed_accounts_with_merkle_context
118 .is_empty()
119 {
120 hash_input_compressed_accounts(
121 ctx.remaining_accounts,
122 &inputs.input_compressed_accounts_with_merkle_context,
123 &mut input_compressed_account_hashes,
124 &mut compressed_account_addresses,
125 &mut hashed_pubkeys,
126 )?;
127 if hashed_pubkeys.capacity() != hashed_pubkeys_capacity {
130 msg!(
131 "hashed_pubkeys exceeded capacity. Used {}, allocated {}.",
132 hashed_pubkeys.capacity(),
133 hashed_pubkeys_capacity
134 );
135 return err!(SystemProgramError::InvalidCapacity);
136 }
137 fetch_input_compressed_account_roots(
138 &inputs.input_compressed_accounts_with_merkle_context,
139 &ctx,
140 &mut input_compressed_account_roots,
141 )?;
142 }
143
144 bench_sbf_end!("cpda_hash_input_compressed_accounts");
145 let mut new_addresses = vec![[0u8; 32]; num_new_addresses];
146 if !new_addresses.is_empty() {
148 derive_new_addresses(
149 &inputs.new_address_params,
150 num_input_compressed_accounts,
151 ctx.remaining_accounts,
152 &mut compressed_account_addresses,
153 &mut new_addresses,
154 )?;
155 let network_fee_bundle = insert_addresses_into_address_merkle_tree_queue(
156 &ctx,
157 &new_addresses,
158 &inputs.new_address_params,
159 &invoking_program,
160 )?;
161 if let Some(network_fee_bundle) = network_fee_bundle {
162 let (remaining_account_index, network_fee) = network_fee_bundle;
163 transfer_lamports_cpi(
164 ctx.accounts.get_fee_payer(),
165 &ctx.remaining_accounts[remaining_account_index as usize],
166 network_fee,
167 )?;
168 }
169 fetch_roots_address_merkle_tree(
170 &inputs.new_address_params,
171 &ctx,
172 &mut new_address_roots,
173 )?;
174 }
175 bench_sbf_start!("cpda_verify_state_proof");
176
177 let proof = match &inputs.proof {
178 Some(proof) => proof,
179 None => return err!(SystemProgramError::ProofIsNone),
180 };
181 let compressed_verifier_proof = CompressedVerifierProof {
182 a: proof.a,
183 b: proof.b,
184 c: proof.c,
185 };
186 match verify_state_proof(
187 &input_compressed_account_roots,
188 &input_compressed_account_hashes,
189 &new_address_roots,
190 &new_addresses,
191 &compressed_verifier_proof,
192 ) {
193 Ok(_) => Ok(()),
194 Err(e) => {
195 msg!(
196 "input_compressed_accounts_with_merkle_context: {:?}",
197 inputs.input_compressed_accounts_with_merkle_context
198 );
199 Err(e)
200 }
201 }?;
202 bench_sbf_end!("cpda_verify_state_proof");
203 bench_sbf_start!("cpda_nullifiers");
205 if !inputs
206 .input_compressed_accounts_with_merkle_context
207 .is_empty()
208 {
209 let network_fee_bundle = insert_nullifiers(
210 &inputs,
211 &ctx,
212 &input_compressed_account_hashes,
213 &invoking_program,
214 )?;
215 if let Some(network_fee_bundle) = network_fee_bundle {
216 let (remaining_account_index, network_fee) = network_fee_bundle;
217 transfer_lamports_cpi(
218 ctx.accounts.get_fee_payer(),
219 &ctx.remaining_accounts[remaining_account_index as usize],
220 network_fee,
221 )?;
222 }
223 }
224 bench_sbf_end!("cpda_nullifiers");
225 } else if inputs.proof.is_some() {
226 return err!(SystemProgramError::ProofIsSome);
227 } else if inputs
228 .input_compressed_accounts_with_merkle_context
229 .is_empty()
230 && inputs.new_address_params.is_empty()
231 && inputs.output_compressed_accounts.is_empty()
232 {
233 return err!(SystemProgramError::EmptyInputs);
234 }
235 bench_sbf_end!("cpda_nullifiers");
236
237 let mut sequence_numbers = Vec::with_capacity(ctx.remaining_accounts.len());
242 if !inputs.output_compressed_accounts.is_empty() {
244 bench_sbf_start!("cpda_append");
245 insert_output_compressed_accounts_into_state_merkle_tree(
246 &mut inputs.output_compressed_accounts,
247 &ctx,
248 &mut output_leaf_indices,
249 &mut output_compressed_account_hashes,
250 &mut compressed_account_addresses,
251 &invoking_program,
252 &mut hashed_pubkeys,
253 &mut sequence_numbers,
254 )?;
255 if hashed_pubkeys.capacity() != hashed_pubkeys_capacity {
258 msg!(
259 "hashed_pubkeys exceeded capacity. Used {}, allocated {}.",
260 hashed_pubkeys.capacity(),
261 hashed_pubkeys_capacity
262 );
263 return err!(SystemProgramError::InvalidCapacity);
264 }
265 bench_sbf_end!("cpda_append");
266 }
267 bench_sbf_start!("emit_state_transition_event");
268 sequence_numbers.shrink_to_fit();
270 bench_sbf_start!("emit_state_transition_event");
272 emit_state_transition_event(
273 inputs,
274 &ctx,
275 input_compressed_account_hashes,
276 output_compressed_account_hashes,
277 output_leaf_indices,
278 sequence_numbers,
279 )?;
280 bench_sbf_end!("emit_state_transition_event");
281
282 Ok(())
283}