Skip to main content

yellowstone_vixen_proto/
lib.rs

1#![warn(missing_docs)]
2#![allow(clippy::module_name_repetitions)]
3
4//! Protobuf definitions used by the `yellowstone-vixen` family of crates.
5
6pub extern crate prost;
7#[cfg(feature = "stream")]
8pub extern crate prost_types;
9#[cfg(feature = "stream")]
10pub extern crate tonic;
11#[cfg(feature = "stream")]
12pub extern crate tonic_reflection;
13
14mod vixen {
15    #[cfg(feature = "parser")]
16    pub mod parser {
17        #![allow(missing_docs)]
18
19        pub mod token {
20            #![allow(clippy::all)]
21            include!(concat!(env!("OUT_DIR"), "/vixen.parser.token.rs"));
22
23            pub const DESCRIPTOR_SET: &[u8] =
24                include_bytes!(concat!(env!("OUT_DIR"), "/vixen.parser.token.bin"));
25
26            /// Raw `.proto` schema text for the token parser.
27            pub const PROTOBUF_SCHEMA: &str = include_str!("../proto/token.proto");
28
29            ///
30            /// IMPORTANT - If you update the .proto files, make sure to update the dispatch message indices below if needed
31            ///
32
33            /// 0-based index of the account dispatch message (`TokenProgramState`) in the proto file descriptor.
34            pub const ACCOUNT_DISPATCH_MESSAGE_INDEX: Option<usize> = Some(4);
35            /// 0-based index of the instruction dispatch message (`TokenProgram`) in the proto file descriptor.
36            pub const INSTRUCTION_DISPATCH_MESSAGE_INDEX: Option<usize> = Some(71);
37        }
38
39        pub mod bpf_loader {
40            #![allow(clippy::all)]
41            include!(concat!(env!("OUT_DIR"), "/vixen.parser.bpf_loader.rs"));
42
43            pub const DESCRIPTOR_SET: &[u8] =
44                include_bytes!(concat!(env!("OUT_DIR"), "/vixen.parser.bpf_loader.bin"));
45
46            /// Raw `.proto` schema text for the BPF loader parser.
47            pub const PROTOBUF_SCHEMA: &str = include_str!("../proto/bpf_loader.proto");
48
49            ///
50            /// IMPORTANT - If you update the .proto files, make sure to update the dispatch message indices below if needed
51            ///
52
53            /// 0-based index of the account dispatch message (`BpfLoaderState`) in the proto file descriptor.
54            pub const ACCOUNT_DISPATCH_MESSAGE_INDEX: Option<usize> = Some(4);
55            /// 0-based index of the instruction dispatch message (`BpfLoaderProgram`) in the proto file descriptor.
56            pub const INSTRUCTION_DISPATCH_MESSAGE_INDEX: Option<usize> = Some(24);
57        }
58
59        pub mod token_extensions {
60            #![allow(clippy::all)]
61            include!(concat!(
62                env!("OUT_DIR"),
63                "/vixen.parser.token_extensions.rs"
64            ));
65
66            pub const DESCRIPTOR_SET: &[u8] = include_bytes!(concat!(
67                env!("OUT_DIR"),
68                "/vixen.parser.token_extensions.bin"
69            ));
70
71            /// Self-contained `.proto` schema text for the token extensions
72            /// parser. Bundles the `token.proto` dependency inline so
73            /// consumers don't need to resolve the import separately.
74            pub const PROTOBUF_SCHEMA: &str = include_str!(concat!(
75                env!("OUT_DIR"),
76                "/token_extensions_full_schema.proto"
77            ));
78
79            ///
80            /// IMPORTANT - If you update the .proto files, make sure to update the dispatch message indices below if needed
81            ///
82
83            /// 0-based index of the account dispatch message (`TokenExtensionState`) in the proto file descriptor.
84            pub const ACCOUNT_DISPATCH_MESSAGE_INDEX: Option<usize> = Some(6);
85            /// 0-based index of the instruction dispatch message (`TokenExtensionProgram`) in the proto file descriptor.
86            pub const INSTRUCTION_DISPATCH_MESSAGE_INDEX: Option<usize> = Some(93);
87        }
88    }
89
90    #[cfg(feature = "stream")]
91    pub mod stream {
92        #![allow(missing_docs)]
93
94        //! Protobuf definitions for the `stream` feature of the
95        //! `yellowstone-vixen` crate.
96
97        tonic::include_proto!("vixen.stream");
98
99        /// Compiled protobuf file descriptor set for the `vixen.stream`
100        /// package.
101        pub const DESCRIPTOR_SET: &[u8] = tonic::include_file_descriptor_set!("stream_descriptor");
102    }
103}
104
105pub use vixen::*;
106
107///
108/// Non-regression tests to ensure that if token.proto or token_extensions.proto are updated, the dispatch message indices are also updated accordingly.
109/// It's not 100% foul proof, but the idea is for the tests to fail if someone adds a new top-level message in the proto file without updating the dispatch indices
110///
111#[cfg(all(test, feature = "parser"))]
112mod dispatch_index_tests {
113    /// Extract top-level message names from a `.proto` file (skips nested messages).
114    fn top_level_message_names(proto_text: &str) -> Vec<String> {
115        let mut names = Vec::new();
116        let mut depth: i32 = 0;
117
118        for line in proto_text.lines() {
119            let trimmed = line.trim();
120
121            if depth == 0 && trimmed.starts_with("message ") {
122                let name = trimmed
123                    .strip_prefix("message ")
124                    .unwrap()
125                    .split(|c: char| !c.is_alphanumeric() && c != '_')
126                    .next()
127                    .unwrap();
128                names.push(name.to_string());
129            }
130
131            depth += trimmed.chars().filter(|&c| c == '{').count() as i32;
132            depth -= trimmed.chars().filter(|&c| c == '}').count() as i32;
133        }
134
135        names
136    }
137
138    #[test]
139    fn token_dispatch_indices_match_proto() {
140        let proto = include_str!("../proto/token.proto");
141        let messages = top_level_message_names(proto);
142
143        let account_idx = crate::parser::token::ACCOUNT_DISPATCH_MESSAGE_INDEX
144            .expect("ACCOUNT_DISPATCH_MESSAGE_INDEX should be Some for token");
145        let instruction_idx = crate::parser::token::INSTRUCTION_DISPATCH_MESSAGE_INDEX
146            .expect("INSTRUCTION_DISPATCH_MESSAGE_INDEX should be Some for token");
147
148        assert_eq!(
149            messages[account_idx], "TokenProgramState",
150            "ACCOUNT_DISPATCH_MESSAGE_INDEX ({account_idx}) should point to TokenProgramState, \
151             found {}",
152            messages[account_idx],
153        );
154        assert_eq!(
155            messages[instruction_idx], "TokenProgram",
156            "INSTRUCTION_DISPATCH_MESSAGE_INDEX ({instruction_idx}) should point to TokenProgram, \
157             found {}",
158            messages[instruction_idx],
159        );
160    }
161
162    #[test]
163    fn bpf_loader_dispatch_indices_match_proto() {
164        let proto = include_str!("../proto/bpf_loader.proto");
165        let messages = top_level_message_names(proto);
166
167        let account_idx = crate::parser::bpf_loader::ACCOUNT_DISPATCH_MESSAGE_INDEX
168            .expect("ACCOUNT_DISPATCH_MESSAGE_INDEX should be Some for bpf_loader");
169        let instruction_idx = crate::parser::bpf_loader::INSTRUCTION_DISPATCH_MESSAGE_INDEX
170            .expect("INSTRUCTION_DISPATCH_MESSAGE_INDEX should be Some for bpf_loader");
171
172        assert_eq!(
173            messages[account_idx], "BpfLoaderState",
174            "ACCOUNT_DISPATCH_MESSAGE_INDEX ({account_idx}) should point to BpfLoaderState, found \
175             {}",
176            messages[account_idx],
177        );
178        assert_eq!(
179            messages[instruction_idx], "BpfLoaderProgram",
180            "INSTRUCTION_DISPATCH_MESSAGE_INDEX ({instruction_idx}) should point to \
181             BpfLoaderProgram, found {}",
182            messages[instruction_idx],
183        );
184    }
185
186    #[test]
187    fn token_extensions_dispatch_indices_match_proto() {
188        let proto = include_str!("../proto/token_extensions.proto");
189        let messages = top_level_message_names(proto);
190
191        let account_idx = crate::parser::token_extensions::ACCOUNT_DISPATCH_MESSAGE_INDEX
192            .expect("ACCOUNT_DISPATCH_MESSAGE_INDEX should be Some for token_extensions");
193        let instruction_idx = crate::parser::token_extensions::INSTRUCTION_DISPATCH_MESSAGE_INDEX
194            .expect("INSTRUCTION_DISPATCH_MESSAGE_INDEX should be Some for token_extensions");
195
196        assert_eq!(
197            messages[account_idx], "TokenExtensionState",
198            "ACCOUNT_DISPATCH_MESSAGE_INDEX ({account_idx}) should point to TokenExtensionState, \
199             found {}",
200            messages[account_idx],
201        );
202        assert_eq!(
203            messages[instruction_idx], "TokenExtensionProgram",
204            "INSTRUCTION_DISPATCH_MESSAGE_INDEX ({instruction_idx}) should point to \
205             TokenExtensionProgram, found {}",
206            messages[instruction_idx],
207        );
208    }
209}