55//! flashblock partitioning logic.
66
77use {
8- crate :: {
9- Flashblocks ,
10- state:: { FlashblockNumber , TargetFlashblocks } ,
11- } ,
8+ crate :: Flashblocks ,
129 core:: time:: Duration ,
1310 rblib:: { alloy:: consensus:: BlockHeader , prelude:: * } ,
14- std:: sync:: { Arc , Mutex } ,
15- tracing:: debug,
1611} ;
1712
1813/// Specifies the limits for individual flashblocks.
@@ -26,173 +21,51 @@ use {
2621/// deadline by the flashblock interval.
2722#[ derive( Debug , Clone , Default ) ]
2823pub struct FlashblockLimits {
29- state : Arc < Mutex < FlashblockState > > ,
3024 /// The time interval between flashblocks within one payload job.
3125 interval : Duration ,
3226}
3327
34- #[ derive( Debug , Clone , Default ) ]
35- pub struct FlashblockState {
36- /// Current block number being built, or `None` if uninitialized.
37- current_block : Option < u64 > ,
38- /// Current flashblock number. Used to check if we're on the first
39- /// flashblock or to adjust the target number of flashblocks for a block.
40- target_flashblocks : Arc < TargetFlashblocks > ,
41- /// Duration for the first flashblock, which may be shortened to absorb
42- /// timing variance.
43- first_flashblock_interval : Duration ,
44- /// Gas allocated per flashblock (total gas limit divided by flashblock
45- /// count).
46- gas_per_flashblock : u64 ,
47- }
48-
49- impl FlashblockState {
50- fn current_gas_limit ( & self , flashblock_number : & FlashblockNumber ) -> u64 {
51- self
52- . gas_per_flashblock
53- . saturating_mul ( flashblock_number. current ( ) )
54- }
55- }
56-
5728impl FlashblockLimits {
58- pub fn new (
59- interval : Duration ,
60- target_flashblocks : Arc < TargetFlashblocks > ,
61- ) -> Self {
62- let state = FlashblockState {
63- target_flashblocks,
64- ..Default :: default ( )
65- } ;
66- FlashblockLimits {
67- interval,
68- state : Arc :: new ( Mutex :: new ( state) ) ,
69- }
29+ pub fn new ( interval : Duration ) -> Self {
30+ FlashblockLimits { interval }
7031 }
32+ }
7133
72- /// Resets state when starting a new block, calculating target flashblock
73- /// count.
74- ///
75- /// If a new block is detected (different block number than current state),
76- /// initializes the flashblock partition for this block by:
77- /// - Calculating available time and dividing it into flashblock intervals
78- /// - Computing gas per flashblock from the total gas limit
79- /// - Resetting the current flashblock counter to 0
80- /// - Adjusting the target number of flashblocks
81- pub fn update_state (
34+ impl ScopedLimits < Flashblocks > for FlashblockLimits {
35+ /// Creates the payload limits for the next flashblock in a new payload job.
36+ fn create (
8237 & self ,
8338 payload : & Checkpoint < Flashblocks > ,
8439 enclosing : & Limits < Flashblocks > ,
85- ) {
86- let mut state = self . state . lock ( ) . expect ( "mutex is not poisoned" ) ;
87-
88- if state. current_block != Some ( payload. block ( ) . number ( ) ) {
89- let payload_deadline = enclosing. deadline . expect (
90- "Flashblock limit require its enclosing scope to have a deadline" ,
91- ) ;
92- let elapsed = payload. building_since ( ) . elapsed ( ) ;
93- let remaining_time = payload_deadline. saturating_sub ( elapsed) ;
94-
95- let ( target_flashblocks, first_flashblock_interval) =
96- self . calculate_flashblocks ( payload, remaining_time) ;
97-
98- state. gas_per_flashblock = enclosing
99- . gas_limit
100- . checked_div ( target_flashblocks)
101- . unwrap_or ( enclosing. gas_limit ) ;
102- state. current_block = Some ( payload. block ( ) . number ( ) ) ;
103- state. first_flashblock_interval = first_flashblock_interval;
104- state. target_flashblocks . set ( target_flashblocks) ;
105-
106- debug ! (
107- target_flashblocks = target_flashblocks,
108- first_flashblock_interval = ?first_flashblock_interval,
109- "Set flashblock timing for this block"
110- ) ;
111- }
112- }
113-
114- /// Returns limits for the current flashblock.
115- ///
116- /// If all flashblocks have been produced, returns a deadline of 1ms to stop
117- /// production.
118- pub fn get_limits (
119- & self ,
120- enclosing : & Limits < Flashblocks > ,
121- flashblock_number : & FlashblockNumber ,
12240 ) -> Limits < Flashblocks > {
123- let state = self . state . lock ( ) . expect ( "mutex is not poisoned" ) ;
124- // If flashblock number == 1, we're building the first flashblock
125- let deadline = if flashblock_number. current ( ) == 1 {
126- state. first_flashblock_interval
127- } else {
128- self . interval
129- } ;
130-
131- enclosing
132- . with_deadline ( deadline)
133- . with_gas_limit ( state. current_gas_limit ( flashblock_number) )
134- }
41+ let flashblock_number = payload. context ( ) ;
42+
43+ let payload_deadline = enclosing. deadline . expect (
44+ "FlashblockLimits requires its enclosing scope to have a deadline" ,
45+ ) ;
46+ let elapsed = payload. building_since ( ) . elapsed ( ) ;
47+ let remaining_time = payload_deadline. saturating_sub ( elapsed) ;
13548
136- /// Calculates the number of flashblocks and first flashblock interval for
137- /// this block.
138- ///
139- /// Extracts block time from block timestamps, then partitions the remaining
140- /// time into flashblock intervals.
141- pub fn calculate_flashblocks (
142- & self ,
143- payload : & Checkpoint < Flashblocks > ,
144- remaining_time : Duration ,
145- ) -> ( u64 , Duration ) {
14649 let block_time = Duration :: from_secs (
14750 payload
14851 . block ( )
14952 . timestamp ( )
15053 . saturating_sub ( payload. block ( ) . parent ( ) . header ( ) . timestamp ( ) ) ,
15154 ) ;
15255
153- partition_time_into_flashblocks ( block_time, remaining_time, self . interval )
154- }
155- }
156-
157- impl ScopedLimits < Flashblocks > for FlashblockLimits {
158- /// Creates the payload limits for the next flashblock in a new payload job.
159- fn create (
160- & self ,
161- payload : & Checkpoint < Flashblocks > ,
162- enclosing : & Limits < Flashblocks > ,
163- ) -> Limits < Flashblocks > {
164- let flashblock_number = payload. context ( ) ;
165- // Check the state and reset if we started building next block
166- self . update_state ( payload, enclosing) ;
167-
168- let limits = self . get_limits ( enclosing, flashblock_number) ;
56+ let ( target_flashblocks, deadline) = partition_time_into_flashblocks (
57+ block_time,
58+ remaining_time,
59+ self . interval ,
60+ ) ;
16961
170- let state = self . state . lock ( ) . expect ( "mutex is not poisoned" ) ;
171- let flashblock_number = payload. context ( ) ;
172- if flashblock_number. current ( ) <= state. target_flashblocks . get ( ) {
173- let gas_used = payload. cumulative_gas_used ( ) ;
174- let remaining_gas = enclosing. gas_limit . saturating_sub ( gas_used) ;
175- tracing:: info!(
176- "Creating flashblocks limits: {}, payload txs: {}, gas used: {} \
177- ({}%), gas_remaining: {} ({}%), next_block_gas_limit: {} ({}%), gas \
178- per block: {} ({}%), remaining_time: {}ms, gas_limit: {}",
179- flashblock_number,
180- payload. history( ) . transactions( ) . count( ) ,
181- gas_used,
182- ( gas_used * 100 / enclosing. gas_limit) ,
183- remaining_gas,
184- ( remaining_gas * 100 / enclosing. gas_limit) ,
185- state. current_gas_limit( flashblock_number) ,
186- ( state. current_gas_limit( flashblock_number) * 100
187- / enclosing. gas_limit) ,
188- state. gas_per_flashblock,
189- ( state. gas_per_flashblock * 100 / enclosing. gas_limit) ,
190- limits. deadline. expect( "deadline is set" ) . as_millis( ) ,
191- limits. gas_limit
192- ) ;
193- }
62+ let gas_limit = enclosing
63+ . gas_limit
64+ . checked_div ( target_flashblocks)
65+ . unwrap_or ( enclosing. gas_limit )
66+ . saturating_mul ( flashblock_number. current ( ) ) ;
19467
195- limits
68+ enclosing . with_deadline ( deadline ) . with_gas_limit ( gas_limit )
19669 }
19770}
19871
@@ -221,21 +94,21 @@ fn partition_time_into_flashblocks(
22194) -> ( u64 , Duration ) {
22295 let remaining_time = remaining_time. min ( block_time) ;
22396
224- let remaining_millis = u64:: try_from ( remaining_time. as_millis ( ) )
97+ let remaining_ms = u64:: try_from ( remaining_time. as_millis ( ) )
22598 . expect ( "remaining_time should never exceed u64::MAX milliseconds" ) ;
226- let interval_millis = u64:: try_from ( flashblock_interval. as_millis ( ) )
99+ let flashblock_interval_ms = u64:: try_from ( flashblock_interval. as_millis ( ) )
227100 . expect ( "flashblock_interval should never exceed u64::MAX milliseconds" ) ;
228101
229- let first_offset_millis = remaining_millis % interval_millis ;
102+ let first_offset_ms = remaining_ms % flashblock_interval_ms ;
230103
231- if first_offset_millis == 0 {
104+ if first_offset_ms == 0 {
232105 // Perfect division: remaining time is exact multiple of interval
233- ( remaining_millis / interval_millis , flashblock_interval)
106+ ( remaining_ms / flashblock_interval_ms , flashblock_interval)
234107 } else {
235108 // Non-perfect division: add extra flashblock with shortened first interval
236109 (
237- remaining_millis / interval_millis + 1 ,
238- Duration :: from_millis ( first_offset_millis ) ,
110+ remaining_ms / flashblock_interval_ms + 1 ,
111+ Duration :: from_millis ( first_offset_ms ) ,
239112 )
240113 }
241114}
0 commit comments