@@ -12211,3 +12211,159 @@ fn v3_transaction_api_endpoint() {
12211
12211
12212
12212
run_loop_thread. join ( ) . unwrap ( ) ;
12213
12213
}
12214
+
12215
+ #[ test]
12216
+ #[ ignore]
12217
+ /// This test verifies that the miner can continue even if an insertion into
12218
+ /// the `considered_txs` table fails due to a foreign key failure.
12219
+ fn handle_considered_txs_foreign_key_failure ( ) {
12220
+ if env:: var ( "BITCOIND_TEST" ) != Ok ( "1" . into ( ) ) {
12221
+ return ;
12222
+ }
12223
+
12224
+ let ( mut naka_conf, _miner_account) = naka_neon_integration_conf ( None ) ;
12225
+ let prom_bind = "127.0.0.1:6000" . to_string ( ) ;
12226
+ naka_conf. node . prometheus_bind = Some ( prom_bind) ;
12227
+ naka_conf. miner . nakamoto_attempt_time_ms = 5_000 ;
12228
+ naka_conf. miner . tenure_cost_limit_per_block_percentage = None ;
12229
+ naka_conf. miner . mempool_walk_strategy = MemPoolWalkStrategy :: NextNonceWithHighestFeeRate ;
12230
+ // setup senders
12231
+ let send_amt = 1000 ;
12232
+ let send_fee = 180 ;
12233
+ let bad_sender_sk = Secp256k1PrivateKey :: from_seed ( & [ 30 ] ) ;
12234
+ let bad_sender_addr = tests:: to_addr ( & bad_sender_sk) ;
12235
+ naka_conf. add_initial_balance (
12236
+ PrincipalData :: from ( bad_sender_addr) . to_string ( ) ,
12237
+ send_amt + send_fee,
12238
+ ) ;
12239
+ let good_sender_sk = Secp256k1PrivateKey :: from_seed ( & [ 31 ] ) ;
12240
+ let good_sender_addr = tests:: to_addr ( & good_sender_sk) ;
12241
+ naka_conf. add_initial_balance (
12242
+ PrincipalData :: from ( good_sender_addr) . to_string ( ) ,
12243
+ ( send_amt + send_fee) * 2 ,
12244
+ ) ;
12245
+
12246
+ let sender_signer_sk = Secp256k1PrivateKey :: random ( ) ;
12247
+ let sender_signer_addr = tests:: to_addr ( & sender_signer_sk) ;
12248
+ let mut signers = TestSigners :: new ( vec ! [ sender_signer_sk] ) ;
12249
+ naka_conf. add_initial_balance ( PrincipalData :: from ( sender_signer_addr) . to_string ( ) , 100000 ) ;
12250
+ let recipient = PrincipalData :: from ( StacksAddress :: burn_address ( false ) ) ;
12251
+ let stacker_sk = setup_stacker ( & mut naka_conf) ;
12252
+ let http_origin = format ! ( "http://{}" , & naka_conf. node. rpc_bind) ;
12253
+
12254
+ test_observer:: spawn ( ) ;
12255
+ test_observer:: register_any ( & mut naka_conf) ;
12256
+
12257
+ let mut btcd_controller = BitcoinCoreController :: new ( naka_conf. clone ( ) ) ;
12258
+ btcd_controller
12259
+ . start_bitcoind ( )
12260
+ . expect ( "Failed starting bitcoind" ) ;
12261
+ let mut btc_regtest_controller = BitcoinRegtestController :: new ( naka_conf. clone ( ) , None ) ;
12262
+ btc_regtest_controller. bootstrap_chain ( 201 ) ;
12263
+
12264
+ let mut run_loop = boot_nakamoto:: BootRunLoop :: new ( naka_conf. clone ( ) ) . unwrap ( ) ;
12265
+ let run_loop_stopper = run_loop. get_termination_switch ( ) ;
12266
+ let Counters {
12267
+ blocks_processed,
12268
+ naka_submitted_commits : commits_submitted,
12269
+ ..
12270
+ } = run_loop. counters ( ) ;
12271
+ let counters = run_loop. counters ( ) ;
12272
+
12273
+ let coord_channel = run_loop. coordinator_channels ( ) ;
12274
+
12275
+ let run_loop_thread = thread:: spawn ( move || run_loop. start ( None , 0 ) ) ;
12276
+ wait_for_runloop ( & blocks_processed) ;
12277
+ boot_to_epoch_3 (
12278
+ & naka_conf,
12279
+ & blocks_processed,
12280
+ & [ stacker_sk] ,
12281
+ & [ sender_signer_sk] ,
12282
+ & mut Some ( & mut signers) ,
12283
+ & mut btc_regtest_controller,
12284
+ ) ;
12285
+
12286
+ info ! ( "Bootstrapped to Epoch-3.0 boundary, starting nakamoto miner" ) ;
12287
+
12288
+ info ! ( "Nakamoto miner started..." ) ;
12289
+ blind_signer ( & naka_conf, & signers, & counters) ;
12290
+
12291
+ wait_for_first_naka_block_commit ( 60 , & commits_submitted) ;
12292
+
12293
+ next_block_and_process_new_stacks_block ( & mut btc_regtest_controller, 60 , & coord_channel)
12294
+ . unwrap ( ) ;
12295
+
12296
+ let good_transfer_tx = make_stacks_transfer (
12297
+ & good_sender_sk,
12298
+ 0 ,
12299
+ send_fee,
12300
+ naka_conf. burnchain . chain_id ,
12301
+ & recipient,
12302
+ send_amt,
12303
+ ) ;
12304
+ submit_tx ( & http_origin, & good_transfer_tx) ;
12305
+
12306
+ wait_for ( 60 , || {
12307
+ let nonce = get_account ( & http_origin, & good_sender_addr) . nonce ;
12308
+ Ok ( nonce == 1 )
12309
+ } )
12310
+ . expect ( "Timed out waiting for first block" ) ;
12311
+
12312
+ let height_before = get_chain_info ( & naka_conf) . stacks_tip_height ;
12313
+
12314
+ // Initiate the transaction stall, then submit transactions.
12315
+ TEST_MINE_STALL . set ( true ) ;
12316
+ TEST_TX_STALL . set ( true ) ;
12317
+
12318
+ let bad_transfer_tx = make_stacks_transfer (
12319
+ & bad_sender_sk,
12320
+ 0 ,
12321
+ send_fee,
12322
+ naka_conf. burnchain . chain_id ,
12323
+ & recipient,
12324
+ send_amt,
12325
+ ) ;
12326
+ let txid = submit_tx ( & http_origin, & bad_transfer_tx) ;
12327
+ info ! ( "Bad transaction submitted: {txid}" ) ;
12328
+
12329
+ TEST_MINE_STALL . set ( false ) ;
12330
+
12331
+ // Sleep long enough to ensure that the miner has started processing the tx
12332
+ sleep_ms ( 5_000 ) ;
12333
+
12334
+ info ! ( "--------------------- Deleting tx from the mempool ---------------------" ) ;
12335
+ // Delete the bad transaction from the mempool.
12336
+ let mempool_db_path = format ! (
12337
+ "{}/nakamoto-neon/chainstate/mempool.sqlite" ,
12338
+ naka_conf. node. working_dir
12339
+ ) ;
12340
+ let conn = Connection :: open ( & mempool_db_path) . unwrap ( ) ;
12341
+ conn. execute ( "DELETE FROM mempool WHERE txid = ?" , [ txid] )
12342
+ . unwrap ( ) ;
12343
+
12344
+ // Unstall the transaction processing, so that the miner will resume.
12345
+ TEST_TX_STALL . set ( false ) ;
12346
+
12347
+ info ! ( "--------------------- Waiting for the block ---------------------" ) ;
12348
+
12349
+ // Now wait for the next block to be mined.
12350
+ wait_for ( 30 , || {
12351
+ let height = get_chain_info ( & naka_conf) . stacks_tip_height ;
12352
+ Ok ( height > height_before)
12353
+ } )
12354
+ . expect ( "Timed out waiting for block" ) ;
12355
+
12356
+ let good_sender_nonce = get_account ( & http_origin, & good_sender_addr) . nonce ;
12357
+ let bad_sender_nonce = get_account ( & http_origin, & bad_sender_addr) . nonce ;
12358
+
12359
+ assert_eq ! ( good_sender_nonce, 1 ) ;
12360
+ assert_eq ! ( bad_sender_nonce, 1 ) ;
12361
+
12362
+ coord_channel
12363
+ . lock ( )
12364
+ . expect ( "Mutex poisoned" )
12365
+ . stop_chains_coordinator ( ) ;
12366
+ run_loop_stopper. store ( false , Ordering :: SeqCst ) ;
12367
+
12368
+ run_loop_thread. join ( ) . unwrap ( ) ;
12369
+ }
0 commit comments