Skip to content

Commit bd0d657

Browse files
authored
chore: Reduce RPC calls for EVM by using eth_getLogs (#221)
* test: Add tests * docs: Update documentation * docs: Update docs * docs: Update docs * chore: Use transaction's transaction_index * chore: Remove unused From implementation
1 parent 1b4d5d8 commit bd0d657

File tree

22 files changed

+733
-350
lines changed

22 files changed

+733
-350
lines changed

docs/modules/ROOT/pages/rpc.adoc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,8 @@ graph TD
250250
B[Network Init] -->|net_version| D
251251
D -->|eth_blockNumber| E[For every block in range]
252252
E -->|eth_getBlockByNumber| G1[Process Block]
253-
G1 -->|For every transaction| J[Get Transaction Receipt]
253+
G1 -->|eth_getLogs| H[Get Block Logs]
254+
H -->|Only when needed| J[Get Transaction Receipt]
254255
J -->|eth_getTransactionReceipt| I[Complete]
255256
end
256257
@@ -275,7 +276,10 @@ graph TD
275276
* RPC Client initialization (per active network): `net_version`
276277
* Fetching the latest block number (per cron iteration): `eth_blockNumber`
277278
* Fetching block data (per block): `eth_getBlockByNumber`
278-
* Fetching transaction receipt (per transaction in block): `eth_getTransactionReceipt`
279+
* Fetching block logs (per block): `eth_getLogs`
280+
* Fetching transaction receipt (only when needed):
281+
** When monitor condition requires receipt-specific fields (e.g., `gas_used`)
282+
** When monitoring transaction status and no logs are present to validate status
279283

280284
*Stellar*
281285

docs/modules/ROOT/pages/scripts.adoc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,23 @@ Custom filter scripts allow you to apply additional conditions to matches detect
120120
"transactionIndex": "0x1fc",
121121
"type": "0x2"
122122
},
123+
"logs": [
124+
{
125+
"address": "0xd1f2586790a5bd6da1e443441df53af6ec213d83",
126+
"topics": [
127+
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
128+
"0x00000000000000000000000060af8cf92e5aa9ead4a592d657cd6debecfbc616",
129+
"0x000000000000000000000000d1f2586790a5bd6da1e443441df53af6ec213d83"
130+
],
131+
"data": "0x00000000000000000000000000000000000000000000106015728793d21f77ac",
132+
"blockNumber": "0x1451aca",
133+
"transactionHash": "0xa39d1b9b3edda74414bd6ffaf6596f8ea12cf0012fd9a930f71ed69df6ff34d0",
134+
"transactionIndex": "0x0",
135+
"blockHash": "0x9432868b7fc57e85f0435ca3047f6a76add86f804b3c1af85647520061e30f80",
136+
"logIndex": "0x2",
137+
"removed": false
138+
},
139+
],
123140
"transaction": {
124141
"accessList": [],
125142
"blockHash": "0x...",

src/bootstrap/mod.rs

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -521,16 +521,14 @@ mod tests {
521521
use super::*;
522522
use crate::{
523523
models::{
524-
EVMMonitorMatch, EVMTransaction, EVMTransactionReceipt, MatchConditions, Monitor,
525-
MonitorMatch, ScriptLanguage, StellarBlock, StellarMonitorMatch, StellarTransaction,
526-
StellarTransactionInfo, TriggerConditions,
524+
EVMMonitorMatch, EVMReceiptLog, EVMTransaction, EVMTransactionReceipt, MatchConditions,
525+
Monitor, MonitorMatch, ScriptLanguage, StellarBlock, StellarMonitorMatch,
526+
StellarTransaction, StellarTransactionInfo, TriggerConditions,
527527
},
528-
utils::tests::builders::evm::monitor::MonitorBuilder,
528+
utils::tests::{builders::evm::monitor::MonitorBuilder, evm::receipt::ReceiptBuilder},
529529
};
530530
use alloy::{
531-
consensus::{
532-
transaction::Recovered, Receipt, ReceiptEnvelope, ReceiptWithBloom, Signed, TxEnvelope,
533-
},
531+
consensus::{transaction::Recovered, Signed, TxEnvelope},
534532
primitives::{Address, Bytes, TxKind, B256, U256},
535533
};
536534
use std::io::Write;
@@ -561,23 +559,11 @@ mod tests {
561559
}
562560

563561
fn create_test_evm_transaction_receipt() -> EVMTransactionReceipt {
564-
EVMTransactionReceipt::from(alloy::rpc::types::TransactionReceipt {
565-
inner: ReceiptEnvelope::Legacy(ReceiptWithBloom {
566-
receipt: Receipt::default(),
567-
logs_bloom: Default::default(),
568-
}),
569-
transaction_hash: B256::ZERO,
570-
transaction_index: Some(0),
571-
block_hash: Some(B256::ZERO),
572-
block_number: Some(0),
573-
gas_used: 0,
574-
effective_gas_price: 0,
575-
blob_gas_used: None,
576-
blob_gas_price: None,
577-
from: Address::ZERO,
578-
to: Some(Address::ZERO),
579-
contract_address: None,
580-
})
562+
ReceiptBuilder::new().build()
563+
}
564+
565+
fn create_test_evm_logs() -> Vec<EVMReceiptLog> {
566+
ReceiptBuilder::new().build().logs.clone()
581567
}
582568

583569
fn create_test_evm_transaction() -> EVMTransaction {
@@ -628,7 +614,8 @@ mod tests {
628614
BlockChainType::EVM => MonitorMatch::EVM(Box::new(EVMMonitorMatch {
629615
monitor: create_test_monitor("test", vec![], false, script_path),
630616
transaction: create_test_evm_transaction(),
631-
receipt: create_test_evm_transaction_receipt(),
617+
receipt: Some(create_test_evm_transaction_receipt()),
618+
logs: Some(create_test_evm_logs()),
632619
network_slug: "ethereum_mainnet".to_string(),
633620
matched_on: MatchConditions {
634621
functions: vec![],
@@ -662,7 +649,8 @@ mod tests {
662649
BlockChainType::EVM => MonitorMatch::EVM(Box::new(EVMMonitorMatch {
663650
monitor,
664651
transaction: create_test_evm_transaction(),
665-
receipt: create_test_evm_transaction_receipt(),
652+
receipt: Some(create_test_evm_transaction_receipt()),
653+
logs: Some(create_test_evm_logs()),
666654
network_slug: "ethereum_mainnet".to_string(),
667655
matched_on: MatchConditions {
668656
functions: vec![],

src/models/blockchain/evm/monitor.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::models::{EVMTransaction, EVMTransactionReceipt, MatchConditions, Monitor};
1+
use crate::models::{
2+
EVMReceiptLog, EVMTransaction, EVMTransactionReceipt, MatchConditions, Monitor,
3+
};
24
use serde::{Deserialize, Serialize};
35

46
/// Result of a successful monitor match on an EVM chain
@@ -11,7 +13,10 @@ pub struct EVMMonitorMatch {
1113
pub transaction: EVMTransaction,
1214

1315
/// Transaction receipt with execution results
14-
pub receipt: EVMTransactionReceipt,
16+
pub receipt: Option<EVMTransactionReceipt>,
17+
18+
/// Transaction logs
19+
pub logs: Option<Vec<EVMReceiptLog>>,
1520

1621
/// Network slug that the transaction was sent from
1722
pub network_slug: String,
@@ -180,7 +185,8 @@ mod tests {
180185
let monitor_match = EVMMonitorMatch {
181186
monitor: monitor.clone(),
182187
transaction: transaction.clone(),
183-
receipt: receipt.clone(),
188+
receipt: Some(receipt.clone()),
189+
logs: Some(receipt.logs.clone()),
184190
network_slug: "ethereum_mainnet".to_string(),
185191
matched_on: MatchConditions {
186192
functions: vec![FunctionCondition {
@@ -198,7 +204,10 @@ mod tests {
198204

199205
assert_eq!(monitor_match.monitor.name, "TestMonitor");
200206
assert_eq!(monitor_match.transaction.hash, B256::with_last_byte(1));
201-
assert_eq!(monitor_match.receipt.status, Some(U64::from(1)));
207+
assert_eq!(
208+
monitor_match.receipt.as_ref().unwrap().status,
209+
Some(U64::from(1))
210+
);
202211
assert_eq!(monitor_match.network_slug, "ethereum_mainnet");
203212
assert_eq!(monitor_match.matched_on.functions.len(), 1);
204213
assert_eq!(

src/services/blockchain/clients/evm/client.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,14 @@ pub trait EvmClientTrait {
8383
/// # Arguments
8484
/// * `from_block` - Starting block number
8585
/// * `to_block` - Ending block number
86-
///
86+
/// * `addresses` - Optional list of addresses to filter logs by
8787
/// # Returns
8888
/// * `Result<Vec<Log>, anyhow::Error>` - Collection of matching logs or error
8989
async fn get_logs_for_blocks(
9090
&self,
9191
from_block: u64,
9292
to_block: u64,
93+
addresses: Option<Vec<String>>,
9394
) -> Result<Vec<EVMReceiptLog>, anyhow::Error>;
9495
}
9596

@@ -137,19 +138,21 @@ impl<T: Send + Sync + Clone + BlockchainTransport> EvmClientTrait for EvmClient<
137138
/// # Arguments
138139
/// * `from_block` - Starting block number
139140
/// * `to_block` - Ending block number
140-
///
141+
/// * `addresses` - Optional list of addresses to filter logs by
141142
/// # Returns
142143
/// * `Result<Vec<EVMReceiptLog>, anyhow::Error>` - Collection of matching logs or error
143144
#[instrument(skip(self), fields(from_block, to_block))]
144145
async fn get_logs_for_blocks(
145146
&self,
146147
from_block: u64,
147148
to_block: u64,
149+
addresses: Option<Vec<String>>,
148150
) -> Result<Vec<EVMReceiptLog>, anyhow::Error> {
149151
// Convert parameters to JSON-RPC format
150152
let params = json!([{
151153
"fromBlock": format!("0x{:x}", from_block),
152-
"toBlock": format!("0x{:x}", to_block)
154+
"toBlock": format!("0x{:x}", to_block),
155+
"address": addresses
153156
}])
154157
.as_array()
155158
.with_context(|| "Failed to create JSON-RPC params array")?

0 commit comments

Comments
 (0)