@@ -3760,164 +3760,6 @@ fn tx_replay_disagreement() {
3760
3760
miners.shutdown();
3761
3761
}
3762
3762
3763
- #[test]
3764
- #[ignore]
3765
- /// Demonstrates Tx Replay reject a proposal with partial replayed transactions,
3766
- /// when not due to a Tenure Extend
3767
- ///
3768
- /// The test flow is:
3769
- ///
3770
- /// - Boot to Epoch 3
3771
- /// - Mine 3 tenures
3772
- /// - Submit 2 STX transfers (Tx1, Tx2) in the last tenure
3773
- /// - Trigger a Bitcoin fork
3774
- /// - Verify that signers move into tx replay state [Tx1, Tx2]
3775
- /// - Force Miner to do partial replay (only Tx1)
3776
- /// - Signers should reject miner proposal
3777
- /// - In the end, Tx Replay Set remains unchanged [Tx1, Tx2]
3778
- fn tx_replay_rejected_for_invalid_proposal_due_to_partial_replay() {
3779
- if env::var("BITCOIND_TEST") != Ok("1".into()) {
3780
- return;
3781
- }
3782
-
3783
- let num_signers = 5;
3784
- let sender1_sk = Secp256k1PrivateKey::random();
3785
- let sender1_addr = tests::to_addr(&sender1_sk);
3786
- let send_amt = 100;
3787
- let send_fee = 180;
3788
- let num_txs = 2;
3789
- let signer_test: SignerTest<SpawnedSigner> = SignerTest::new_with_config_modifications(
3790
- num_signers,
3791
- vec![(sender1_addr, (send_amt + send_fee) * num_txs)],
3792
- |c| {
3793
- c.validate_with_replay_tx = true;
3794
- },
3795
- |node_config| {
3796
- node_config.miner.block_commit_delay = Duration::from_secs(1);
3797
- node_config.miner.replay_transactions = true;
3798
- },
3799
- None,
3800
- None,
3801
- );
3802
- let conf = &signer_test.running_nodes.conf;
3803
- let btc_controller = &signer_test.running_nodes.btc_regtest_controller;
3804
- let counters = &signer_test.running_nodes.counters;
3805
- let http_origin = format!("http://{}", &conf.node.rpc_bind);
3806
- let stacks_miner_pk = StacksPublicKey::from_private(&conf.miner.mining_key.unwrap());
3807
-
3808
- signer_test.boot_to_epoch_3();
3809
- info!("------------------------- Reached Epoch 3.0 -------------------------");
3810
-
3811
- let pre_fork_tenures = 3;
3812
- for i in 0..pre_fork_tenures {
3813
- info!("Mining pre-fork tenure {} of {pre_fork_tenures}", i + 1);
3814
- signer_test.mine_nakamoto_block(Duration::from_secs(30), true);
3815
- }
3816
- signer_test.check_signer_states_normal();
3817
-
3818
- // Make transfer txs (these will get forked)
3819
- let (sender1_tx1, sender1_nonce) = signer_test
3820
- .submit_transfer_tx(&sender1_sk, send_fee, send_amt)
3821
- .unwrap();
3822
- signer_test
3823
- .wait_for_nonce_increase(&sender1_addr, sender1_nonce)
3824
- .expect("Expect sender1 nonce increased");
3825
-
3826
- let (sender1_tx2, sender1_nonce) = signer_test
3827
- .submit_transfer_tx(&sender1_sk, send_fee, send_amt)
3828
- .unwrap();
3829
- signer_test
3830
- .wait_for_nonce_increase(&sender1_addr, sender1_nonce)
3831
- .expect("Expect sender1 nonce increased");
3832
-
3833
- let sender1_nonce = get_account(&http_origin, &sender1_addr).nonce;
3834
- assert_eq!(2, sender1_nonce);
3835
-
3836
- info!("------------------------- Triggering Bitcoin Fork -------------------------");
3837
- let tip = get_chain_info(&conf);
3838
- let burn_header_hash_to_fork = btc_controller.get_block_hash(tip.burn_block_height - 2);
3839
- btc_controller.invalidate_block(&burn_header_hash_to_fork);
3840
- btc_controller.build_next_block(3);
3841
- // note, we should still have normal signer states!
3842
- signer_test.check_signer_states_normal();
3843
-
3844
- info!("Wait for block off of shallow fork");
3845
- TEST_MINE_STALL.set(true);
3846
-
3847
- let submitted_commits = counters.naka_submitted_commits.clone();
3848
- // we need to mine some blocks to get back to being considered a frequent miner
3849
- for i in 0..3 {
3850
- let current_burn_height = get_chain_info(&conf).burn_block_height;
3851
- info!(
3852
- "Mining block #{i} to be considered a frequent miner";
3853
- "current_burn_height" => current_burn_height,
3854
- );
3855
- let commits_count = submitted_commits.load(Ordering::SeqCst);
3856
- next_block_and(btc_controller, 60, || {
3857
- Ok(submitted_commits.load(Ordering::SeqCst) > commits_count)
3858
- })
3859
- .unwrap();
3860
- }
3861
-
3862
- signer_test
3863
- .wait_for_signer_state_check(30, |state| {
3864
- let Some(tx_replay_set) = state.get_tx_replay_set() else {
3865
- return Ok(false);
3866
- };
3867
- let len_ok = tx_replay_set.len() == 2;
3868
- let txid_ok = tx_replay_set[0].txid().to_hex() == sender1_tx1
3869
- && tx_replay_set[1].txid().to_hex() == sender1_tx2;
3870
- Ok(len_ok && txid_ok)
3871
- })
3872
- .expect("Timed out waiting for tx replay set to be updated");
3873
-
3874
- // We should have forked 2 txs
3875
- let sender1_nonce_post_fork = get_account(&http_origin, &sender1_addr).nonce;
3876
- assert_eq!(0, sender1_nonce_post_fork);
3877
-
3878
- info!("------------------------- Partial Tx Replay (only Tx1) -------------------------");
3879
- test_observer::clear();
3880
- TEST_MINE_ALLOWED_REPLAY_TXS.set(vec![sender1_tx1.clone()]);
3881
- TEST_MINE_STALL.set(false);
3882
-
3883
- // First, a Tenure Change block mined
3884
- let tip = get_chain_info(&conf);
3885
- _ = wait_for_tenure_change_tx(30, TenureChangeCause::BlockFound, tip.stacks_tip_height + 1);
3886
-
3887
- // Then, expect next block proposal to contain just Tx1
3888
- let block_prop = wait_for_block_proposal(30, tip.stacks_tip_height + 2, &stacks_miner_pk)
3889
- .expect("Time out waiting for block proposal");
3890
- assert_eq!(1, block_prop.txs.len());
3891
- assert_eq!(sender1_tx1, block_prop.txs[0].txid().to_hex());
3892
-
3893
- // Signers should reject this proposal, because not justified (e.g. tenure extend)
3894
- wait_for_block_global_rejection_with_reject_reason(
3895
- 30,
3896
- block_prop.header.signer_signature_hash(),
3897
- num_signers,
3898
- RejectReason::ValidationFailed(ValidateRejectCode::InvalidTransactionReplay),
3899
- )
3900
- .expect("Time out waiting for global block rejection due to invalid tx replay");
3901
-
3902
- // Tx Replay Set remains untouched
3903
- signer_test
3904
- .wait_for_signer_state_check(30, |state| {
3905
- let Some(tx_replay_set) = state.get_tx_replay_set() else {
3906
- return Ok(false);
3907
- };
3908
- let len_ok = tx_replay_set.len() == 2;
3909
- let txid_ok = tx_replay_set[0].txid().to_hex() == sender1_tx1
3910
- && tx_replay_set[1].txid().to_hex() == sender1_tx2;
3911
- Ok(len_ok && txid_ok)
3912
- })
3913
- .expect("Timed out waiting for tx replay set to be updated");
3914
-
3915
- let sender1_nonce = get_account(&http_origin, &sender1_addr).nonce;
3916
- assert_eq!(0, sender1_nonce);
3917
-
3918
- signer_test.shutdown();
3919
- }
3920
-
3921
3763
#[test]
3922
3764
#[ignore]
3923
3765
/// Demonstrates that transaction replay can be "solved" using mempool transactions,
0 commit comments