Skip to main content

catscope_edge_generator/
lib.rs

1use std::collections::VecDeque;
2
3use primitive::{
4    filter::{ptr_to_filter, CatscopeFilter, GuestFilter},
5    soltoken::SolToken,
6    tree::{parse_program_list, ProgramList},
7    wasmimport::HostImport,
8    wasmstore::{AccountOnGuest, FilterEdgeWithNextPointer},
9};
10use safejar::Safejar;
11use solpipe::Solpipe;
12
13//pub mod all;
14pub mod primitive;
15pub mod safejar;
16pub mod solpipe;
17
18/// A place holder for starting the web assembly.
19/// # Safety
20#[no_mangle] // Prevent Rust from changing the function name
21pub extern "C" fn _start() -> i32 {
22    0
23}
24
25/// The code below defines a basic filter (edge generator) for
26/// system, token, Safejar, and Solpipe accounts.
27/// # Safety
28#[no_mangle] // Prevent Rust from changing the function name
29pub unsafe extern "C" fn init() -> u64 {
30    let mut hi = HostImport::default();
31
32    let mut list: VecDeque<Box<dyn GuestFilter + 'static>> = VecDeque::new();
33    list.push_back(Box::new(SolToken::default()));
34
35    let args = match hi.init_args() {
36        Ok(x) => match x {
37            Some(y) => y,
38            None => return 0,
39        },
40        Err(_) => return 0,
41    };
42    let program_list = match parse_program_list(args.slice()) {
43        Ok(x) => x,
44        Err(_) => return 0,
45    };
46    for (i, program_id) in program_list.iter().enumerate() {
47        match i {
48            0 => {
49                list.push_back(Box::new(Safejar::new(program_id)));
50            }
51            1 => {
52                list.push_back(Box::new(Solpipe::new(program_id)));
53            }
54            _ => {}
55        }
56    }
57
58    let filter = Box::new(CatscopeFilter::new(list, hi));
59    Box::into_raw(filter) as u64
60}
61
62/// Deallocate a blob.
63/// # Returns
64/// Returns the memory offset to this byte slice.
65/// # Safety
66#[no_mangle] // Prevent Rust from changing the function name
67pub unsafe extern "C" fn allocate(cat_ptr: u64, data_size: u32) -> u64 {
68    let filter: &mut CatscopeFilter = ptr_to_filter(cat_ptr).unwrap();
69    let r = filter.store_mut().allocate(data_size as usize).unwrap();
70    r.pointer()
71}
72
73/// Deallocate a blob.
74/// # Safety
75#[no_mangle]
76pub unsafe extern "C" fn deallocate(cat_ptr: u64, ptr: u64) -> u64 {
77    let filter: &mut CatscopeFilter = ptr_to_filter(cat_ptr).unwrap();
78    filter.store_mut().deallocate(ptr);
79    0
80}
81
82/// Close the filtering object.
83/// # Safety
84#[no_mangle] // Prevent Rust from changing the function name
85pub unsafe extern "C" fn close(cat_ptr: u64) -> u64 {
86    unsafe {
87        // Reconstruct the Box<T> from the raw pointer and immediately drop it
88        drop(Box::from_raw(cat_ptr as *mut CatscopeFilter));
89    }
90    0
91}
92
93/// A holder for responses.
94/// # Safety
95#[no_mangle] // Prevent Rust from changing the function name
96pub unsafe extern "C" fn response(
97    _x1: i64,
98    _x2: i64,
99    _x3: i32,
100    _x4: i64,
101    _x5: i64,
102    _x6: i64,
103    _x7: i64,
104    _x8: i64,
105    _x9: i64,
106    _x10: i64,
107    _x11: i64,
108    _x12: i64,
109    _x13: i64,
110) -> i64 {
111    0
112}
113
114/// List programs that need to be tracked.
115/// # Safety
116///
117#[no_mangle]
118pub unsafe extern "C" fn program_list(cat_ptr: u64) -> u64 {
119    let filter: &mut CatscopeFilter = ptr_to_filter(cat_ptr).unwrap();
120    let list = filter.program_id_list();
121    let store = filter.store_mut();
122    let mut out = store.allocate_struct::<ProgramList>().unwrap();
123    {
124        let p = out.payload_mut::<ProgramList>();
125        for (i, pk) in list.iter().enumerate() {
126            p.list[i] = *pk;
127        }
128        p.count = list.len() as u16;
129    }
130    out.pointer()
131}
132
133/// Produce edges from reading an account.
134/// # Safety
135///
136#[no_mangle] // Prevent Rust from changing the function name
137pub unsafe extern "C" fn edge(cat_ptr: u64, ptr: u64, size: u32) -> u64 {
138    let filter: &mut CatscopeFilter = ptr_to_filter(cat_ptr).unwrap();
139    let blob;
140    {
141        let store = filter.store();
142        blob = store.recover_blob(ptr as usize, size as usize).unwrap();
143    }
144
145    let a: AccountOnGuest = match blob.try_into() {
146        Ok(x) => x,
147        Err(_) => return 0,
148    };
149    let h = a.header();
150    /*    HostImport::log(format!(
151        "edge - 1 - header {} {} {}",
152        h.pubkey, h.owner, h.lamports
153    ));*/
154    let data = a.data();
155    let mut list = filter.edge(h, data);
156    if list.is_empty() {
157        return 0;
158    }
159    let mut last_ptr = 0;
160    while let Some(edge) = list.pop_back() {
161        let store = filter.store_mut();
162        let mut out = store
163            .allocate_struct::<FilterEdgeWithNextPointer>()
164            .unwrap();
165        let h = out.payload_mut::<FilterEdgeWithNextPointer>();
166        h.edge = edge;
167        h.next_pointer = last_ptr;
168        last_ptr = out.pointer();
169    }
170    last_ptr
171}