@@ -136,13 +136,13 @@ pub enum PrioritizationFeeError {
136136/// block; and the minimum fee for each writable account in all transactions in this block. The only relevant
137137/// write account minimum fees are those greater than the block minimum transaction fee, because the minimum fee needed to land
138138/// a transaction is determined by Max( min_transaction_fee, min_writable_account_fees(key), ...)
139- #[ derive( Debug ) ]
139+ #[ derive( Debug , Default ) ]
140140pub struct PrioritizationFee {
141- // The minimum prioritization fee of transactions that landed in this block.
142- min_transaction_fee : u64 ,
141+ // Prioritization fee of transactions that landed in this block.
142+ transaction_fees : Vec < u64 > ,
143143
144- // The minimum prioritization fee of each writable account in transactions in this block.
145- min_writable_account_fees : HashMap < Pubkey , u64 > ,
144+ // Prioritization fee of each writable account in transactions in this block.
145+ writable_account_fees : HashMap < Pubkey , Vec < u64 > > ,
146146
147147 // Default to `false`, set to `true` when a block is completed, therefore the minimum fees recorded
148148 // are finalized, and can be made available for use (e.g., RPC query)
@@ -152,33 +152,18 @@ pub struct PrioritizationFee {
152152 metrics : PrioritizationFeeMetrics ,
153153}
154154
155- impl Default for PrioritizationFee {
156- fn default ( ) -> Self {
157- PrioritizationFee {
158- min_transaction_fee : u64:: MAX ,
159- min_writable_account_fees : HashMap :: new ( ) ,
160- is_finalized : false ,
161- metrics : PrioritizationFeeMetrics :: default ( ) ,
162- }
163- }
164- }
165-
166155impl PrioritizationFee {
167156 /// Update self for minimum transaction fee in the block and minimum fee for each writable account.
168157 pub fn update ( & mut self , transaction_fee : u64 , writable_accounts : Vec < Pubkey > ) {
169158 let ( _, update_us) = measure_us ! ( {
170159 if !self . is_finalized {
171- if transaction_fee < self . min_transaction_fee {
172- self . min_transaction_fee = transaction_fee;
173- }
160+ self . transaction_fees. push( transaction_fee) ;
174161
175162 for write_account in writable_accounts {
176- self . min_writable_account_fees
163+ self . writable_account_fees
177164 . entry( write_account)
178- . and_modify( |write_lock_fee| {
179- * write_lock_fee = std:: cmp:: min( * write_lock_fee, transaction_fee)
180- } )
181- . or_insert( transaction_fee) ;
165+ . or_default( )
166+ . push( transaction_fee) ;
182167 }
183168
184169 self . metrics
@@ -193,38 +178,54 @@ impl PrioritizationFee {
193178 self . metrics . accumulate_total_update_elapsed_us ( update_us) ;
194179 }
195180
196- /// Accounts that have minimum fees lesser or equal to the minimum fee in the block are redundant, they are
197- /// removed to reduce memory footprint when mark_block_completed() is called.
198- fn prune_irrelevant_writable_accounts ( & mut self ) {
199- self . metrics . total_writable_accounts_count = self . get_writable_accounts_count ( ) as u64 ;
200- self . min_writable_account_fees
201- . retain ( |_, account_fee| account_fee > & mut self . min_transaction_fee ) ;
202- self . metrics . relevant_writable_accounts_count = self . get_writable_accounts_count ( ) as u64 ;
203- }
204-
205181 pub fn mark_block_completed ( & mut self ) -> Result < ( ) , PrioritizationFeeError > {
206182 if self . is_finalized {
207183 return Err ( PrioritizationFeeError :: BlockIsAlreadyFinalized ) ;
208184 }
209- self . prune_irrelevant_writable_accounts ( ) ;
210185 self . is_finalized = true ;
186+
187+ self . transaction_fees . sort ( ) ;
188+ for fees in self . writable_account_fees . values_mut ( ) {
189+ fees. sort ( )
190+ }
191+
192+ self . metrics . total_writable_accounts_count = self . get_writable_accounts_count ( ) as u64 ;
193+ self . metrics . relevant_writable_accounts_count = self . get_writable_accounts_count ( ) as u64 ;
194+
211195 Ok ( ( ) )
212196 }
213197
214198 pub fn get_min_transaction_fee ( & self ) -> Option < u64 > {
215- ( self . min_transaction_fee != u64:: MAX ) . then_some ( self . min_transaction_fee )
199+ self . transaction_fees . first ( ) . copied ( )
200+ }
201+
202+ fn get_percentile ( fees : & [ u64 ] , percentile : u16 ) -> Option < u64 > {
203+ let index = ( percentile as usize ) . min ( 9_999 ) * fees. len ( ) / 10_000 ;
204+ fees. get ( index) . copied ( )
205+ }
206+
207+ pub fn get_transaction_fee ( & self , percentile : u16 ) -> Option < u64 > {
208+ Self :: get_percentile ( & self . transaction_fees , percentile)
209+ }
210+
211+ pub fn get_min_writable_account_fee ( & self , key : & Pubkey ) -> Option < u64 > {
212+ self . writable_account_fees
213+ . get ( key)
214+ . and_then ( |fees| fees. first ( ) . copied ( ) )
216215 }
217216
218- pub fn get_writable_account_fee ( & self , key : & Pubkey ) -> Option < u64 > {
219- self . min_writable_account_fees . get ( key) . copied ( )
217+ pub fn get_writable_account_fee ( & self , key : & Pubkey , percentile : u16 ) -> Option < u64 > {
218+ self . writable_account_fees
219+ . get ( key)
220+ . and_then ( |fees| Self :: get_percentile ( fees, percentile) )
220221 }
221222
222- pub fn get_writable_account_fees ( & self ) -> impl Iterator < Item = ( & Pubkey , & u64 ) > {
223- self . min_writable_account_fees . iter ( )
223+ pub fn get_writable_account_fees ( & self ) -> impl Iterator < Item = ( & Pubkey , & Vec < u64 > ) > {
224+ self . writable_account_fees . iter ( )
224225 }
225226
226227 pub fn get_writable_accounts_count ( & self ) -> usize {
227- self . min_writable_account_fees . len ( )
228+ self . writable_account_fees . len ( )
228229 }
229230
230231 pub fn is_finalized ( & self ) -> bool {
@@ -236,20 +237,28 @@ impl PrioritizationFee {
236237
237238 // report this slot's min_transaction_fee and top 10 min_writable_account_fees
238239 let min_transaction_fee = self . get_min_transaction_fee ( ) . unwrap_or ( 0 ) ;
239- let mut accounts_fees: Vec < _ > = self . get_writable_account_fees ( ) . collect ( ) ;
240- accounts_fees. sort_by ( |lh, rh| rh. 1 . cmp ( lh. 1 ) ) ;
241240 datapoint_info ! (
242241 "block_min_prioritization_fee" ,
243242 ( "slot" , slot as i64 , i64 ) ,
244243 ( "entity" , "block" , String ) ,
245244 ( "min_prioritization_fee" , min_transaction_fee as i64 , i64 ) ,
246245 ) ;
247- for ( account_key, fee) in accounts_fees. iter ( ) . take ( 10 ) {
246+
247+ let mut accounts_fees: Vec < ( & Pubkey , u64 ) > = self
248+ . get_writable_account_fees ( )
249+ . filter_map ( |( account, fees) | {
250+ fees. first ( )
251+ . copied ( )
252+ . map ( |min_account_fee| ( account, min_transaction_fee. min ( min_account_fee) ) )
253+ } )
254+ . collect ( ) ;
255+ accounts_fees. sort_by ( |lh, rh| rh. 1 . cmp ( & lh. 1 ) ) ;
256+ for ( account_key, fee) in accounts_fees. into_iter ( ) . take ( 10 ) {
248257 datapoint_trace ! (
249258 "block_min_prioritization_fee" ,
250259 ( "slot" , slot as i64 , i64 ) ,
251260 ( "entity" , account_key. to_string( ) , String ) ,
252- ( "min_prioritization_fee" , * * fee as i64 , i64 ) ,
261+ ( "min_prioritization_fee" , fee as i64 , i64 ) ,
253262 ) ;
254263 }
255264 }
@@ -275,22 +284,26 @@ mod tests {
275284 // [5, a, b ] --> [5, 5, 5, nil ]
276285 {
277286 prioritization_fee. update ( 5 , vec ! [ write_account_a, write_account_b] ) ;
287+ assert ! ( prioritization_fee. mark_block_completed( ) . is_ok( ) ) ;
288+
278289 assert_eq ! ( 5 , prioritization_fee. get_min_transaction_fee( ) . unwrap( ) ) ;
279290 assert_eq ! (
280291 5 ,
281292 prioritization_fee
282- . get_writable_account_fee ( & write_account_a)
293+ . get_min_writable_account_fee ( & write_account_a)
283294 . unwrap( )
284295 ) ;
285296 assert_eq ! (
286297 5 ,
287298 prioritization_fee
288- . get_writable_account_fee ( & write_account_b)
299+ . get_min_writable_account_fee ( & write_account_b)
289300 . unwrap( )
290301 ) ;
291302 assert ! ( prioritization_fee
292- . get_writable_account_fee ( & write_account_c)
303+ . get_min_writable_account_fee ( & write_account_c)
293304 . is_none( ) ) ;
305+
306+ prioritization_fee. is_finalized = false ;
294307 }
295308
296309 // Assert for second transaction:
@@ -299,25 +312,29 @@ mod tests {
299312 // [9, b, c ] --> [5, 5, 5, 9 ]
300313 {
301314 prioritization_fee. update ( 9 , vec ! [ write_account_b, write_account_c] ) ;
315+ assert ! ( prioritization_fee. mark_block_completed( ) . is_ok( ) ) ;
316+
302317 assert_eq ! ( 5 , prioritization_fee. get_min_transaction_fee( ) . unwrap( ) ) ;
303318 assert_eq ! (
304319 5 ,
305320 prioritization_fee
306- . get_writable_account_fee ( & write_account_a)
321+ . get_min_writable_account_fee ( & write_account_a)
307322 . unwrap( )
308323 ) ;
309324 assert_eq ! (
310325 5 ,
311326 prioritization_fee
312- . get_writable_account_fee ( & write_account_b)
327+ . get_min_writable_account_fee ( & write_account_b)
313328 . unwrap( )
314329 ) ;
315330 assert_eq ! (
316331 9 ,
317332 prioritization_fee
318- . get_writable_account_fee ( & write_account_c)
333+ . get_min_writable_account_fee ( & write_account_c)
319334 . unwrap( )
320335 ) ;
336+
337+ prioritization_fee. is_finalized = false ;
321338 }
322339
323340 // Assert for third transaction:
@@ -326,44 +343,56 @@ mod tests {
326343 // [2, a, c ] --> [2, 2, 5, 2 ]
327344 {
328345 prioritization_fee. update ( 2 , vec ! [ write_account_a, write_account_c] ) ;
346+ assert ! ( prioritization_fee. mark_block_completed( ) . is_ok( ) ) ;
347+
329348 assert_eq ! ( 2 , prioritization_fee. get_min_transaction_fee( ) . unwrap( ) ) ;
330349 assert_eq ! (
331350 2 ,
332351 prioritization_fee
333- . get_writable_account_fee ( & write_account_a)
352+ . get_min_writable_account_fee ( & write_account_a)
334353 . unwrap( )
335354 ) ;
336355 assert_eq ! (
337356 5 ,
338357 prioritization_fee
339- . get_writable_account_fee ( & write_account_b)
358+ . get_min_writable_account_fee ( & write_account_b)
340359 . unwrap( )
341360 ) ;
342361 assert_eq ! (
343362 2 ,
344363 prioritization_fee
345- . get_writable_account_fee ( & write_account_c)
364+ . get_min_writable_account_fee ( & write_account_c)
346365 . unwrap( )
347366 ) ;
367+
368+ prioritization_fee. is_finalized = false ;
348369 }
349370
350- // assert after prune, account a and c should be removed from cache to save space
371+ // assert after sort
351372 {
352- prioritization_fee. prune_irrelevant_writable_accounts ( ) ;
353- assert_eq ! ( 1 , prioritization_fee. min_writable_account_fees. len( ) ) ;
373+ prioritization_fee. update ( 2 , vec ! [ write_account_a, write_account_c] ) ;
374+ assert ! ( prioritization_fee. mark_block_completed( ) . is_ok( ) ) ;
375+
354376 assert_eq ! ( 2 , prioritization_fee. get_min_transaction_fee( ) . unwrap( ) ) ;
355- assert ! ( prioritization_fee
356- . get_writable_account_fee( & write_account_a)
357- . is_none( ) ) ;
377+ assert_eq ! ( 3 , prioritization_fee. writable_account_fees. len( ) ) ;
378+ assert_eq ! (
379+ 2 ,
380+ prioritization_fee
381+ . get_min_writable_account_fee( & write_account_a)
382+ . unwrap( )
383+ ) ;
358384 assert_eq ! (
359385 5 ,
360386 prioritization_fee
361- . get_writable_account_fee( & write_account_b)
387+ . get_min_writable_account_fee( & write_account_b)
388+ . unwrap( )
389+ ) ;
390+ assert_eq ! (
391+ 2 ,
392+ prioritization_fee
393+ . get_min_writable_account_fee( & write_account_c)
362394 . unwrap( )
363395 ) ;
364- assert ! ( prioritization_fee
365- . get_writable_account_fee( & write_account_c)
366- . is_none( ) ) ;
367396 }
368397 }
369398
0 commit comments