Skip to content

Commit ba5b565

Browse files
authored
fix(l1): make from and to optional in eth_getLogs (#5361)
**Motivation** We had a difference with the spec in `eth_getLogs`. **Description** This PR makes `fromBlock`, `toBlock`, and `address` params optional. Closes #5360
1 parent 2e98c07 commit ba5b565

File tree

1 file changed

+76
-9
lines changed

1 file changed

+76
-9
lines changed

crates/networking/rpc/eth/logs.rs

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,35 @@
44
// - Ethereum's reference: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newfilter
55
use crate::{
66
rpc::{RpcApiContext, RpcHandler},
7-
types::{block_identifier::BlockIdentifier, receipt::RpcLog},
7+
types::{
8+
block_identifier::{BlockIdentifier, BlockTag},
9+
receipt::RpcLog,
10+
},
811
utils::RpcErr,
912
};
1013
use ethrex_common::{H160, H256};
1114
use ethrex_storage::Store;
1215
use serde::Deserialize;
1316
use serde_json::Value;
1417
use std::collections::HashSet;
18+
1519
#[derive(Deserialize, Debug, Clone)]
1620
#[serde(untagged)]
1721
pub enum AddressFilter {
1822
Single(H160),
1923
Many(Vec<H160>),
2024
}
2125

22-
#[derive(Deserialize, Debug, Clone)]
26+
impl AsRef<[H160]> for AddressFilter {
27+
fn as_ref(&self) -> &[H160] {
28+
match self {
29+
AddressFilter::Single(address) => std::slice::from_ref(address),
30+
AddressFilter::Many(addresses) => addresses.as_ref(),
31+
}
32+
}
33+
}
34+
35+
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
2336
#[serde(untagged)]
2437
pub enum TopicFilter {
2538
Topic(Option<H256>),
@@ -49,21 +62,24 @@ impl RpcHandler for LogsFilter {
4962
.ok_or(RpcErr::BadParams("Param is not a object".to_owned()))?;
5063
let from_block = param
5164
.get("fromBlock")
52-
.ok_or_else(|| RpcErr::MissingParam("fromBlock".to_string()))
53-
.and_then(|block_number| BlockIdentifier::parse(block_number.clone(), 0))?;
65+
.map(|block_number| BlockIdentifier::parse(block_number.clone(), 0))
66+
.transpose()?
67+
.unwrap_or(BlockIdentifier::Tag(BlockTag::Latest));
5468
let to_block = param
5569
.get("toBlock")
56-
.ok_or_else(|| RpcErr::MissingParam("toBlock".to_string()))
57-
.and_then(|block_number| BlockIdentifier::parse(block_number.clone(), 0))?;
70+
.map(|block_number| BlockIdentifier::parse(block_number.clone(), 0))
71+
.transpose()?
72+
.unwrap_or(BlockIdentifier::Tag(BlockTag::Latest));
5873
let address_filters = param
5974
.get("address")
60-
.ok_or_else(|| RpcErr::MissingParam("address".to_string()))
61-
.and_then(|address| {
75+
.map(|address| {
6276
match serde_json::from_value::<Option<AddressFilter>>(address.clone()) {
6377
Ok(filters) => Ok(filters),
6478
_ => Err(RpcErr::WrongParam("address".to_string())),
6579
}
66-
})?;
80+
})
81+
.transpose()?
82+
.flatten();
6783
let topics_filters = param
6884
.get("topics")
6985
.ok_or_else(|| RpcErr::MissingParam("topics".to_string()))
@@ -214,3 +230,54 @@ pub(crate) async fn fetch_logs_with_filter(
214230

215231
Ok(filtered_logs)
216232
}
233+
234+
#[cfg(test)]
235+
mod tests {
236+
use super::*;
237+
use serde_json::json;
238+
239+
#[test]
240+
fn test_get_logs_with_defaults() {
241+
let params = Some(vec![
242+
json!({"topics": ["0x0000000000000000000000000000000000000000000000000000000000000000"]}),
243+
]);
244+
let request = LogsFilter::parse(&params).unwrap();
245+
246+
assert!(request.address_filters.is_none(), "{request:?}");
247+
assert!(
248+
matches!(request.from_block, BlockIdentifier::Tag(BlockTag::Latest)),
249+
"{request:?}"
250+
);
251+
assert!(
252+
matches!(request.to_block, BlockIdentifier::Tag(BlockTag::Latest)),
253+
"{request:?}"
254+
);
255+
assert_eq!(request.topics, vec![TopicFilter::Topic(Some(H256::zero()))]);
256+
}
257+
258+
#[test]
259+
fn test_get_logs_multiple_addresses() {
260+
let params = Some(vec![json!({
261+
"address": [
262+
"0x0000000000000000000000000000000000000001",
263+
"0x0000000000000000000000000000000000000002"
264+
],
265+
"topics": ["0x0000000000000000000000000000000000000000000000000000000000000000"]
266+
})]);
267+
let request = LogsFilter::parse(&params).unwrap();
268+
269+
assert_eq!(
270+
request.address_filters.as_ref().unwrap().as_ref(),
271+
[H160::from_low_u64_be(1), H160::from_low_u64_be(2)],
272+
);
273+
assert!(
274+
matches!(request.from_block, BlockIdentifier::Tag(BlockTag::Latest)),
275+
"{request:?}"
276+
);
277+
assert!(
278+
matches!(request.to_block, BlockIdentifier::Tag(BlockTag::Latest)),
279+
"{request:?}"
280+
);
281+
assert_eq!(request.topics, vec![TopicFilter::Topic(Some(H256::zero()))]);
282+
}
283+
}

0 commit comments

Comments
 (0)