Skip to content

Commit d59e715

Browse files
committed
ethereum: Batch eth_getLogs over 1000 contracts
1 parent 4175720 commit d59e715

File tree

1 file changed

+45
-19
lines changed

1 file changed

+45
-19
lines changed

chain/ethereum/src/adapter.rs

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ use crate::{data_source::DataSource, Chain};
2626
pub type EventSignature = H256;
2727
pub type FunctionSelector = [u8; 4];
2828

29+
const ETH_GET_LOGS_MAX_CONTRACTS: usize = 1000;
30+
2931
#[derive(Clone, Debug)]
3032
pub struct EthereumContractCall {
3133
pub address: Address,
@@ -70,6 +72,22 @@ pub struct EthGetLogsFilter {
7072
pub event_signatures: Vec<EventSignature>,
7173
}
7274

75+
impl EthGetLogsFilter {
76+
fn from_contract(address: Address) -> Self {
77+
EthGetLogsFilter {
78+
contracts: vec![address],
79+
event_signatures: vec![],
80+
}
81+
}
82+
83+
fn from_event(event: EventSignature) -> Self {
84+
EthGetLogsFilter {
85+
contracts: vec![],
86+
event_signatures: vec![event],
87+
}
88+
}
89+
}
90+
7391
impl fmt::Display for EthGetLogsFilter {
7492
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7593
if self.contracts.len() == 1 {
@@ -209,10 +227,7 @@ impl EthereumLogFilter {
209227

210228
// First add the wildcard event filters.
211229
for wildcard_event in self.wildcard_events {
212-
filters.push(EthGetLogsFilter {
213-
contracts: vec![],
214-
event_signatures: vec![wildcard_event],
215-
})
230+
filters.push(EthGetLogsFilter::from_event(wildcard_event))
216231
}
217232

218233
// The current algorithm is to repeatedly find the maximum cardinality vertex and turn all
@@ -230,31 +245,37 @@ impl EthereumLogFilter {
230245
// might cause the filter to become too broad, so at the moment it seems excessive.
231246
let mut g = self.contracts_and_events_graph;
232247
while g.edge_count() > 0 {
248+
let mut push_filter = |filter: EthGetLogsFilter| {
249+
// Sanity checks:
250+
// - The filter is not a wildcard because all nodes have neighbors.
251+
// - The graph is bipartite.
252+
assert!(filter.contracts.len() > 0 && filter.event_signatures.len() > 0);
253+
assert!(filter.contracts.len() == 1 || filter.event_signatures.len() == 1);
254+
filters.push(filter);
255+
};
256+
233257
// If there are edges, there are vertexes.
234258
let max_vertex = g.nodes().max_by_key(|&n| g.neighbors(n).count()).unwrap();
235259
let mut filter = match max_vertex {
236-
LogFilterNode::Contract(address) => EthGetLogsFilter {
237-
contracts: vec![address],
238-
event_signatures: vec![],
239-
},
240-
LogFilterNode::Event(event_sig) => EthGetLogsFilter {
241-
contracts: vec![],
242-
event_signatures: vec![event_sig],
243-
},
260+
LogFilterNode::Contract(address) => EthGetLogsFilter::from_contract(address),
261+
LogFilterNode::Event(event_sig) => EthGetLogsFilter::from_event(event_sig),
244262
};
245263
for neighbor in g.neighbors(max_vertex) {
246264
match neighbor {
247-
LogFilterNode::Contract(address) => filter.contracts.push(address),
265+
LogFilterNode::Contract(address) => {
266+
if filter.contracts.len() == ETH_GET_LOGS_MAX_CONTRACTS {
267+
// The batch size was reached, register the filter and start a new one.
268+
let event = filter.event_signatures[0];
269+
push_filter(filter);
270+
filter = EthGetLogsFilter::from_event(event);
271+
}
272+
filter.contracts.push(address);
273+
}
248274
LogFilterNode::Event(event_sig) => filter.event_signatures.push(event_sig),
249275
}
250276
}
251277

252-
// Sanity checks:
253-
// - The filter is not a wildcard because all nodes have neighbors.
254-
// - The graph is bipartite.
255-
assert!(filter.contracts.len() > 0 && filter.event_signatures.len() > 0);
256-
assert!(filter.contracts.len() == 1 || filter.event_signatures.len() == 1);
257-
filters.push(filter);
278+
push_filter(filter);
258279
g.remove_node(max_vertex);
259280
}
260281
filters.into_iter()
@@ -794,6 +815,11 @@ fn complete_log_filter() {
794815
.collect::<BTreeSet<_>>(),
795816
events
796817
);
818+
819+
// Assert that chunking works.
820+
for filter in logs_filters {
821+
assert!(filter.contracts.len() <= 1000);
822+
}
797823
}
798824
}
799825
}

0 commit comments

Comments
 (0)