1use crate::{epoch::EpochNumber, log_entry::LogEntry};
24use cfx_types::{Address, Bloom, BloomInput, Space, H256};
25use cfxcore_errors::ProviderBlockError;
26use std::{
27 error, fmt,
28 ops::{Deref, DerefMut},
29};
30
31#[derive(Debug, PartialEq, Clone)]
32pub enum FilterError {
34 InvalidEpochNumber {
36 from_epoch: u64,
37 to_epoch: u64,
38 },
39
40 InvalidBlockNumber {
42 from_block: u64,
43 to_block: u64,
44 },
45
46 OutOfBoundEpochNumber {
47 to_epoch: u64,
48 max_epoch: u64,
49 },
50
51 EpochNumberGapTooLarge {
52 from_epoch: u64,
53 to_epoch: u64,
54 max_gap: u64,
55 },
56
57 BlockNumberGapTooLarge {
58 from_block: u64,
59 to_block: u64,
60 max_gap: u64,
61 },
62
63 UnableToVerify {
65 epoch: u64,
66 latest_verifiable: u64,
67 },
68
69 UnknownBlock {
71 hash: H256,
72 },
73
74 EpochAlreadyPruned {
76 epoch: u64,
77 min: u64,
78 },
79
80 BlockAlreadyPruned {
83 block_hash: H256,
84 },
85
86 BlockNotExecutedYet {
88 block_hash: H256,
89 },
90
91 PivotChainReorg {
93 epoch: u64,
94 from: H256,
95 to: H256,
96 },
97
98 Custom(String),
100}
101
102impl From<String> for FilterError {
103 fn from(s: String) -> Self { FilterError::Custom(s) }
104}
105
106impl From<&str> for FilterError {
107 fn from(s: &str) -> Self { FilterError::Custom(s.to_string()) }
108}
109
110impl From<ProviderBlockError> for FilterError {
111 fn from(err: ProviderBlockError) -> Self {
112 FilterError::from(err.to_string())
113 }
114}
115
116impl fmt::Display for FilterError {
117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118 use self::FilterError::*;
119 let msg = match *self {
120 InvalidEpochNumber {
121 from_epoch,
122 to_epoch,
123 } => format! {
124 "Filter has wrong epoch numbers set (from: {}, to: {})",
125 from_epoch, to_epoch
126 },
127 InvalidBlockNumber {
128 from_block,
129 to_block,
130 } => format! {
131 "Filter has wrong block numbers set (from: {}, to: {})",
132 from_block, to_block
133 },
134 OutOfBoundEpochNumber {
135 to_epoch,
136 max_epoch,
137 } => format! {
138 "Filter to_epoch is larger than the current best_epoch (to: {}, max: {})",
139 to_epoch, max_epoch,
140 },
141 EpochNumberGapTooLarge {
142 from_epoch,
143 to_epoch,
144 max_gap,
145 } => {
146 format! {
147 "The gap between from_epoch and to_epoch is larger than max_gap \
148 (from: {}, to: {}, max_gap: {})",
149 from_epoch, to_epoch, max_gap
150 }
151 }
152 BlockNumberGapTooLarge {
153 from_block,
154 to_block,
155 max_gap,
156 } => {
157 format! {
158 "The gap between from_block and to_block is larger than max_gap \
159 (from: {}, to: {}, max_gap: {})",
160 from_block, to_block, max_gap
161 }
162 }
163 UnableToVerify {
164 epoch,
165 latest_verifiable,
166 } => format! {
167 "Unable to verify epoch {} (latest verifiable epoch is {})",
168 epoch, latest_verifiable
169 },
170 UnknownBlock { hash } => format! {
171 "Unable to identify block {:?}", hash
172 },
173 EpochAlreadyPruned { epoch, min } => format! {
174 "Epoch is smaller than the earliest epoch stored (epoch: {}, min: {})",
175 epoch, min,
176 },
177 BlockAlreadyPruned { block_hash } => format! {
178 "Block {:?} has been pruned from db", block_hash,
179 },
180 BlockNotExecutedYet { block_hash } => format! {
181 "Block {:?} is not executed yet", block_hash,
182 },
183 PivotChainReorg { epoch, from, to } => format! {
184 "Pivot chain at epoch {} has been reorganized during log filtering: {:?} -> {:?}. Operation terminated to avoid inconsistent results.",
185 epoch, from, to,
186 },
187 Custom(ref s) => s.clone(),
188 };
189
190 f.write_fmt(format_args!("Filter error: {}", msg))
191 }
192}
193
194impl error::Error for FilterError {
195 fn description(&self) -> &str { "Filter error" }
196}
197
198#[derive(Clone, Debug, PartialEq, Eq, Hash)]
199pub enum LogFilter {
200 EpochLogFilter {
201 from_epoch: EpochNumber,
202 to_epoch: EpochNumber,
203 params: LogFilterParams,
204 },
205 BlockHashLogFilter {
206 block_hashes: Vec<H256>,
207 params: LogFilterParams,
208 },
209 BlockNumberLogFilter {
210 from_block: u64,
211 to_block: u64,
212 params: LogFilterParams,
213 },
214}
215
216#[derive(Clone, Debug, PartialEq, Eq, Hash)]
218pub struct LogFilterParams {
219 pub address: Option<Vec<Address>>,
224
225 pub topics: Vec<Option<Vec<H256>>>,
230
231 pub trusted: bool,
237
238 pub space: Space,
242}
243
244impl Default for LogFilterParams {
245 fn default() -> Self {
246 LogFilterParams {
247 address: None,
248 topics: vec![None, None, None, None],
249 trusted: false,
250 space: Space::Native,
251 }
252 }
253}
254
255impl Default for LogFilter {
256 fn default() -> Self {
257 LogFilter::EpochLogFilter {
258 from_epoch: EpochNumber::LatestCheckpoint,
259 to_epoch: EpochNumber::LatestState,
260 params: Default::default(),
261 }
262 }
263}
264
265impl Deref for LogFilter {
266 type Target = LogFilterParams;
267
268 fn deref(&self) -> &Self::Target {
269 match &self {
270 &LogFilter::EpochLogFilter { params, .. } => params,
271 &LogFilter::BlockHashLogFilter { params, .. } => params,
272 &LogFilter::BlockNumberLogFilter { params, .. } => params,
273 }
274 }
275}
276
277impl DerefMut for LogFilter {
278 fn deref_mut(&mut self) -> &mut Self::Target {
279 match self {
280 LogFilter::EpochLogFilter { params, .. } => params,
281 LogFilter::BlockHashLogFilter { params, .. } => params,
282 LogFilter::BlockNumberLogFilter { params, .. } => params,
283 }
284 }
285}
286
287impl LogFilterParams {
288 pub fn bloom_possibilities(&self) -> Vec<Bloom> {
290 let blooms = match self.address {
291 Some(ref addresses) if !addresses.is_empty() => addresses
292 .iter()
293 .map(|ref address| {
294 Bloom::from(BloomInput::Raw(address.as_bytes()))
295 })
296 .collect(),
297 _ => vec![Bloom::default()],
298 };
299
300 self.topics.iter().fold(blooms, |bs, topic| match *topic {
301 None => bs,
302 Some(ref topics) => bs
303 .into_iter()
304 .flat_map(|bloom| {
305 topics
306 .iter()
307 .map(|topic| {
308 let mut b = bloom.clone();
309 b.accrue(BloomInput::Raw(topic.as_bytes()));
310 b
311 })
312 .collect::<Vec<Bloom>>()
313 })
314 .collect(),
315 })
316 }
317
318 pub fn matches(&self, log: &LogEntry) -> bool {
320 if log.space != self.space {
321 return false;
322 }
323
324 let matches = match self.address {
325 Some(ref addresses) if !addresses.is_empty() => {
326 addresses.iter().any(|address| &log.address == address)
327 }
328 _ => true,
329 };
330
331 matches
332 && self
333 .topics
334 .iter()
335 .enumerate()
336 .all(|(i, topic)| match *topic {
337 Some(ref topics) if !topics.is_empty() => topics
338 .iter()
339 .any(|topic| log.topics.get(i) == Some(topic)),
340 _ => true,
341 })
342 }
343}