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