@@ -18,6 +18,7 @@ use std::collections::{HashMap, HashSet};
18
18
use std:: sync:: atomic:: { AtomicBool , Ordering } ;
19
19
use std:: sync:: { Arc , Mutex } ;
20
20
use std:: thread:: ThreadId ;
21
+ use std:: time:: Instant ;
21
22
use std:: { cmp, fs, mem} ;
22
23
23
24
use clarity:: vm:: analysis:: { CheckError , CheckErrors } ;
@@ -2211,6 +2212,15 @@ impl StacksBlockBuilder {
2211
2212
) ;
2212
2213
}
2213
2214
2215
+ // nakamoto miner tenure start heuristic:
2216
+ // mine an empty block so you can start your tenure quickly!
2217
+ if let Some ( tx) = initial_txs. first ( ) {
2218
+ if matches ! ( & tx. payload, TransactionPayload :: TenureChange ( _) ) {
2219
+ debug ! ( "Nakamoto miner heuristic: during tenure change blocks, produce a fast short block to begin tenure" ) ;
2220
+ return Ok ( ( false , tx_events) ) ;
2221
+ }
2222
+ }
2223
+
2214
2224
mempool. reset_nonce_cache ( ) ?;
2215
2225
mempool. estimate_tx_rates ( 100 , & block_limit, & stacks_epoch_id) ?;
2216
2226
@@ -2221,6 +2231,7 @@ impl StacksBlockBuilder {
2221
2231
2222
2232
let mut invalidated_txs = vec ! [ ] ;
2223
2233
let mut to_drop_and_blacklist = vec ! [ ] ;
2234
+ let mut update_timings = vec ! [ ] ;
2224
2235
2225
2236
let deadline = ts_start + u128:: from ( max_miner_time_ms) ;
2226
2237
let mut num_txs = 0 ;
@@ -2250,10 +2261,27 @@ impl StacksBlockBuilder {
2250
2261
if block_limit_hit == BlockLimitFunction :: LIMIT_REACHED {
2251
2262
return Ok ( None ) ;
2252
2263
}
2253
- if get_epoch_time_ms ( ) >= deadline {
2264
+ let time_now = get_epoch_time_ms ( ) ;
2265
+ if time_now >= deadline {
2254
2266
debug ! ( "Miner mining time exceeded ({} ms)" , max_miner_time_ms) ;
2255
2267
return Ok ( None ) ;
2256
2268
}
2269
+ if let Some ( time_estimate) = txinfo. metadata . time_estimate_ms {
2270
+ if time_now. saturating_add ( time_estimate. into ( ) ) > deadline {
2271
+ debug ! ( "Mining tx would cause us to exceed our deadline, skipping" ;
2272
+ "txid" => %txinfo. tx. txid( ) ,
2273
+ "deadline" => deadline,
2274
+ "now" => time_now,
2275
+ "estimate" => time_estimate) ;
2276
+ return Ok ( Some (
2277
+ TransactionResult :: skipped (
2278
+ & txinfo. tx ,
2279
+ "Transaction would exceed deadline." . into ( ) ,
2280
+ )
2281
+ . convert_to_event ( ) ,
2282
+ ) ) ;
2283
+ }
2284
+ }
2257
2285
2258
2286
// skip transactions early if we can
2259
2287
if considered. contains ( & txinfo. tx . txid ( ) ) {
@@ -2303,6 +2331,7 @@ impl StacksBlockBuilder {
2303
2331
considered. insert ( txinfo. tx . txid ( ) ) ;
2304
2332
num_considered += 1 ;
2305
2333
2334
+ let tx_start = Instant :: now ( ) ;
2306
2335
let tx_result = builder. try_mine_tx_with_len (
2307
2336
epoch_tx,
2308
2337
& txinfo. tx ,
@@ -2314,6 +2343,21 @@ impl StacksBlockBuilder {
2314
2343
let result_event = tx_result. convert_to_event ( ) ;
2315
2344
match tx_result {
2316
2345
TransactionResult :: Success ( TransactionSuccess { receipt, .. } ) => {
2346
+ if txinfo. metadata . time_estimate_ms . is_none ( ) {
2347
+ // use i64 to avoid running into issues when storing in
2348
+ // rusqlite.
2349
+ let time_estimate_ms: i64 = tx_start
2350
+ . elapsed ( )
2351
+ . as_millis ( )
2352
+ . try_into ( )
2353
+ . unwrap_or_else ( |_| i64:: MAX ) ;
2354
+ let time_estimate_ms: u64 = time_estimate_ms
2355
+ . try_into ( )
2356
+ // should be unreachable
2357
+ . unwrap_or_else ( |_| 0 ) ;
2358
+ update_timings. push ( ( txinfo. tx . txid ( ) , time_estimate_ms) ) ;
2359
+ }
2360
+
2317
2361
num_txs += 1 ;
2318
2362
if update_estimator {
2319
2363
if let Err ( e) = estimator. notify_event (
@@ -2386,6 +2430,12 @@ impl StacksBlockBuilder {
2386
2430
} ,
2387
2431
) ;
2388
2432
2433
+ if !update_timings. is_empty ( ) {
2434
+ if let Err ( e) = mempool. update_tx_time_estimates ( & update_timings) {
2435
+ warn ! ( "Error while updating time estimates for mempool" ; "err" => ?e) ;
2436
+ }
2437
+ }
2438
+
2389
2439
if to_drop_and_blacklist. len ( ) > 0 {
2390
2440
let _ = mempool. drop_and_blacklist_txs ( & to_drop_and_blacklist) ;
2391
2441
}
0 commit comments