Skip to content

Commit bea1d62

Browse files
committed
Use latest block state for metering instead of bundle.block_number
Bundle metering now always uses the latest available block state for simulation. The bundle.block_number parameter is only used for TIPS bundle validity checks, not for state selection.
1 parent ea0edba commit bea1d62

File tree

3 files changed

+49
-16
lines changed

3 files changed

+49
-16
lines changed

crates/metering/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Simulates a bundle of transactions, providing gas usage and execution time metri
1111
The method accepts a Bundle object with the following fields:
1212

1313
- `txs`: Array of signed, RLP-encoded transactions (hex strings with 0x prefix)
14-
- `block_number`: Target block number (used both for bundle validity and as the state block for simulation)
14+
- `block_number`: Target block number for bundle validity (note: simulation always uses the latest available block state)
1515
- `min_timestamp` (optional): Minimum timestamp for bundle validity (also used as simulation timestamp if provided)
1616
- `max_timestamp` (optional): Maximum timestamp for bundle validity
1717
- `reverting_tx_hashes` (optional): Array of transaction hashes allowed to revert
@@ -26,7 +26,7 @@ The method accepts a Bundle object with the following fields:
2626
- `coinbaseDiff`: Total gas fees paid
2727
- `ethSentToCoinbase`: ETH sent directly to coinbase
2828
- `gasFees`: Total gas fees
29-
- `stateBlockNumber`: Block number used for state
29+
- `stateBlockNumber`: Block number used for state (always the latest available block)
3030
- `totalGasUsed`: Total gas consumed
3131
- `totalExecutionTimeUs`: Total execution time (μs)
3232
- `results`: Array of per-transaction results:

crates/metering/src/rpc.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use alloy_consensus::Header;
22
use alloy_eips::eip2718::Decodable2718;
3+
use alloy_eips::BlockNumberOrTag;
34
use alloy_primitives::U256;
45
use jsonrpsee::{
56
core::{async_trait, RpcResult},
@@ -57,21 +58,21 @@ where
5758
"Starting bundle metering"
5859
);
5960

60-
// Get the header
61+
// Get the latest header
6162
let header = self
6263
.provider
63-
.sealed_header(bundle.block_number)
64+
.sealed_header_by_number_or_tag(BlockNumberOrTag::Latest)
6465
.map_err(|e| {
6566
jsonrpsee::types::ErrorObjectOwned::owned(
6667
jsonrpsee::types::ErrorCode::InternalError.code(),
67-
format!("Failed to get header: {}", e),
68+
format!("Failed to get latest header: {}", e),
6869
None::<()>,
6970
)
7071
})?
7172
.ok_or_else(|| {
7273
jsonrpsee::types::ErrorObjectOwned::owned(
73-
jsonrpsee::types::ErrorCode::InvalidParams.code(),
74-
format!("Block {} not found", bundle.block_number),
74+
jsonrpsee::types::ErrorCode::InternalError.code(),
75+
"Latest block not found".to_string(),
7576
None::<()>,
7677
)
7778
})?;
@@ -153,7 +154,7 @@ where
153154
eth_sent_to_coinbase: "0".to_string(),
154155
gas_fees: result.total_gas_fees.to_string(),
155156
results: result.results,
156-
state_block_number: bundle.block_number,
157+
state_block_number: header.number,
157158
total_gas_used: result.total_gas_used,
158159
total_execution_time_us: result.total_execution_time_us,
159160
state_root_time_us: result.state_root_time_us,

crates/metering/src/tests/rpc.rs

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -291,19 +291,48 @@ mod tests {
291291
}
292292

293293
#[tokio::test]
294-
async fn test_meter_bundle_uses_block_number() -> eyre::Result<()> {
294+
async fn test_meter_bundle_uses_latest_block() -> eyre::Result<()> {
295295
reth_tracing::init_test_tracing();
296296
let node = setup_node().await?;
297297
let client = node.rpc_client().await?;
298298

299-
// Bundle.block_number is used as the state block for simulation
299+
// Metering always uses the latest block state, regardless of bundle.block_number
300300
let bundle = create_bundle(vec![], 0, None);
301301

302302
let response: crate::MeterBundleResponse = client
303303
.request("base_meterBundle", (bundle,))
304304
.await?;
305305

306-
assert_eq!(response.state_block_number, 0); // Uses bundle.block_number
306+
// Should return the latest block number (genesis block 0)
307+
assert_eq!(response.state_block_number, 0);
308+
309+
Ok(())
310+
}
311+
312+
#[tokio::test]
313+
async fn test_meter_bundle_ignores_bundle_block_number() -> eyre::Result<()> {
314+
reth_tracing::init_test_tracing();
315+
let node = setup_node().await?;
316+
let client = node.rpc_client().await?;
317+
318+
// Even if bundle.block_number is different, it should use the latest block
319+
// In this test, we specify block_number=0 in the bundle
320+
let bundle1 = create_bundle(vec![], 0, None);
321+
let response1: crate::MeterBundleResponse = client
322+
.request("base_meterBundle", (bundle1,))
323+
.await?;
324+
325+
// Try with a different bundle.block_number (999 - arbitrary value)
326+
// Since we can't create future blocks, we use a different value to show it's ignored
327+
let bundle2 = create_bundle(vec![], 999, None);
328+
let response2: crate::MeterBundleResponse = client
329+
.request("base_meterBundle", (bundle2,))
330+
.await?;
331+
332+
// Both should return the same state_block_number (the latest block)
333+
// because the implementation always uses Latest, not bundle.block_number
334+
assert_eq!(response1.state_block_number, response2.state_block_number);
335+
assert_eq!(response1.state_block_number, 0); // Genesis block
307336

308337
Ok(())
309338
}
@@ -332,18 +361,21 @@ mod tests {
332361
}
333362

334363
#[tokio::test]
335-
async fn test_meter_bundle_nonexistent_block() -> eyre::Result<()> {
364+
async fn test_meter_bundle_arbitrary_block_number() -> eyre::Result<()> {
336365
reth_tracing::init_test_tracing();
337366
let node = setup_node().await?;
338367
let client = node.rpc_client().await?;
339368

340-
let bundle = create_bundle(vec![], 999999, None); // Non-existent block
369+
// Since we now ignore bundle.block_number and always use the latest block,
370+
// any block_number value should work (it's only used for bundle validity in TIPS)
371+
let bundle = create_bundle(vec![], 999999, None);
341372

342-
let result: Result<crate::MeterBundleResponse, _> = client
373+
let response: crate::MeterBundleResponse = client
343374
.request("base_meterBundle", (bundle,))
344-
.await;
375+
.await?;
345376

346-
assert!(result.is_err());
377+
// Should succeed and use the latest block (genesis block 0)
378+
assert_eq!(response.state_block_number, 0);
347379

348380
Ok(())
349381
}

0 commit comments

Comments
 (0)