Skip to content

Commit 15d88dc

Browse files
committed
improved tests
1 parent e42a410 commit 15d88dc

File tree

3 files changed

+130
-18
lines changed

3 files changed

+130
-18
lines changed

stacks-node/src/tests/nakamoto_integrations.rs

Lines changed: 125 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ use std::thread::JoinHandle;
2323
use std::time::{Duration, Instant};
2424
use std::{env, thread};
2525

26+
use clarity::boot_util::boot_code_addr;
2627
use clarity::vm::ast::ASTRules;
2728
use clarity::vm::costs::ExecutionCost;
29+
use clarity::vm::representations::ContractName;
2830
use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier};
2931
use clarity::vm::{ClarityName, ClarityVersion, Value};
3032
use http_types::headers::AUTHORIZATION;
@@ -64,8 +66,8 @@ use stacks::chainstate::stacks::miner::{
6466
use stacks::chainstate::stacks::{
6567
SinglesigHashMode, SinglesigSpendingCondition, StacksTransaction, TenureChangeCause,
6668
TenureChangePayload, TransactionAnchorMode, TransactionAuth, TransactionPayload,
67-
TransactionPostConditionMode, TransactionPublicKeyEncoding, TransactionSpendingCondition,
68-
TransactionVersion, MAX_BLOCK_LEN,
69+
TransactionPostConditionMode, TransactionPublicKeyEncoding, TransactionSmartContract,
70+
TransactionSpendingCondition, TransactionVersion, MAX_BLOCK_LEN,
6971
};
7072
use stacks::config::{EventKeyType, InitialBalance};
7173
use stacks::core::mempool::{MemPoolWalkStrategy, MAXIMUM_MEMPOOL_TX_CHAINING};
@@ -266,14 +268,32 @@ impl TestSigningChannel {
266268
/// Assert that the block events captured by the test observer
267269
/// all match the miner heuristic of *exclusively* including the
268270
/// tenure change transaction in tenure changing blocks.
269-
pub fn check_nakamoto_empty_block_heuristics() {
271+
pub fn check_nakamoto_empty_block_heuristics(mainnet: bool) {
270272
let blocks = test_observer::get_blocks();
271273
for block in blocks.iter() {
272274
// if its not a nakamoto block, don't check anything
273275
if block.get("miner_signature").is_none() {
274276
continue;
275277
}
278+
276279
let txs = test_observer::parse_transactions(block);
280+
let has_sip_031_boot_contract_deploy = txs.iter().any(|tx| match &tx.payload {
281+
TransactionPayload::SmartContract(
282+
TransactionSmartContract {
283+
name: contract_name,
284+
..
285+
},
286+
..,
287+
) => {
288+
contract_name == &ContractName::try_from(SIP_031_NAME.to_string()).unwrap()
289+
&& tx.origin_address() == boot_code_addr(mainnet)
290+
}
291+
_ => false,
292+
});
293+
// skip sip-031 boot contract
294+
if has_sip_031_boot_contract_deploy {
295+
continue;
296+
}
277297
let has_tenure_change = txs.iter().any(|tx| {
278298
matches!(
279299
tx.payload,
@@ -749,6 +769,33 @@ pub fn next_block_and_process_new_stacks_block(
749769
})
750770
}
751771

772+
/// Mine a bitcoin block, and wait until:
773+
/// number_of_blocks has been processed by the coordinator
774+
pub fn next_block_and_process_new_stacks_blocks(
775+
btc_controller: &BitcoinRegtestController,
776+
number_of_blocks: u32,
777+
timeout_secs: u64,
778+
coord_channels: &Arc<Mutex<CoordinatorChannels>>,
779+
) -> Result<(), String> {
780+
for _ in 0..number_of_blocks {
781+
let blocks_processed_before = coord_channels
782+
.lock()
783+
.expect("Mutex poisoned")
784+
.get_stacks_blocks_processed();
785+
next_block_and(btc_controller, timeout_secs, || {
786+
let blocks_processed = coord_channels
787+
.lock()
788+
.expect("Mutex poisoned")
789+
.get_stacks_blocks_processed();
790+
if blocks_processed > blocks_processed_before {
791+
return Ok(true);
792+
}
793+
Ok(false)
794+
})?;
795+
}
796+
Ok(())
797+
}
798+
752799
/// Mine a bitcoin block, and wait until:
753800
/// (1) a new block has been processed by the coordinator
754801
/// (2) 2 block commits have been issued ** or ** more than 10 seconds have
@@ -1703,7 +1750,7 @@ fn simple_neon_integration() {
17031750
.expect("Prometheus metrics did not update");
17041751
}
17051752

1706-
check_nakamoto_empty_block_heuristics();
1753+
check_nakamoto_empty_block_heuristics(naka_conf.is_mainnet());
17071754

17081755
coord_channel
17091756
.lock()
@@ -1919,7 +1966,7 @@ fn restarting_miner() {
19191966
panic!("Missing the following burn blocks: {missing_is_error:?}");
19201967
}
19211968

1922-
check_nakamoto_empty_block_heuristics();
1969+
check_nakamoto_empty_block_heuristics(naka_conf.is_mainnet());
19231970

19241971
assert!(tip.stacks_block_height >= block_height_pre_3_0 + 4);
19251972
}
@@ -2161,7 +2208,7 @@ fn flash_blocks_on_epoch_3_FLAKY() {
21612208
// Verify blocks before and after the gap
21622209
test_observer::contains_burn_block_range(220..=(gap_start - 1)).unwrap();
21632210
test_observer::contains_burn_block_range((gap_end + 1)..=bhh).unwrap();
2164-
check_nakamoto_empty_block_heuristics();
2211+
check_nakamoto_empty_block_heuristics(naka_conf.is_mainnet());
21652212

21662213
info!("Verified burn block ranges, including expected gap for flash blocks");
21672214
info!("Confirmed that the gap includes the Epoch 3.0 activation height (Bitcoin block height): {epoch_3_start_height}");
@@ -2341,7 +2388,7 @@ fn mine_multiple_per_tenure_integration() {
23412388
"Should have mined (1 + interim_blocks_per_tenure) * tenure_count nakamoto blocks"
23422389
);
23432390

2344-
check_nakamoto_empty_block_heuristics();
2391+
check_nakamoto_empty_block_heuristics(naka_conf.is_mainnet());
23452392

23462393
coord_channel
23472394
.lock()
@@ -2593,7 +2640,7 @@ fn multiple_miners() {
25932640
"Should have mined (1 + interim_blocks_per_tenure) * tenure_count nakamoto blocks"
25942641
);
25952642

2596-
check_nakamoto_empty_block_heuristics();
2643+
check_nakamoto_empty_block_heuristics(naka_conf.is_mainnet());
25972644

25982645
coord_channel
25992646
.lock()
@@ -2934,7 +2981,7 @@ fn correct_burn_outs() {
29342981
assert_eq!(signer_weight, 1, "The signer should have a weight of 1, indicating they stacked the minimum stacking amount");
29352982
}
29362983

2937-
check_nakamoto_empty_block_heuristics();
2984+
check_nakamoto_empty_block_heuristics(naka_conf.is_mainnet());
29382985

29392986
run_loop_thread.join().unwrap();
29402987
}
@@ -9792,7 +9839,7 @@ fn skip_mining_long_tx() {
97929839
let bhh = u64::from(tip.burn_header_height);
97939840
check_nakamoto_no_missing_blocks(&naka_conf, 220..=bhh);
97949841

9795-
check_nakamoto_empty_block_heuristics();
9842+
check_nakamoto_empty_block_heuristics(naka_conf.is_mainnet());
97969843

97979844
coord_channel
97989845
.lock()
@@ -12845,6 +12892,10 @@ fn test_sip_031_activation() {
1284512892
if burn_block_height
1284612893
== naka_conf.burnchain.epochs.clone().unwrap()[StacksEpochId::Epoch32].start_height
1284712894
{
12895+
println!(
12896+
"\n\nOOPS {:?}\n\n",
12897+
block.get("transactions").unwrap().as_array().unwrap()
12898+
);
1284812899
// the first transaction is the coinbase
1284912900
coinbase_txid = Some(
1285012901
block
@@ -13080,7 +13131,7 @@ fn test_sip_031_last_phase() {
1308013131
);
1308113132

1308213133
// get current liquidity
13083-
let sip_031_current_liquid_ustx = chainstate
13134+
let _sip_031_current_liquid_ustx = chainstate
1308413135
.with_read_only_clarity_tx(
1308513136
&sortdb
1308613137
.index_handle_at_block(&chainstate, &latest_stacks_block_id)
@@ -13093,16 +13144,76 @@ fn test_sip_031_last_phase() {
1309313144
// 50 more tenures...
1309413145
for _ in 0..50 {
1309513146
let commits_before = commits_submitted.load(Ordering::SeqCst);
13096-
next_block_and_process_new_stacks_block(&mut btc_regtest_controller, 60, &coord_channel)
13097-
.unwrap();
13147+
next_block_and_process_new_stacks_blocks(
13148+
&mut btc_regtest_controller,
13149+
3,
13150+
60,
13151+
&coord_channel,
13152+
)
13153+
.unwrap();
1309813154
wait_for(20, || {
1309913155
Ok(commits_submitted.load(Ordering::SeqCst) > commits_before)
1310013156
})
1310113157
.unwrap();
13158+
}
1310213159

13103-
let node_info = get_chain_info_opt(&naka_conf).unwrap();
13160+
let mut total_minted_and_transferred: u128 = 0;
13161+
13162+
for block in test_observer::get_blocks() {
13163+
let burn_block_height = block.get("burn_block_height").unwrap().as_u64().unwrap();
13164+
13165+
let sip_031_mint_and_transfer_amount =
13166+
SIP031EmissionInterval::get_sip_031_emission_at_height(
13167+
burn_block_height,
13168+
naka_conf.is_mainnet(),
13169+
);
13170+
13171+
let events = block.get("events").unwrap().as_array().unwrap();
13172+
for event in events {
13173+
if let Some(mint_event) = event.get("stx_mint_event") {
13174+
let minted_amount =
13175+
u128::try_from(mint_event.get("amount").unwrap().as_u64().unwrap()).unwrap();
13176+
assert_eq!(sip_031_mint_and_transfer_amount, minted_amount);
13177+
total_minted_and_transferred += minted_amount;
13178+
break;
13179+
}
13180+
}
13181+
total_minted_and_transferred += sip_031_mint_and_transfer_amount;
1310413182
}
1310513183

13184+
// (100_000 + 200_000 + 300_000) * 5
13185+
assert_eq!(total_minted_and_transferred, 3_000_000);
13186+
13187+
let latest_stacks_block_id = get_latest_block_proposal(&naka_conf, &sortdb)
13188+
.unwrap()
13189+
.0
13190+
.block_id();
13191+
13192+
// get sip-031 boot contract balance (will be checked for 200_000_000 STX + total_minted_and_transferred)
13193+
let sip_031_boot_contract_balance = chainstate.with_read_only_clarity_tx(
13194+
&sortdb
13195+
.index_handle_at_block(&chainstate, &latest_stacks_block_id)
13196+
.unwrap(),
13197+
&latest_stacks_block_id,
13198+
|conn| {
13199+
conn.with_clarity_db_readonly(|db| {
13200+
db.get_account_stx_balance(&PrincipalData::Contract(boot_code_id(
13201+
SIP_031_NAME,
13202+
naka_conf.is_mainnet(),
13203+
)))
13204+
})
13205+
},
13206+
);
13207+
13208+
assert_eq!(
13209+
sip_031_boot_contract_balance,
13210+
Some(Ok(STXBalance::Unlocked {
13211+
amount: SIP_031_INITIAL_MINT + total_minted_and_transferred
13212+
}))
13213+
);
13214+
13215+
set_test_sip_031_emission_schedule(None);
13216+
1310613217
coord_channel
1310713218
.lock()
1310813219
.expect("Mutex poisoned")

stacks-node/src/tests/signer/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1397,7 +1397,7 @@ impl<Z: SpawnedSignerTrait> SignerTest<Z> {
13971397
}
13981398

13991399
fn shutdown_and_make_snapshot(mut self, needs_snapshot: bool) {
1400-
check_nakamoto_empty_block_heuristics();
1400+
check_nakamoto_empty_block_heuristics(self.stacks_client.mainnet);
14011401

14021402
self.running_nodes
14031403
.coord_channel

stackslib/src/chainstate/nakamoto/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4834,14 +4834,15 @@ impl NakamotoChainState {
48344834
&mut clarity_tx,
48354835
chain_tip_burn_header_height,
48364836
) {
4837-
if let Some(receipt) = tx_receipts.get_mut(0) {
4837+
// for sip-031 we are safe in assuming coinbase is at index 1
4838+
if let Some(receipt) = tx_receipts.get_mut(1) {
48384839
if receipt.is_coinbase_tx() {
48394840
receipt.events.push(event);
48404841
} else {
4841-
warn!("Unable to attach SIP-031 mint events, block's first transaction is not a coinbase transaction")
4842+
error!("Unable to attach SIP-031 mint events, block's second transaction is not a coinbase transaction")
48424843
}
48434844
} else {
4844-
warn!("Unable to attach SIP-031 mint events, block's first transaction not available")
4845+
error!("Unable to attach SIP-031 mint events, block's second transaction not available")
48454846
}
48464847
}
48474848
}

0 commit comments

Comments
 (0)