11#[ cfg( test) ]
22mod tests {
33 use crate :: {
4- MeteringApiImpl , MeteringApiServer , MeteringCache , PriorityFeeEstimator , ResourceLimits ,
4+ MeteredTransaction , MeteringApiImpl , MeteringApiServer , MeteringCache ,
5+ PriorityFeeEstimator , ResourceLimits ,
56 } ;
67
78 const PRIORITY_FEE_PERCENTILE : f64 = 0.5 ;
@@ -21,9 +22,11 @@ mod tests {
2122 use reth:: chainspec:: Chain ;
2223 use reth:: core:: exit:: NodeExitFuture ;
2324 use reth:: tasks:: TaskManager ;
25+ use reth_rpc_server_types:: { RethRpcModule , RpcModuleSelection } ;
2426 use reth_optimism_chainspec:: OpChainSpecBuilder ;
2527 use reth_optimism_node:: OpNode ;
2628 use reth_optimism_node:: args:: RollupArgs ;
29+ use reth_optimism_payload_builder:: config:: OpDAConfig ;
2730 use reth_optimism_primitives:: OpTransactionSigned ;
2831 use reth_provider:: providers:: BlockchainProvider ;
2932 use reth_transaction_pool:: test_utils:: TransactionBuilder ;
@@ -35,6 +38,7 @@ mod tests {
3538
3639 pub struct NodeContext {
3740 http_api_addr : SocketAddr ,
41+ cache : Arc < RwLock < MeteringCache > > ,
3842 _node_exit_future : NodeExitFuture ,
3943 _node : Box < dyn Any + Sync + Send > ,
4044 }
@@ -86,10 +90,19 @@ mod tests {
8690
8791 let node_config = NodeConfig :: new ( chain_spec. clone ( ) )
8892 . with_network ( network_config. clone ( ) )
89- . with_rpc ( RpcServerArgs :: default ( ) . with_unused_ports ( ) . with_http ( ) )
93+ . with_rpc (
94+ RpcServerArgs :: default ( )
95+ . with_unused_ports ( )
96+ . with_http ( )
97+ . with_http_api ( RpcModuleSelection :: from ( [ RethRpcModule :: Miner ] ) ) ,
98+ )
9099 . with_unused_ports ( ) ;
91100
92- let node = OpNode :: new ( RollupArgs :: default ( ) ) ;
101+ // Create shared DA config that will be used by both the miner RPC and the estimator.
102+ // When miner_setMaxDASize is called, the OpDAConfig is updated atomically and
103+ // the estimator will see the new limits.
104+ let da_config = OpDAConfig :: default ( ) ;
105+ let node = OpNode :: new ( RollupArgs :: default ( ) ) . with_da_config ( da_config. clone ( ) ) ;
93106
94107 let cache = Arc :: new ( RwLock :: new ( MeteringCache :: new ( 12 ) ) ) ;
95108 let limits = ResourceLimits {
@@ -103,6 +116,7 @@ mod tests {
103116 PRIORITY_FEE_PERCENTILE ,
104117 limits,
105118 U256 :: from ( UNCONGESTED_PRIORITY_FEE ) ,
119+ Some ( da_config. clone ( ) ) ,
106120 ) ) ;
107121 let estimator_for_rpc = estimator. clone ( ) ;
108122
@@ -130,6 +144,7 @@ mod tests {
130144
131145 Ok ( NodeContext {
132146 http_api_addr,
147+ cache,
133148 _node_exit_future : node_exit_future,
134149 _node : Box :: new ( node) ,
135150 } )
@@ -487,4 +502,108 @@ mod tests {
487502
488503 Ok ( ( ) )
489504 }
505+
506+ /// Creates a test transaction with specified priority fee and DA bytes.
507+ fn test_tx ( priority_fee : u64 , da_bytes : u64 ) -> MeteredTransaction {
508+ let mut hash_bytes = [ 0u8 ; 32 ] ;
509+ hash_bytes[ 24 ..] . copy_from_slice ( & priority_fee. to_be_bytes ( ) ) ;
510+ MeteredTransaction {
511+ tx_hash : alloy_primitives:: B256 :: new ( hash_bytes) ,
512+ priority_fee_per_gas : U256 :: from ( priority_fee) ,
513+ gas_used : 21_000 ,
514+ execution_time_us : 100 ,
515+ state_root_time_us : 0 ,
516+ data_availability_bytes : da_bytes,
517+ }
518+ }
519+
520+ #[ tokio:: test]
521+ async fn test_set_max_da_size_updates_priority_fee_estimates ( ) -> eyre:: Result < ( ) > {
522+ reth_tracing:: init_test_tracing ( ) ;
523+ let node = setup_node ( ) . await ?;
524+ let client = node. rpc_client ( ) . await ?;
525+
526+ // Create a transaction to include in the bundle for DA demand calculation.
527+ // Use a funded account from genesis.json (Hardhat account #0).
528+ let sender_secret =
529+ b256 ! ( "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" ) ;
530+
531+ let tx = TransactionBuilder :: default ( )
532+ . signer ( sender_secret)
533+ . chain_id ( 84532 )
534+ . nonce ( 0 )
535+ . to ( address ! ( "0x1111111111111111111111111111111111111111" ) )
536+ . value ( 1000 )
537+ . gas_limit ( 21_000 )
538+ . max_fee_per_gas ( 1_000_000_000 )
539+ . max_priority_fee_per_gas ( 1_000_000_000 )
540+ . into_eip1559 ( ) ;
541+
542+ let signed_tx =
543+ OpTransactionSigned :: Eip1559 ( tx. as_eip1559 ( ) . expect ( "eip1559 transaction" ) . clone ( ) ) ;
544+ let envelope: OpTxEnvelope = signed_tx. into ( ) ;
545+ let tx_bytes = Bytes :: from ( envelope. encoded_2718 ( ) ) ;
546+
547+ // Populate the cache with test transactions that have known DA bytes.
548+ // We'll create a scenario where DA is the constraining resource:
549+ // - tx1: priority=100, DA=50 bytes
550+ // - tx2: priority=50, DA=50 bytes
551+ // - tx3: priority=10, DA=50 bytes
552+ // Total DA used by existing transactions = 150 bytes
553+ {
554+ let mut cache = node. cache . write ( ) ;
555+ cache. upsert_transaction ( 1 , 0 , test_tx ( 100 , 50 ) ) ;
556+ cache. upsert_transaction ( 1 , 0 , test_tx ( 50 , 50 ) ) ;
557+ cache. upsert_transaction ( 1 , 0 , test_tx ( 10 , 50 ) ) ;
558+ }
559+
560+ // Bundle with our transaction - it will have some DA demand from the tx bytes.
561+ let bundle = create_bundle ( vec ! [ tx_bytes] , 0 , None ) ;
562+
563+ // With default DA limit (120KB = 120_000 bytes), there's plenty of room.
564+ // All transactions fit (150 bytes used) plus our bundle's demand.
565+ // This should return the uncongested default fee (1 wei).
566+ //
567+ // Note: We use serde_json::Value because alloy_rpc_client can't deserialize u128 fields
568+ // when they're nested in flattened structs. The response contains totalExecutionTimeUs
569+ // as u128 which causes deserialization issues.
570+ let response: serde_json:: Value = client
571+ . request ( "base_meteredPriorityFeePerGas" , ( bundle. clone ( ) , ) )
572+ . await ?;
573+
574+ let fee_before = response[ "recommendedPriorityFee" ]
575+ . as_str ( )
576+ . expect ( "recommendedPriorityFee should be a string" ) ;
577+ assert_eq ! (
578+ fee_before, "1" ,
579+ "with large DA limit, resource should be uncongested"
580+ ) ;
581+
582+ // Now reduce the DA limit to 200 bytes via miner_setMaxDASize.
583+ // With 200 byte limit and ~100 byte bundle demand, only ~100 bytes available for others.
584+ // tx1 (50) + tx2 (50) = 100 bytes fits, but adding tx3 (50) = 150 bytes exceeds capacity.
585+ // So tx3 gets displaced. Threshold fee = tx2's fee = 50.
586+ let result: bool = client. request ( "miner_setMaxDASize" , ( 1000 , 200 ) ) . await ?;
587+ assert ! ( result, "miner_setMaxDASize should succeed" ) ;
588+
589+ // Request priority fee again - now DA should be congested.
590+ let response: serde_json:: Value = client
591+ . request ( "base_meteredPriorityFeePerGas" , ( bundle, ) )
592+ . await ?;
593+
594+ // With the reduced limit, we should see a higher recommended fee.
595+ // The exact value depends on the percentile calculation, but it should
596+ // be significantly higher than the uncongested fee of 1.
597+ let fee_after = response[ "recommendedPriorityFee" ]
598+ . as_str ( )
599+ . expect ( "recommendedPriorityFee should be a string" ) ;
600+ let fee: u64 = fee_after. parse ( ) . expect ( "valid u64" ) ;
601+ assert ! (
602+ fee > 1 ,
603+ "with reduced DA limit, recommended fee should be higher than uncongested fee (1), got {}" ,
604+ fee
605+ ) ;
606+
607+ Ok ( ( ) )
608+ }
490609}
0 commit comments