Skip to content

Commit 3c7769d

Browse files
committed
prepare for integration test
1 parent e28e22b commit 3c7769d

File tree

1 file changed

+230
-0
lines changed
  • testnet/stacks-node/src/tests/signer

1 file changed

+230
-0
lines changed

testnet/stacks-node/src/tests/signer/v0.rs

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,63 @@ impl MultipleMinerTest {
766766
Ok(txid)
767767
}
768768

769+
pub fn send_contract_publish(&mut self, contract_name: &str, contract_src: &str) -> String {
770+
let http_origin = format!(
771+
"http://{}",
772+
&self.signer_test.running_nodes.conf.node.rpc_bind
773+
);
774+
let contract_tx = make_contract_publish(
775+
&self.sender_sk,
776+
self.sender_nonce,
777+
self.send_fee,
778+
self.signer_test.running_nodes.conf.burnchain.chain_id,
779+
contract_name,
780+
contract_src,
781+
);
782+
self.sender_nonce += 1;
783+
submit_tx(&http_origin, &contract_tx)
784+
}
785+
786+
/// Sends a contract publish tx to the stacks node and waits for the stacks node to mine it
787+
/// Returns the txid of the transfer tx.
788+
pub fn send_and_mine_contract_publish(
789+
&mut self,
790+
contract_name: &str,
791+
contract_src: &str,
792+
timeout_secs: u64,
793+
) -> Result<String, String> {
794+
let stacks_height_before = self.get_peer_stacks_tip_height();
795+
let txid = self.send_contract_publish(contract_name, contract_src);
796+
wait_for(timeout_secs, || {
797+
Ok(self.get_peer_stacks_tip_height() > stacks_height_before)
798+
})?;
799+
Ok(txid)
800+
}
801+
802+
pub fn send_contract_call(
803+
&mut self,
804+
contract_name: &str,
805+
function_name: &str,
806+
function_args: &[clarity::vm::Value],
807+
) -> String {
808+
let http_origin = format!(
809+
"http://{}",
810+
&self.signer_test.running_nodes.conf.node.rpc_bind
811+
);
812+
let contract_tx = make_contract_call(
813+
&self.sender_sk,
814+
self.sender_nonce,
815+
self.send_fee,
816+
self.signer_test.running_nodes.conf.burnchain.chain_id,
817+
&tests::to_addr(&self.sender_sk),
818+
contract_name,
819+
function_name,
820+
function_args,
821+
);
822+
self.sender_nonce += 1;
823+
submit_tx(&http_origin, &contract_tx)
824+
}
825+
769826
/// Return the Peer Info from node 1
770827
pub fn get_peer_info(&self) -> PeerInfo {
771828
self.signer_test.get_peer_info()
@@ -935,6 +992,23 @@ fn last_block_contains_tenure_change_tx(cause: TenureChangeCause) -> bool {
935992
}
936993
}
937994

