1use borsh::{BorshDeserialize, BorshSerialize};
8use bytemuck::{CheckedBitPattern, NoUninit, Pod, Zeroable};
9use num_derive::FromPrimitive;
10use num_traits::FromPrimitive;
11use solana_program::{entrypoint::ProgramResult, msg, program_error::ProgramError};
12
13use crate::error::AoError;
14pub use crate::state::orderbook::{OrderSummary, ORDER_SUMMARY_SIZE};
15pub use crate::utils::get_spread;
16
17use super::{AccountTag, Side};
18
19#[derive(Clone, Zeroable, Pod, Copy, Debug, PartialEq)]
20#[repr(C)]
21pub struct FillEvent {
23 pub tag: u8,
25 pub taker_side: u8,
27 pub(crate) _padding: [u8; 6],
28 pub quote_size: u64,
30 #[cfg(target_os = "solana")]
32 pub maker_order_id: u128,
33 #[cfg(not(target_os = "solana"))]
34 pub maker_order_id: [u64; 2],
36 pub base_size: u64,
38}
39
40impl FillEvent {
41 pub const LEN: usize = std::mem::size_of::<Self>();
43}
44
45#[derive(Clone, Zeroable, Pod, Copy, Debug, PartialEq)]
46#[repr(C)]
47pub struct OutEvent {
49 pub tag: u8,
51 pub side: u8,
53 pub(crate) _padding: [u8; 14],
54 #[cfg(target_os = "solana")]
56 pub order_id: u128,
57 #[cfg(not(target_os = "solana"))]
58 pub order_id: [u64; 2],
60 pub base_size: u64,
62}
63
64#[derive(PartialEq, Debug)]
65pub enum EventRef<'a, C> {
67 #[allow(missing_docs)]
68 Fill(FillEventRef<'a, C>),
69 #[allow(missing_docs)]
70 Out(OutEventRef<'a, C>),
71}
72
73#[derive(PartialEq, Debug)]
74pub struct FillEventRef<'a, C> {
76 #[allow(missing_docs)]
77 pub event: &'a FillEvent,
78 #[allow(missing_docs)]
79 pub maker_callback_info: &'a C,
80 #[allow(missing_docs)]
81 pub taker_callback_info: &'a C,
82}
83
84#[derive(PartialEq, Debug)]
85pub struct OutEventRef<'a, C> {
87 #[allow(missing_docs)]
88 pub event: &'a OutEvent,
89 #[allow(missing_docs)]
90 pub callback_info: &'a C,
91}
92
93#[derive(FromPrimitive, Clone, Copy, CheckedBitPattern, NoUninit)]
94#[repr(u8)]
95pub(crate) enum EventTag {
96 Fill,
97 Out,
98}
99
100pub(crate) type GenericEvent = FillEvent;
101
102pub(crate) trait Event {
103 fn to_generic(&mut self) -> &GenericEvent;
104}
105
106impl Event for FillEvent {
107 fn to_generic(&mut self) -> &GenericEvent {
108 self.tag = EventTag::Fill as u8;
109 self
110 }
111}
112
113impl Event for OutEvent {
114 fn to_generic(&mut self) -> &GenericEvent {
115 self.tag = EventTag::Out as u8;
116 bytemuck::cast_ref(self)
117 }
118}
119
120#[derive(BorshDeserialize, BorshSerialize, Clone, Copy, Pod, Zeroable)]
124#[repr(C)]
125pub struct EventQueueHeader {
127 pub head: u64,
129 pub count: u64,
131 seq_num: u64,
132}
133
134impl EventQueueHeader {
135 pub const LEN: usize = std::mem::size_of::<Self>();
137}
138
139pub struct EventQueue<'a, C> {
144 pub(crate) header: &'a mut EventQueueHeader,
145 pub(crate) events: &'a mut [FillEvent],
146 pub(crate) callback_infos: &'a mut [C],
147}
148
149impl<'queue, C: Pod> EventQueue<'queue, C> {
150 pub fn from_buffer(
152 buf: &'queue mut [u8],
153 expected_tag: AccountTag,
154 ) -> Result<Self, ProgramError> {
155 let callback_info_len = std::mem::size_of::<C>();
156
157 let capacity =
158 (buf.len() - 8 - EventQueueHeader::LEN) / (FillEvent::LEN + 2 * callback_info_len);
159 let account_tag: &mut u64 = bytemuck::from_bytes_mut(&mut buf[0..8]);
160
161 if *account_tag != expected_tag as u64 {
162 return Err(AoError::AccountTagMismatch.into());
163 }
164 *account_tag = AccountTag::EventQueue as u64;
165
166 let (header, remaining) = buf[8..].split_at_mut(EventQueueHeader::LEN);
167
168 let (events, callback_infos) = remaining.split_at_mut(capacity * FillEvent::LEN);
169 Ok(Self {
170 header: bytemuck::from_bytes_mut(header),
171 events: bytemuck::cast_slice_mut(events),
172 callback_infos: bytemuck::cast_slice_mut(callback_infos),
173 })
174 }
175}
176
177impl<'queue, C: Clone> EventQueue<'queue, C> {
178 pub(crate) fn push_back<Ev: Event>(
179 &mut self,
180 mut event: Ev,
181 maker_callback_info: Option<&C>,
182 taker_callback_info: Option<&C>,
183 ) -> Result<(), Ev> {
184 if self.full() {
185 return Err(event);
186 }
187 let generic_event = event.to_generic();
188 let event_idx =
189 (self.header.head as usize + self.header.count as usize) % self.events.len();
190 self.events[event_idx] = *generic_event;
191
192 self.header.count += 1;
193
194 if let Some(c) = maker_callback_info {
195 self.callback_infos[event_idx * 2] = c.clone();
196 }
197
198 if let Some(c) = taker_callback_info {
199 self.callback_infos[event_idx * 2 + 1] = c.clone();
200 }
201
202 Ok(())
203 }
204}
205
206impl<'queue, C> EventQueue<'queue, C> {
207 pub fn compute_allocation_size(desired_event_capacity: usize) -> usize {
209 desired_event_capacity * (FillEvent::LEN + 2 * std::mem::size_of::<C>())
210 + EventQueueHeader::LEN
211 + 8
212 }
213
214 pub(crate) fn check_buffer_size(buffer: &[u8]) -> ProgramResult {
215 const HEADER_OFFSET: usize = EventQueueHeader::LEN + 8;
216 let event_size: usize = FillEvent::LEN + 2 * std::mem::size_of::<C>();
217 let account_len = buffer.len();
218 if account_len < HEADER_OFFSET + 5 * event_size {
219 msg!("The event queue account is too small!");
220 return Err(ProgramError::InvalidAccountData);
221 }
222 if (account_len - HEADER_OFFSET) % event_size != 0 {
223 msg!("Event queue account size is invalid!");
224 return Err(ProgramError::InvalidAccountData);
225 }
226 Ok(())
227 }
228
229 pub(crate) fn gen_order_id(&mut self, limit_price: u64, side: Side) -> u128 {
230 let seq_num = self.gen_seq_num();
231 let upper = (limit_price as u128) << 64;
232 let lower = match side {
233 Side::Bid => !seq_num,
234 Side::Ask => seq_num,
235 };
236 upper | (lower as u128)
237 }
238
239 fn gen_seq_num(&mut self) -> u64 {
240 let seq_num = self.header.seq_num;
241 self.header.seq_num += 1;
242 seq_num
243 }
244
245 pub(crate) fn full(&self) -> bool {
246 self.header.count as usize == self.events.len()
247 }
248
249 pub fn peek_at(&self, index: u64) -> Option<EventRef<'_, C>> {
251 if self.header.count <= index {
252 return None;
253 }
254
255 let event_idx = (self.header.head.checked_add(index).unwrap() as usize) % self.events.len();
256 Some(self.get_event(event_idx))
257 }
258
259 fn get_event(&self, event_idx: usize) -> EventRef<'_, C> {
260 let event = &self.events[event_idx];
261 match EventTag::from_u8(event.tag).unwrap() {
262 EventTag::Fill => EventRef::Fill(FillEventRef {
263 event,
264 maker_callback_info: &self.callback_infos[2 * event_idx],
265 taker_callback_info: &self.callback_infos[2 * event_idx + 1],
266 }),
267 EventTag::Out => EventRef::Out(OutEventRef {
268 event: bytemuck::cast_ref(event),
269 callback_info: &self.callback_infos[2 * event_idx],
270 }),
271 }
272 }
273
274 pub fn pop_n(&mut self, number_of_entries_to_pop: u64) {
276 let capped_number_of_entries_to_pop =
277 std::cmp::min(self.header.count, number_of_entries_to_pop);
278 self.header.count -= capped_number_of_entries_to_pop;
279 self.header.head =
280 (self.header.head + capped_number_of_entries_to_pop) % (self.events.len() as u64);
281 }
282
283 pub fn iter(&self) -> QueueIterator<'_, C> {
285 QueueIterator {
286 queue: self,
287 current_index: 0,
288 remaining: self.header.count,
289 }
290 }
291
292 pub fn is_empty(&self) -> bool {
294 self.header.count == 0
295 }
296
297 pub fn len(&self) -> u64 {
299 self.header.count
300 }
301}
302
303pub struct QueueIterator<'a, C> {
305 queue: &'a EventQueue<'a, C>,
306 current_index: usize,
307 remaining: u64,
308}
309
310impl<'a, C> Iterator for QueueIterator<'a, C> {
311 type Item = EventRef<'a, C>;
312
313 fn next(&mut self) -> Option<Self::Item> {
314 if self.remaining == 0 {
315 return None;
316 }
317 let event_idx =
318 (self.queue.header.head as usize + self.current_index) % self.queue.events.len();
319 self.current_index += 1;
320 self.remaining -= 1;
321 Some(self.queue.get_event(event_idx))
322 }
323}
324
325#[cfg(test)]
326mod tests {
327 use super::*;
328
329 type EventQueueTest<'a> = EventQueue<'a, [u8; 32]>;
330
331 #[test]
332 fn test_event_queue_0() {
333 let allocation_size = EventQueue::<[u8; 32]>::compute_allocation_size(100);
334 let mut buffer = vec![0; allocation_size];
335
336 assert!(EventQueueTest::from_buffer(&mut buffer, AccountTag::EventQueue).is_err());
337
338 assert!(EventQueueTest::check_buffer_size(&[0; 10]).is_err());
339 assert!(EventQueueTest::check_buffer_size(&[0; 1000]).is_err());
340
341 let mut event_queue =
342 EventQueueTest::from_buffer(&mut buffer, AccountTag::Uninitialized).unwrap();
343
344 let mut seq_gen = 0..;
345 let mut parity_gen = 0..;
346
347 for _ in 0..100 {
348 if parity_gen.next().unwrap() % 7 != 3 {
349 #[allow(clippy::let_and_return)]
350 event_queue
351 .push_back(
352 FillEvent {
353 tag: EventTag::Fill as u8,
354 taker_side: Side::Ask as u8,
355 _padding: [0; 6],
356 quote_size: seq_gen.next().unwrap(),
357 maker_order_id: {
358 let s = seq_gen.next().unwrap() as u128;
359 #[cfg(not(target_os = "solana"))]
360 let s = [s as u64, 0];
361 s
362 },
363 base_size: seq_gen.next().unwrap(),
364 },
365 Some(&[seq_gen.next().unwrap() as u8; 32]),
366 Some(&[seq_gen.next().unwrap() as u8; 32]),
367 )
368 .unwrap();
369 } else {
370 #[allow(clippy::let_and_return)]
371 event_queue
372 .push_back(
373 OutEvent {
374 tag: EventTag::Out as u8,
375 side: Side::Ask as u8,
376 _padding: [0; 14],
377 base_size: seq_gen.next().unwrap(),
378 order_id: {
379 let s = seq_gen.next().unwrap() as u128;
380 #[cfg(not(target_os = "solana"))]
381 let s = [s as u64, 0];
382 s
383 },
384 },
385 Some(&[seq_gen.next().unwrap() as u8; 32]),
386 None,
387 )
388 .unwrap();
389 }
390 }
391 #[allow(clippy::let_and_return)]
392 let extra_event = FillEvent {
393 tag: EventTag::Fill as u8,
394 taker_side: Side::Ask as u8,
395 _padding: [0; 6],
396 quote_size: seq_gen.next().unwrap(),
397 maker_order_id: {
398 let s = seq_gen.next().unwrap() as u128;
399 #[cfg(not(target_os = "solana"))]
400 let s = [s as u64, 0];
401 s
402 },
403 base_size: seq_gen.next().unwrap(),
404 };
405 assert_eq!(
406 extra_event,
407 event_queue.push_back(extra_event, None, None).unwrap_err()
408 );
409 let mut number_of_events = 0;
410 let mut seq_gen = 0..;
411 let mut parity_gen = 0..;
412
413 assert!(event_queue.peek_at(100).is_none());
414
415 for (i, e) in event_queue.iter().enumerate() {
416 let is_fill = parity_gen.next().unwrap() % 7 != 3;
417 match e {
418 EventRef::Out(o) => {
419 assert!(!is_fill);
420 #[allow(clippy::let_and_return)]
421 {
422 assert_eq!(
423 o,
424 OutEventRef {
425 event: &OutEvent {
426 tag: EventTag::Out as u8,
427 side: Side::Ask as u8,
428 _padding: [0; 14],
429 base_size: seq_gen.next().unwrap(),
430 order_id: {
431 let s = seq_gen.next().unwrap() as u128;
432 #[cfg(not(target_os = "solana"))]
433 let s = [s as u64, 0];
434 s
435 },
436 },
437 callback_info: &[seq_gen.next().unwrap() as u8; 32]
438 }
439 );
440 }
441 }
442 EventRef::Fill(e) => {
443 assert!(is_fill);
444 #[allow(clippy::let_and_return)]
445 {
446 assert_eq!(
447 e,
448 FillEventRef {
449 event: &FillEvent {
450 tag: EventTag::Fill as u8,
451 taker_side: Side::Ask as u8,
452 _padding: [0; 6],
453 quote_size: seq_gen.next().unwrap(),
454 maker_order_id: {
455 let s = seq_gen.next().unwrap() as u128;
456 #[cfg(not(target_os = "solana"))]
457 let s = [s as u64, 0];
458 s
459 },
460 base_size: seq_gen.next().unwrap(),
461 },
462 maker_callback_info: &[seq_gen.next().unwrap() as u8; 32],
463 taker_callback_info: &[seq_gen.next().unwrap() as u8; 32]
464 }
465 );
466 }
467 assert_eq!(EventRef::Fill(e), event_queue.peek_at(i as u64).unwrap());
468 }
469 }
470 number_of_events = i + 1;
471 }
472 assert_eq!(number_of_events, 100);
473 }
474}