solana_accountsdb_plugin_postgres/
transaction_selector.rs1use {log::*, solana_sdk::pubkey::Pubkey, std::collections::HashSet};
4
5pub(crate) struct TransactionSelector {
6 pub mentioned_addresses: HashSet<Vec<u8>>,
7 pub select_all_transactions: bool,
8 pub select_all_vote_transactions: bool,
9}
10
11#[allow(dead_code)]
12impl TransactionSelector {
13 pub fn default() -> Self {
14 Self {
15 mentioned_addresses: HashSet::default(),
16 select_all_transactions: false,
17 select_all_vote_transactions: false,
18 }
19 }
20
21 pub fn new(mentioned_addresses: &[String]) -> Self {
26 info!(
27 "Creating TransactionSelector from addresses: {:?}",
28 mentioned_addresses
29 );
30
31 let select_all_transactions = mentioned_addresses
32 .iter()
33 .any(|key| key == "*" || key == "all");
34 if select_all_transactions {
35 return Self {
36 mentioned_addresses: HashSet::default(),
37 select_all_transactions,
38 select_all_vote_transactions: true,
39 };
40 }
41 let select_all_vote_transactions = mentioned_addresses.iter().any(|key| key == "all_votes");
42 if select_all_vote_transactions {
43 return Self {
44 mentioned_addresses: HashSet::default(),
45 select_all_transactions,
46 select_all_vote_transactions: true,
47 };
48 }
49
50 let mentioned_addresses = mentioned_addresses
51 .iter()
52 .map(|key| bs58::decode(key).into_vec().unwrap())
53 .collect();
54
55 Self {
56 mentioned_addresses,
57 select_all_transactions: false,
58 select_all_vote_transactions: false,
59 }
60 }
61
62 pub fn is_transaction_selected(
64 &self,
65 is_vote: bool,
66 mentioned_addresses: Box<dyn Iterator<Item = &Pubkey> + '_>,
67 ) -> bool {
68 if !self.is_enabled() {
69 return false;
70 }
71
72 if self.select_all_transactions || (self.select_all_vote_transactions && is_vote) {
73 return true;
74 }
75 for address in mentioned_addresses {
76 if self.mentioned_addresses.contains(address.as_ref()) {
77 return true;
78 }
79 }
80 false
81 }
82
83 pub fn is_enabled(&self) -> bool {
85 self.select_all_transactions
86 || self.select_all_vote_transactions
87 || !self.mentioned_addresses.is_empty()
88 }
89}
90
91#[cfg(test)]
92pub(crate) mod tests {
93 use super::*;
94
95 #[test]
96 fn test_select_transaction() {
97 let pubkey1 = Pubkey::new_unique();
98 let pubkey2 = Pubkey::new_unique();
99
100 let selector = TransactionSelector::new(&[pubkey1.to_string()]);
101
102 assert!(selector.is_enabled());
103
104 let addresses = [pubkey1];
105
106 assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
107
108 let addresses = [pubkey2];
109 assert!(!selector.is_transaction_selected(false, Box::new(addresses.iter())));
110
111 let addresses = [pubkey1, pubkey2];
112 assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
113 }
114
115 #[test]
116 fn test_select_all_transaction_using_wildcard() {
117 let pubkey1 = Pubkey::new_unique();
118 let pubkey2 = Pubkey::new_unique();
119
120 let selector = TransactionSelector::new(&["*".to_string()]);
121
122 assert!(selector.is_enabled());
123
124 let addresses = [pubkey1];
125
126 assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
127
128 let addresses = [pubkey2];
129 assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
130
131 let addresses = [pubkey1, pubkey2];
132 assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
133 }
134
135 #[test]
136 fn test_select_all_transaction_all() {
137 let pubkey1 = Pubkey::new_unique();
138 let pubkey2 = Pubkey::new_unique();
139
140 let selector = TransactionSelector::new(&["all".to_string()]);
141
142 assert!(selector.is_enabled());
143
144 let addresses = [pubkey1];
145
146 assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
147
148 let addresses = [pubkey2];
149 assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
150
151 let addresses = [pubkey1, pubkey2];
152 assert!(selector.is_transaction_selected(false, Box::new(addresses.iter())));
153 }
154
155 #[test]
156 fn test_select_all_vote_transaction() {
157 let pubkey1 = Pubkey::new_unique();
158 let pubkey2 = Pubkey::new_unique();
159
160 let selector = TransactionSelector::new(&["all_votes".to_string()]);
161
162 assert!(selector.is_enabled());
163
164 let addresses = [pubkey1];
165
166 assert!(!selector.is_transaction_selected(false, Box::new(addresses.iter())));
167
168 let addresses = [pubkey2];
169 assert!(selector.is_transaction_selected(true, Box::new(addresses.iter())));
170
171 let addresses = [pubkey1, pubkey2];
172 assert!(selector.is_transaction_selected(true, Box::new(addresses.iter())));
173 }
174
175 #[test]
176 fn test_select_no_transaction() {
177 let pubkey1 = Pubkey::new_unique();
178 let pubkey2 = Pubkey::new_unique();
179
180 let selector = TransactionSelector::new(&[]);
181
182 assert!(!selector.is_enabled());
183
184 let addresses = [pubkey1];
185
186 assert!(!selector.is_transaction_selected(false, Box::new(addresses.iter())));
187
188 let addresses = [pubkey2];
189 assert!(!selector.is_transaction_selected(true, Box::new(addresses.iter())));
190
191 let addresses = [pubkey1, pubkey2];
192 assert!(!selector.is_transaction_selected(true, Box::new(addresses.iter())));
193 }
194}