995+
// Returns whether the last block in the test observer contains a tenure change
996+
/// transaction with the given cause.
997+
fn last_block_contains_txid(txid: &str) -> bool {
998+
let blocks = test_observer::get_blocks();
999+
let last_block = &blocks.last().unwrap();
1000+
let transactions = last_block["transactions"].as_array().unwrap();
1001+
for tx in transactions {
1002+
let raw_tx = tx["raw_tx"].as_str().unwrap();
1003+
let tx_bytes = hex_bytes(&raw_tx[2..]).unwrap();
1004+
let parsed = StacksTransaction::consensus_deserialize(&mut &tx_bytes[..]).unwrap();
1005+
if parsed.txid().to_string() == txid {
1006+
return true;
1007+
}
1008+
}
1009+
false
1010+
}
1011+
9381012
/// Asserts that the last block in the test observer contains a tenure change with the given cause.
9391013
fn verify_last_block_contains_tenure_change_tx(cause: TenureChangeCause) {
9401014
assert!(last_block_contains_tenure_change_tx(cause));
@@ -12438,3 +12512,159 @@ fn signer_can_accept_rejected_block() {
1243812512

1243912513
signer_test.shutdown();
1244012514
}
12515+
12516+
/// Test a scenario where:
12517+
/// Two miners boot to Nakamoto.
12518+
/// Sortition occurs. Miner 1 wins.
12519+
/// Miner 1 proposes a block N
12520+
/// Signers accept and the stacks tip advances to N
12521+
/// Miner 1's block commits are paused so it cannot confirm the next tenure.
12522+
/// Sortition occurs. Miner 2 wins.
12523+
/// Miner 2 successfully mines blocks N+1, N+2, and N+3
12524+
/// Sortition occurs quickly, within first_proposal_burn_block_timing_secs. Miner 1 wins.
12525+
/// Miner 1 proposes block N+1' but gets rejected as more than one block has been mined in the current tenure (by miner2)
12526+
#[test]
12527+
#[ignore]
12528+
fn miner_rejection_by_contract_call_execution_time_expired() {
12529+
if env::var("BITCOIND_TEST") != Ok("1".into()) {
12530+
return;
12531+
}
12532+
12533+
let num_signers = 5;
12534+
let num_txs = 3;
12535+
12536+
let mut miners = MultipleMinerTest::new_with_config_modifications(
12537+
num_signers,
12538+
num_txs,
12539+
|signer_config| {
12540+
// Lets make sure we never time out since we need to stall some things to force our scenario
12541+
signer_config.block_proposal_validation_timeout = Duration::from_secs(1800);
12542+
signer_config.tenure_last_block_proposal_timeout = Duration::from_secs(1800);
12543+
signer_config.first_proposal_burn_block_timing = Duration::from_secs(1800);
12544+
},
12545+
|config| config.miner.max_execution_time = Some(0),
12546+
|config| config.miner.max_execution_time = None,
12547+
);
12548+
let rl1_skip_commit_op = miners
12549+
.signer_test
12550+
.running_nodes
12551+
.counters
12552+
.naka_skip_commit_op
12553+
.clone();
12554+
let rl2_skip_commit_op = miners.rl2_counters.naka_skip_commit_op.clone();
12555+
12556+
let (conf_1, _) = miners.get_node_configs();
12557+
let (miner_pkh_1, miner_pkh_2) = miners.get_miner_public_key_hashes();
12558+
let (miner_pk_1, miner_pk_2) = miners.get_miner_public_keys();
12559+
12560+
info!("------------------------- Pause Miner 2's Block Commits -------------------------");
12561+
12562+
// Make sure Miner 2 cannot win a sortition at first.
12563+
rl2_skip_commit_op.set(true);
12564+
12565+
miners.boot_to_epoch_3();
12566+
12567+
let burnchain = conf_1.get_burnchain();
12568+
let sortdb = burnchain.open_sortition_db(true).unwrap();
12569+
12570+
info!("------------------------- Pause Miner 1's Block Commits -------------------------");
12571+
rl1_skip_commit_op.set(true);
12572+
12573+
// First, lets deploy the contract
12574+
let dummy_contract_src = "
12575+
(define-public (run-f)
12576+
(ok (1)))
12577+
";
12578+
12579+
info!("------------------------- Miner 1 Mines a Nakamoto Block N -------------------------");
12580+
miners
12581+
.mine_bitcoin_block_and_tenure_change_tx(&sortdb, TenureChangeCause::BlockFound, 60)
12582+
.expect("Failed to mine BTC block followed by Block N");
12583+
12584+
// First, lets deploy the contract
12585+
let _contract_publish_txid =
12586+
miners.send_and_mine_contract_publish("dummy-contract", dummy_contract_src, 60);
12587+
12588+
let stacks_height_before = miners.get_peer_stacks_tip_height();
12589+
12590+
// try calling it (has to fail)
12591+
let contract_call_txid = miners.send_contract_call("dummy-contract", "f", &[]);
12592+
12593+
let miner_1_block_n =
12594+
wait_for_block_pushed_by_miner_key(30, stacks_height_before + 1, &miner_pk_1)
12595+
.expect("Failed to get block N+1");
12596+
12597+
assert_eq!(last_block_contains_txid(&contract_call_txid), false);
12598+
12599+
// assure we have a successful sortition that miner 1 won
12600+
verify_sortition_winner(&sortdb, &miner_pkh_1);
12601+
12602+
info!("------------------------- Miner 2 Submits a Block Commit -------------------------");
12603+
miners.submit_commit_miner_2(&sortdb);
12604+
12605+
info!("------------------------- Pause Miner 2's Block Mining -------------------------");
12606+
TEST_MINE_STALL.set(true);
12607+
12608+
info!("------------------------- Mine Tenure -------------------------");
12609+
miners
12610+
.mine_bitcoin_blocks_and_confirm(&sortdb, 1, 60)
12611+
.expect("Failed to mine BTC block");
12612+
12613+
info!("------------------------- Miner 1 Submits a Block Commit -------------------------");
12614+
miners.submit_commit_miner_1(&sortdb);
12615+
12616+
info!("------------------------- Miner 2 Mines Block N+2 -------------------------");
12617+
12618+
TEST_MINE_STALL.set(false);
12619+
let _ = wait_for_block_pushed_by_miner_key(30, block_n_height + 1, &miner_pk_2)
12620+
.expect("Failed to get block N+1");
12621+
12622+
// assure we have a successful sortition that miner 2 won
12623+
verify_sortition_winner(&sortdb, &miner_pkh_2);
12624+
12625+
assert_eq!(
12626+
get_chain_info(&conf_1).stacks_tip_height,
12627+
block_n_height + 1
12628+
);
12629+
12630+
info!("------------------------- Miner 2 Mines N+2 and N+3 -------------------------");
12631+
miners
12632+
.send_and_mine_transfer_tx(30)
12633+
.expect("Failed to send and mine transfer tx");
12634+
miners
12635+
.send_and_mine_transfer_tx(30)
12636+
.expect("Failed to send and mine transfer tx");
12637+
assert_eq!(
12638+
get_chain_info(&conf_1).stacks_tip_height,
12639+
block_n_height + 3
12640+
);
12641+
12642+
info!("------------------------- Miner 1 Wins the Next Tenure, Mines N+3 -------------------------");
12643+
miners.btc_regtest_controller_mut().build_next_block(1);
12644+
12645+
let _ = wait_for_block_pushed_by_miner_key(30, block_n_height + 1, &miner_pk_2)
12646+
.expect("Failed to get block N+3");
12647+
12648+
// check N+2 contains the contract call (previously rejected by miner 1)
12649+
let miner1_blocks_after_boot_to_epoch3 = get_nakamoto_headers(&conf_1)
12650+
.into_iter()
12651+
.filter(|block| {
12652+
// skip first nakamoto block
12653+
if block.stacks_block_height == stacks_height_before {
12654+
return false;
12655+
}
12656+
let nakamoto_block_header = block.anchored_header.as_stacks_nakamoto().unwrap();
12657+
miner_pk_1
12658+
.verify(
12659+
nakamoto_block_header.miner_signature_hash().as_bytes(),
12660+
&nakamoto_block_header.miner_signature,
12661+
)
12662+
.unwrap()
12663+
})
12664+
.count();
12665+
12666+
assert_eq!(miner1_blocks_after_boot_to_epoch3, 1);
12667+
12668+
info!("------------------------- Shutdown -------------------------");
12669+
miners.shutdown();
12670+
}

0 commit comments

Comments
 (0)