@@ -13376,3 +13376,168 @@ fn signers_send_state_message_updates() {
13376
13376
);
13377
13377
miners.shutdown();
13378
13378
}
13379
+
13380
+ #[test]
13381
+ #[ignore]
13382
+ /// Verify that the mempool caching is working as expected
13383
+ ///
13384
+ /// This test will boot to epoch 3 then pause mining and:
13385
+ /// 1. Set the signers to reject all blocks
13386
+ /// 2. Submit a transfer from the sender to the recipient
13387
+ /// 3. Wait for this block to be proposed
13388
+ /// 4. Pause mining
13389
+ /// 5. Wait for block rejection
13390
+ /// 6. Check the nonce cache to see if it cached the nonce (it is paused before
13391
+ /// the cache is cleared).
13392
+ /// 7. Set the signers to accept blocks and unpause mining
13393
+ /// 8. Wait for the block to be mined
13394
+ /// 9. Check the nonce cache and verify that it has correctly cached the nonce
13395
+ /// 10. Submit a second transfer and wait for it to be mined
13396
+ fn verify_mempool_caches() {
13397
+ if env::var("BITCOIND_TEST") != Ok("1".into()) {
13398
+ return;
13399
+ }
13400
+ tracing_subscriber::registry()
13401
+ .with(fmt::layer())
13402
+ .with(EnvFilter::from_default_env())
13403
+ .init();
13404
+
13405
+ info!("------------------------- Test Setup -------------------------");
13406
+ let num_signers = 5;
13407
+ let sender_sk = Secp256k1PrivateKey::random();
13408
+ let sender_addr = tests::to_addr(&sender_sk);
13409
+ let send_amt = 100;
13410
+ let send_fee = 180;
13411
+ let recipient = PrincipalData::from(StacksAddress::burn_address(false));
13412
+ let mut signer_test: SignerTest<SpawnedSigner> =
13413
+ SignerTest::new(num_signers, vec![(sender_addr, (send_amt + send_fee) * 3)]);
13414
+ let http_origin = format!("http://{}", &signer_test.running_nodes.conf.node.rpc_bind);
13415
+ let miner_sk = signer_test.running_nodes.conf.miner.mining_key.unwrap();
13416
+ let miner_pk = StacksPublicKey::from_private(&miner_sk);
13417
+
13418
+ signer_test.boot_to_epoch_3();
13419
+
13420
+ signer_test.mine_nakamoto_block(Duration::from_secs(60), true);
13421
+
13422
+ let info = get_chain_info(&signer_test.running_nodes.conf);
13423
+ let block_height_before = info.stacks_tip_height;
13424
+
13425
+ // All signers reject all blocks
13426
+ let rejecting_signers: Vec<_> = signer_test
13427
+ .signer_stacks_private_keys
13428
+ .iter()
13429
+ .map(StacksPublicKey::from_private)
13430
+ .collect();
13431
+ TEST_REJECT_ALL_BLOCK_PROPOSAL.set(rejecting_signers);
13432
+
13433
+ // submit a tx so that the miner will mine a block
13434
+ let transfer_tx = make_stacks_transfer(
13435
+ &sender_sk,
13436
+ 0,
13437
+ send_fee,
13438
+ signer_test.running_nodes.conf.burnchain.chain_id,
13439
+ &recipient,
13440
+ send_amt,
13441
+ );
13442
+ submit_tx(&http_origin, &transfer_tx);
13443
+
13444
+ info!("Submitted transfer tx and waiting for block proposal");
13445
+ let block = wait_for_block_proposal(30, block_height_before + 1, &miner_pk)
13446
+ .expect("Timed out waiting for block proposal");
13447
+
13448
+ // Stall the miners so that this block is not re-proposed after being rejected
13449
+ TEST_MINE_STALL.set(true);
13450
+
13451
+ // Wait for rejections
13452
+ wait_for_block_rejections(30, block.header.signer_signature_hash(), num_signers)
13453
+ .expect("Failed to get expected rejections for block");
13454
+
13455
+ // Check the nonce cache -- it should have the nonce cached because it will
13456
+ // only be cleared after the miner is unpaused.
13457
+ let mempool_db_path = format!(
13458
+ "{}/nakamoto-neon/chainstate/mempool.sqlite",
13459
+ signer_test.running_nodes.conf.node.working_dir
13460
+ );
13461
+ let conn = Connection::open(&mempool_db_path).unwrap();
13462
+ let result = conn
13463
+ .query_row(
13464
+ "SELECT nonce FROM nonces WHERE address = ?1;",
13465
+ [&sender_addr],
13466
+ |row| {
13467
+ let nonce: u64 = row.get(0)?;
13468
+ Ok(nonce)
13469
+ },
13470
+ )
13471
+ .expect("Failed to get nonce from cache");
13472
+ assert_eq!(result, 1);
13473
+
13474
+ info!("Nonce cache has the expected nonce");
13475
+
13476
+ // Set signers to accept and unpause the miners
13477
+ TEST_REJECT_ALL_BLOCK_PROPOSAL.set(vec![]);
13478
+ TEST_MINE_STALL.set(false);
13479
+
13480
+ info!("Unpausing miners and waiting for block to be mined");
13481
+
13482
+ // Wait for the block to be mined
13483
+ wait_for(60, || {
13484
+ let is_next_block = test_observer::get_blocks()
13485
+ .last()
13486
+ .and_then(|block| block["block_height"].as_u64())
13487
+ .map_or(false, |h| h == block_height_before + 1);
13488
+
13489
+ Ok(is_next_block)
13490
+ })
13491
+ .expect("Timed out waiting for block to be mined");
13492
+
13493
+ // Check the nonce cache again -- it should still have the nonce cached
13494
+ let result = conn
13495
+ .query_row(
13496
+ "SELECT nonce FROM nonces WHERE address = ?1;",
13497
+ [&sender_addr],
13498
+ |row| {
13499
+ let nonce: u64 = row.get(0)?;
13500
+ Ok(nonce)
13501
+ },
13502
+ )
13503
+ .expect("Failed to get nonce from cache");
13504
+ assert_eq!(result, 1);
13505
+
13506
+ info!("Nonce cache has the expected nonce after successfully mining block");
13507
+
13508
+ let transfer_tx = make_stacks_transfer(
13509
+ &sender_sk,
13510
+ 1,
13511
+ send_fee,
13512
+ signer_test.running_nodes.conf.burnchain.chain_id,
13513
+ &recipient,
13514
+ send_amt,
13515
+ );
13516
+ submit_tx(&http_origin, &transfer_tx);
13517
+
13518
+ info!("Waiting for the second block to be mined");
13519
+ wait_for(60, || {
13520
+ let blocks = test_observer::get_blocks();
13521
+
13522
+ // Look for a block with expected height
13523
+ let Some(block) = blocks
13524
+ .iter()
13525
+ .find(|block| block["block_height"].as_u64() == Some(block_height_before + 2))
13526
+ else {
13527
+ return Ok(false); // Keep waiting if the block hasn't been observed yet
13528
+ };
13529
+
13530
+ // This new block should have just the one new transfer
13531
+ let transfers_included_in_block = transfers_in_block(block);
13532
+ if transfers_included_in_block == 1 {
13533
+ Ok(true)
13534
+ } else {
13535
+ Err(format!(
13536
+ "Expected only one transfer in block, found {transfers_included_in_block}"
13537
+ ))
13538
+ }
13539
+ })
13540
+ .expect("Timed out waiting for block");
13541
+
13542
+ signer_test.shutdown();
13543
+ }
0 commit comments