Skip to content

Commit c0b63e8

Browse files
authored
feat: add event queue seq number (#1586)
* feat: add event queue seq number * fix: tests * chore: updated photon * fix: address Merkle tree test & remove comment
1 parent 7ff105c commit c0b63e8

File tree

19 files changed

+222
-78
lines changed

19 files changed

+222
-78
lines changed

js/stateless.js/src/programs/layout.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -331,12 +331,28 @@ export function deserializeAppendNullifyCreateAddressInputsIndexer(
331331
addresses.push(address);
332332
offset += InsertAddressInputLayout.span;
333333
}
334-
const sequenceNumbersCount = buffer.readUInt8(offset);
334+
const outputSequenceNumbersCount = buffer.readUInt8(offset);
335335
offset += 1;
336-
const sequence_numbers = [];
337-
for (let i = 0; i < sequenceNumbersCount; i++) {
336+
const output_sequence_numbers = [];
337+
for (let i = 0; i < outputSequenceNumbersCount; i++) {
338338
const seq = MerkleTreeSequenceNumberLayout.decode(buffer, offset);
339-
sequence_numbers.push(seq);
339+
output_sequence_numbers.push(seq);
340+
offset += MerkleTreeSequenceNumberLayout.span;
341+
}
342+
const inputSequenceNumbersCount = buffer.readUInt8(offset);
343+
offset += 1;
344+
const inputSequence_numbers = [];
345+
for (let i = 0; i < inputSequenceNumbersCount; i++) {
346+
const seq = MerkleTreeSequenceNumberLayout.decode(buffer, offset);
347+
inputSequence_numbers.push(seq);
348+
offset += MerkleTreeSequenceNumberLayout.span;
349+
}
350+
const addressSequenceNumbersCount = buffer.readUInt8(offset);
351+
offset += 1;
352+
const addressSequence_numbers = [];
353+
for (let i = 0; i < addressSequenceNumbersCount; i++) {
354+
const seq = MerkleTreeSequenceNumberLayout.decode(buffer, offset);
355+
addressSequence_numbers.push(seq);
340356
offset += MerkleTreeSequenceNumberLayout.span;
341357
}
342358
const outputLeafIndicesCount = buffer.readUInt8(offset);
@@ -352,7 +368,7 @@ export function deserializeAppendNullifyCreateAddressInputsIndexer(
352368
leaves,
353369
nullifiers,
354370
addresses,
355-
sequence_numbers,
371+
sequence_numbers: output_sequence_numbers,
356372
output_leaf_indices,
357373
};
358374
}

js/stateless.js/tests/unit/utils/conversion.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ describe('deserialize apc cpi', () => {
3232
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3333
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3434
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
36-
0,
35+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
36+
0, 0, 0,
3737
];
3838

3939
it('deserialize acp cpi', () => {

program-libs/batched-merkle-tree/src/merkle_tree.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,10 @@ impl<'a> BatchedMerkleTreeAccount<'a> {
668668
Some(compressed_account_hash),
669669
None,
670670
current_slot,
671-
)
671+
)?;
672+
// Increment queue next index so that the indexer can use it like a sequence number.
673+
self.increment_queue_next_index();
674+
Ok(())
672675
}
673676

674677
pub fn insert_address_into_queue(

program-libs/batched-merkle-tree/tests/merkle_tree.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ use light_compressed_account::{
3333
pubkey::Pubkey,
3434
};
3535
use light_hasher::{Hasher, Poseidon};
36-
use light_merkle_tree_metadata::merkle_tree::TreeType;
3736
use light_merkle_tree_reference::MerkleTree;
3837
use light_prover_client::{
3938
gnark::helpers::{spawn_prover, ProofType, ProverConfig},
@@ -137,10 +136,8 @@ pub fn assert_input_queue_insert(
137136
.batches
138137
.get_mut(inserted_batch_index)
139138
.unwrap();
140-
// Address queue insertions append state, input queue insertions only nullify existing state
141-
if pre_account.tree_type == TreeType::BatchedAddress as u64 {
142-
pre_account.queue_batches.next_index += 1;
143-
}
139+
140+
pre_account.queue_batches.next_index += 1;
144141

145142
println!(
146143
"assert input queue batch update: expected_batch: {:?}",

program-libs/compressed-account/src/event.rs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,20 @@ pub struct PublicTransactionEvent {
3131
pub pubkey_array: Vec<Pubkey>,
3232
pub message: Option<Vec<u8>>,
3333
}
34-
34+
#[derive(Debug, Clone)]
3535
pub struct NewAddress {
3636
pub address: [u8; 32],
3737
pub mt_pubkey: Pubkey,
3838
}
3939

40+
#[derive(Debug, Clone)]
41+
pub struct BatchPublicTransactionEvent {
42+
pub event: PublicTransactionEvent,
43+
pub new_addresses: Vec<NewAddress>,
44+
pub input_sequence_numbers: Vec<MerkleTreeSequenceNumber>,
45+
pub address_sequence_numbers: Vec<MerkleTreeSequenceNumber>,
46+
}
47+
4048
// TODO: remove unwraps
4149
/// We piece the event together from 2 instructions:
4250
/// 1. light_system_program::{Invoke, InvokeCpi, InvokeCpiReadOnly} (one of the 3)
@@ -54,15 +62,15 @@ pub struct NewAddress {
5462
pub fn event_from_light_transaction(
5563
instructions: &[Vec<u8>],
5664
remaining_accounts: Vec<Vec<Pubkey>>,
57-
) -> Result<(Option<PublicTransactionEvent>, Option<Vec<NewAddress>>), ZeroCopyError> {
65+
) -> Result<Option<BatchPublicTransactionEvent>, ZeroCopyError> {
5866
let mut event = PublicTransactionEvent::default();
5967
let mut ix_set_cpi_context = false;
6068
let found_event = instructions.iter().any(|x| {
6169
match_system_program_instruction(x, false, &mut event, &mut ix_set_cpi_context).unwrap()
6270
});
6371
println!("found event {}", found_event);
6472
if !found_event {
65-
return Ok((None, None));
73+
return Ok(None);
6674
}
6775
println!("ix_set_cpi_context {}", ix_set_cpi_context);
6876
// If an instruction set the cpi context add the instructions that set the cpi context.
@@ -74,6 +82,8 @@ pub fn event_from_light_transaction(
7482
}
7583
// New addresses in batched trees.
7684
let mut new_addresses = Vec::new();
85+
let mut input_sequence_numbers = Vec::new();
86+
let mut address_sequence_numbers = Vec::new();
7787
let pos = instructions.iter().enumerate().position(|(i, x)| {
7888
if remaining_accounts[i].len() < 3 {
7989
return false;
@@ -82,6 +92,8 @@ pub fn event_from_light_transaction(
8292
x,
8393
&mut event,
8494
&mut new_addresses,
95+
&mut input_sequence_numbers,
96+
&mut address_sequence_numbers,
8597
&remaining_accounts[i][2..],
8698
)
8799
.unwrap()
@@ -92,21 +104,25 @@ pub fn event_from_light_transaction(
92104
println!("remaining accounts {:?}", remaining_accounts);
93105
event.pubkey_array = remaining_accounts[pos][2..].to_vec().clone();
94106
println!("event pubkey array {:?}", event.pubkey_array);
95-
let new_addresses = if new_addresses.is_empty() {
96-
None
97-
} else {
98-
Some(new_addresses)
99-
};
100-
Ok((Some(event), new_addresses))
107+
println!("input_sequence_numbers {:?}", input_sequence_numbers);
108+
println!("address_sequence_numbers {:?}", address_sequence_numbers);
109+
Ok(Some(BatchPublicTransactionEvent {
110+
event,
111+
new_addresses,
112+
input_sequence_numbers,
113+
address_sequence_numbers,
114+
}))
101115
} else {
102-
Ok((None, None))
116+
Ok(None)
103117
}
104118
}
105119

106120
pub fn match_account_compression_program_instruction(
107121
instruction: &[u8],
108122
event: &mut PublicTransactionEvent,
109123
new_addresses: &mut Vec<NewAddress>,
124+
input_sequence_numbers: &mut Vec<MerkleTreeSequenceNumber>,
125+
address_sequence_numbers: &mut Vec<MerkleTreeSequenceNumber>,
110126
accounts: &[Pubkey],
111127
) -> Result<bool, ZeroCopyError> {
112128
if instruction.len() < 8 {
@@ -122,7 +138,7 @@ pub fn match_account_compression_program_instruction(
122138
data.nullifiers.iter().map(|x| x.account_hash).collect();
123139
event.output_compressed_account_hashes = data.leaves.iter().map(|x| x.leaf).collect();
124140
event.sequence_numbers = data
125-
.sequence_numbers
141+
.output_sequence_numbers
126142
.iter()
127143
.map(|x| MerkleTreeSequenceNumber {
128144
pubkey: x.pubkey.into(),
@@ -151,6 +167,22 @@ pub fn match_account_compression_program_instruction(
151167
});
152168
}
153169
});
170+
data.input_sequence_numbers.iter().for_each(|x| {
171+
if x.pubkey != Pubkey::default().into() {
172+
input_sequence_numbers.push(MerkleTreeSequenceNumber {
173+
pubkey: x.pubkey.into(),
174+
seq: x.seq.into(),
175+
});
176+
}
177+
});
178+
data.address_sequence_numbers.iter().for_each(|x| {
179+
if x.pubkey != Pubkey::default().into() {
180+
address_sequence_numbers.push(MerkleTreeSequenceNumber {
181+
pubkey: x.pubkey.into(),
182+
seq: x.seq.into(),
183+
});
184+
}
185+
});
154186
Ok(true)
155187
}
156188
_ => Ok(false),

program-libs/compressed-account/src/instruction_data/insert_into_queues.rs

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ pub struct InsertIntoQueuesInstructionData<'a> {
6565
pub leaves: ZeroCopySlice<'a, u8, AppendLeavesInput, false>,
6666
pub nullifiers: ZeroCopySlice<'a, u8, InsertNullifierInput, false>,
6767
pub addresses: ZeroCopySlice<'a, u8, InsertAddressInput, false>,
68-
pub sequence_numbers: ZeroCopySlice<'a, u8, MerkleTreeSequenceNumber, false>,
68+
pub output_sequence_numbers: ZeroCopySlice<'a, u8, MerkleTreeSequenceNumber, false>,
69+
pub input_sequence_numbers: ZeroCopySlice<'a, u8, MerkleTreeSequenceNumber, false>,
70+
pub address_sequence_numbers: ZeroCopySlice<'a, u8, MerkleTreeSequenceNumber, false>,
6971
pub output_leaf_indices: ZeroCopySlice<'a, u8, U32, false>,
7072
}
7173

@@ -95,9 +97,12 @@ impl<'a> Deserialize<'a> for InsertIntoQueuesInstructionData<'a> {
9597

9698
let (addresses, bytes) =
9799
ZeroCopySlice::<u8, InsertAddressInput, false>::from_bytes_at(bytes)?;
98-
let (sequence_numbers, bytes) =
100+
let (output_sequence_numbers, bytes) =
101+
ZeroCopySlice::<u8, MerkleTreeSequenceNumber, false>::from_bytes_at(bytes)?;
102+
let (input_sequence_numbers, bytes) =
103+
ZeroCopySlice::<u8, MerkleTreeSequenceNumber, false>::from_bytes_at(bytes)?;
104+
let (address_sequence_numbers, bytes) =
99105
ZeroCopySlice::<u8, MerkleTreeSequenceNumber, false>::from_bytes_at(bytes)?;
100-
101106
let output_leaf_indices =
102107
ZeroCopySlice::<u8, zerocopy::little_endian::U32, false>::from_bytes(bytes)?;
103108
Ok((
@@ -106,7 +111,9 @@ impl<'a> Deserialize<'a> for InsertIntoQueuesInstructionData<'a> {
106111
leaves,
107112
nullifiers,
108113
addresses,
109-
sequence_numbers,
114+
output_sequence_numbers,
115+
input_sequence_numbers,
116+
address_sequence_numbers,
110117
output_leaf_indices,
111118
},
112119
bytes,
@@ -134,7 +141,9 @@ pub struct InsertIntoQueuesInstructionDataMut<'a> {
134141
pub leaves: ZeroCopySliceMut<'a, u8, AppendLeavesInput, false>,
135142
pub nullifiers: ZeroCopySliceMut<'a, u8, InsertNullifierInput, false>,
136143
pub addresses: ZeroCopySliceMut<'a, u8, InsertAddressInput, false>,
137-
pub sequence_numbers: ZeroCopySliceMut<'a, u8, MerkleTreeSequenceNumber, false>,
144+
pub output_sequence_numbers: ZeroCopySliceMut<'a, u8, MerkleTreeSequenceNumber, false>,
145+
pub input_sequence_numbers: ZeroCopySliceMut<'a, u8, MerkleTreeSequenceNumber, false>,
146+
pub address_sequence_numbers: ZeroCopySliceMut<'a, u8, MerkleTreeSequenceNumber, false>,
138147
pub output_leaf_indices: ZeroCopySliceMut<'a, u8, U32, false>,
139148
}
140149

@@ -147,11 +156,35 @@ impl<'a> InsertIntoQueuesInstructionDataMut<'a> {
147156
self.meta.is_invoked_by_program = value as u8;
148157
}
149158

159+
pub fn insert_input_sequence_number(&mut self, index: &mut usize, pubkey: &Pubkey, seq: u64) {
160+
Self::insert_sequence_number(&mut self.input_sequence_numbers, index, pubkey, seq);
161+
}
162+
163+
pub fn insert_address_sequence_number(&mut self, index: &mut usize, pubkey: &Pubkey, seq: u64) {
164+
Self::insert_sequence_number(&mut self.address_sequence_numbers, index, pubkey, seq);
165+
}
166+
167+
fn insert_sequence_number(
168+
sequence_numbers: &mut ZeroCopySliceMut<'a, u8, MerkleTreeSequenceNumber, false>,
169+
index: &mut usize,
170+
pubkey: &Pubkey,
171+
seq: u64,
172+
) {
173+
let pos = sequence_numbers.iter().position(|x| x.pubkey == *pubkey);
174+
if pos.is_none() {
175+
sequence_numbers[*index].pubkey = *pubkey;
176+
sequence_numbers[*index].seq = seq.into();
177+
*index += 1;
178+
}
179+
}
180+
150181
pub fn required_size_for_capacity(
151182
leaves_capacity: u8,
152183
nullifiers_capacity: u8,
153184
addresses_capacity: u8,
154185
num_output_trees: u8,
186+
num_input_trees: u8,
187+
num_address_trees: u8,
155188
) -> usize {
156189
size_of::<InsertIntoQueuesInstructionDataMeta>()
157190
+ ZeroCopySliceMut::<u8, AppendLeavesInput, false>::required_size_for_capacity(
@@ -166,6 +199,12 @@ impl<'a> InsertIntoQueuesInstructionDataMut<'a> {
166199
+ ZeroCopySliceMut::<u8, MerkleTreeSequenceNumber, false>::required_size_for_capacity(
167200
num_output_trees,
168201
)
202+
+ ZeroCopySliceMut::<u8, MerkleTreeSequenceNumber, false>::required_size_for_capacity(
203+
num_input_trees,
204+
)
205+
+ ZeroCopySliceMut::<u8, MerkleTreeSequenceNumber, false>::required_size_for_capacity(
206+
num_address_trees,
207+
)
169208
+ ZeroCopySliceMut::<u8, U32, false>::required_size_for_capacity(leaves_capacity)
170209
}
171210

@@ -175,6 +214,8 @@ impl<'a> InsertIntoQueuesInstructionDataMut<'a> {
175214
nullifiers_capacity: u8,
176215
addresses_capacity: u8,
177216
num_output_trees: u8,
217+
num_input_trees: u8,
218+
num_address_trees: u8,
178219
) -> std::result::Result<Self, ZeroCopyError> {
179220
let (meta, bytes) =
180221
Ref::<&mut [u8], InsertIntoQueuesInstructionDataMeta>::from_prefix(bytes)?;
@@ -186,18 +227,30 @@ impl<'a> InsertIntoQueuesInstructionDataMut<'a> {
186227
)?;
187228
let (addresses, bytes) =
188229
ZeroCopySliceMut::<u8, InsertAddressInput, false>::new_at(addresses_capacity, bytes)?;
189-
let (sequence_numbers, bytes) =
190-
ZeroCopySliceMut::<u8, MerkleTreeSequenceNumber, false>::new_at(
191-
num_output_trees,
192-
bytes,
193-
)?;
230+
let (output_sequence_numbers, bytes) = ZeroCopySliceMut::<
231+
u8,
232+
MerkleTreeSequenceNumber,
233+
false,
234+
>::new_at(num_output_trees, bytes)?;
235+
let (input_sequence_numbers, bytes) = ZeroCopySliceMut::<
236+
u8,
237+
MerkleTreeSequenceNumber,
238+
false,
239+
>::new_at(num_input_trees, bytes)?;
240+
let (address_sequence_numbers, bytes) = ZeroCopySliceMut::<
241+
u8,
242+
MerkleTreeSequenceNumber,
243+
false,
244+
>::new_at(num_address_trees, bytes)?;
194245
let output_leaf_indices = ZeroCopySliceMut::<u8, U32, false>::new(leaves_capacity, bytes)?;
195246
Ok(InsertIntoQueuesInstructionDataMut {
196247
meta,
197248
leaves,
198249
nullifiers,
199250
addresses,
200-
sequence_numbers,
251+
output_sequence_numbers,
252+
input_sequence_numbers,
253+
address_sequence_numbers,
201254
output_leaf_indices,
202255
})
203256
}
@@ -230,11 +283,15 @@ fn test_rnd_insert_into_queues_ix_data() {
230283
let nullifiers_capacity: u8 = rng.gen();
231284
let addresses_capacity: u8 = rng.gen();
232285
let num_output_trees: u8 = rng.gen();
286+
let num_input_trees: u8 = rng.gen();
287+
let num_address_trees: u8 = rng.gen();
233288
let size = InsertIntoQueuesInstructionDataMut::required_size_for_capacity(
234289
leaves_capacity,
235290
nullifiers_capacity,
236291
addresses_capacity,
237292
num_output_trees,
293+
num_input_trees,
294+
num_address_trees,
238295
);
239296
let mut bytes = vec![0u8; size];
240297
let mut new_data = InsertIntoQueuesInstructionDataMut::new(
@@ -243,6 +300,8 @@ fn test_rnd_insert_into_queues_ix_data() {
243300
nullifiers_capacity,
244301
addresses_capacity,
245302
num_output_trees,
303+
num_input_trees,
304+
num_address_trees,
246305
)
247306
.unwrap();
248307
*new_data.meta = InsertIntoQueuesInstructionDataMeta {

0 commit comments

Comments
 (0)