substreams_antelope_core/
block.rs1use crate::block::pb::TransactionStatus::TransactionstatusExecuted;
2use crate::pb;
3
4impl pb::Block {
5 pub fn transaction_traces(&self) -> impl Iterator<Item = &pb::TransactionTrace> {
14 let traces = if self.filtering_applied {
15 self.filtered_transaction_traces.iter()
16 } else {
17 self.unfiltered_transaction_traces.iter()
18 };
19
20 traces.filter(|trx| trx.receipt.is_some() && trx.receipt.as_ref().unwrap().status == TransactionstatusExecuted as i32)
21 }
22
23 pub fn into_transaction_traces(self) -> impl Iterator<Item = pb::TransactionTrace> {
32 let traces = if self.filtering_applied {
33 self.filtered_transaction_traces.into_iter()
34 } else {
35 self.unfiltered_transaction_traces.into_iter()
36 };
37
38 traces.filter(|trx| trx.receipt.is_some() && trx.receipt.as_ref().unwrap().status == TransactionstatusExecuted as i32)
39 }
40
41 pub fn action_traces(&self) -> impl Iterator<Item = (&pb::ActionTrace, &pb::TransactionTrace)> {
50 self.transaction_traces()
51 .flat_map(|trx| trx.action_traces.iter().map(move |trace| (trace, trx)))
52 }
53
54 pub fn into_action_traces(self) -> impl Iterator<Item = pb::ActionTrace> {
63 self.into_transaction_traces().flat_map(|trx| trx.action_traces)
64 }
65
66 pub fn all_actions<'a, A: crate::action::Action>(
75 &'a self,
76 accounts: &'a [&str],
77 ) -> impl Iterator<Item = (A, &pb::ActionTrace, &pb::TransactionTrace)> + 'a {
78 self.action_traces().filter_map(|(trace, trx)| {
79 let contract = trace.action.as_ref().unwrap().account.as_str();
80 if !accounts.is_empty() && !accounts.contains(&contract) {
81 return None;
82 }
83
84 A::match_and_decode(trace).map(|action| (action, trace, trx))
85 })
86 }
87
88 pub fn actions<'a, A: crate::action::Action>(
98 &'a self,
99 accounts: &'a [&str],
100 ) -> impl Iterator<Item = (A, &pb::ActionTrace, &pb::TransactionTrace)> + 'a {
101 self.all_actions(accounts)
102 .filter(|(_, trace, _)| trace.receiver.as_str() == trace.action.as_ref().unwrap().account.as_str())
103 }
104
105 pub fn notifications<'a, A: crate::action::Action>(
115 &'a self,
116 accounts: &'a [&str],
117 ) -> impl Iterator<Item = (A, &pb::ActionTrace, &pb::TransactionTrace)> + 'a {
118 self.all_actions(accounts)
119 .filter(|(_, trace, _)| trace.receiver.as_str() != trace.action.as_ref().unwrap().account.as_str())
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use crate::block::pb::TransactionStatus::{TransactionstatusExecuted, TransactionstatusSoftfail};
127
128 fn create_test_block(
130 filtering_applied: bool,
131 unfiltered_transaction_traces: Vec<pb::TransactionTrace>,
132 filtered_transaction_traces: Vec<pb::TransactionTrace>,
133 unfiltered_transaction_count: u32,
134 filtered_transaction_count: u32,
135 unfiltered_executed_input_action_count: u32,
136 filtered_executed_input_action_count: u32,
137 unfiltered_executed_total_action_count: u32,
138 filtered_executed_total_action_count: u32,
139 ) -> pb::Block {
140 pb::Block {
141 filtering_applied,
142 unfiltered_transaction_traces,
143 filtered_transaction_traces,
144 unfiltered_transaction_count,
145 filtered_transaction_count,
146 unfiltered_executed_input_action_count,
147 filtered_executed_input_action_count,
148 unfiltered_executed_total_action_count,
149 filtered_executed_total_action_count,
150 ..Default::default()
151 }
152 }
153
154 #[test]
155 fn test_all_transaction_traces() {
156 let unfiltered_traces = vec![
157 pb::TransactionTrace {
158 id: String::from("trx1"),
159 receipt: Some(pb::TransactionReceiptHeader {
160 status: TransactionstatusExecuted as i32,
161 ..Default::default()
162 }),
163 ..Default::default()
164 },
165 pb::TransactionTrace {
166 id: String::from("trx2"),
167 receipt: Some(pb::TransactionReceiptHeader {
168 status: TransactionstatusExecuted as i32,
169 ..Default::default()
170 }),
171 ..Default::default()
172 },
173 ];
174 let block = create_test_block(false, unfiltered_traces.clone(), vec![], 2, 0, 5, 0, 7, 0);
175
176 let all_traces: Vec<_> = block.into_transaction_traces().collect();
177 assert_eq!(all_traces, unfiltered_traces);
178 }
179
180 #[test]
181 fn test_all_action_traces() {
182 let unfiltered_traces = vec![
183 pb::TransactionTrace {
184 id: String::from("trx1"),
185 receipt: Some(pb::TransactionReceiptHeader {
186 status: TransactionstatusExecuted as i32,
187 ..Default::default()
188 }),
189 action_traces: vec![pb::ActionTrace { ..Default::default() }],
190 ..Default::default()
191 },
192 pb::TransactionTrace {
193 id: String::from("trx2"),
194 receipt: Some(pb::TransactionReceiptHeader {
195 status: TransactionstatusExecuted as i32,
196 ..Default::default()
197 }),
198 action_traces: vec![pb::ActionTrace { ..Default::default() }, pb::ActionTrace { ..Default::default() }],
199 ..Default::default()
200 },
201 ];
202 let block = create_test_block(false, unfiltered_traces.clone(), vec![], 2, 0, 5, 0, 7, 0);
203
204 let all_traces: Vec<_> = block.action_traces().collect();
205 assert_eq!(all_traces.len(), 3);
206 }
207
208 #[test]
209 fn test_executed_transaction_traces() {
210 let executed_traces = vec![
211 pb::TransactionTrace {
212 id: String::from("trx1"),
213 receipt: Some(pb::TransactionReceiptHeader {
214 status: TransactionstatusExecuted as i32,
215 ..Default::default()
216 }),
217 ..Default::default()
218 },
219 pb::TransactionTrace {
220 id: String::from("trx2"),
221 receipt: Some(pb::TransactionReceiptHeader {
222 status: TransactionstatusExecuted as i32,
223 ..Default::default()
224 }),
225 ..Default::default()
226 },
227 ];
228 let block = create_test_block(false, executed_traces.clone(), vec![], 2, 0, 5, 0, 7, 0);
229
230 let produced_traces: Vec<_> = block.transaction_traces().cloned().collect();
231 assert_eq!(executed_traces, produced_traces);
232 }
233
234 #[test]
235 fn test_executed_transaction_traces_no_receipt() {
236 let executed_traces = vec![
237 pb::TransactionTrace {
238 id: String::from("trx1"),
239 receipt: Some(pb::TransactionReceiptHeader {
240 status: TransactionstatusExecuted as i32,
241 ..Default::default()
242 }),
243 ..Default::default()
244 },
245 pb::TransactionTrace {
246 id: String::from("trx2"),
247 receipt: Some(pb::TransactionReceiptHeader {
248 status: TransactionstatusSoftfail as i32,
249 ..Default::default()
250 }),
251 ..Default::default()
252 },
253 pb::TransactionTrace {
254 id: String::from("trx3"),
255 receipt: None,
256 ..Default::default()
257 },
258 ];
259 let block = create_test_block(false, executed_traces.clone(), vec![], 2, 0, 5, 0, 7, 0);
260
261 let produced_traces: Vec<_> = block.transaction_traces().cloned().collect();
262 assert_eq!(executed_traces[0], produced_traces[0]);
263 assert_eq!(produced_traces.len(), 1);
264 }
265}