Skip to content

Commit 2be69cb

Browse files
authored
Merge pull request #5111 from stacks-network/bugfix/end-of-tenure
Remove deadlock introduced in commit 1d83617
2 parents 42fd891 + 56746d0 commit 2be69cb

File tree

5 files changed

+57
-41
lines changed

5 files changed

+57
-41
lines changed

stackslib/src/chainstate/nakamoto/coordinator/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ impl<'a, T: BlockEventDispatcher> OnChainRewardSetProvider<'a, T> {
188188
debug_log: bool,
189189
) -> Result<RewardSet, Error> {
190190
let Some(reward_set_block) = NakamotoChainState::get_header_by_coinbase_height(
191-
&mut chainstate.index_tx_begin(),
191+
&mut chainstate.index_conn(),
192192
block_id,
193193
coinbase_height_of_calculation,
194194
)?

stackslib/src/chainstate/nakamoto/coordinator/tests.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,8 +1086,6 @@ fn test_nakamoto_chainstate_getters() {
10861086
let chainstate = &mut peer.stacks_node.as_mut().unwrap().chainstate;
10871087
let sort_db = peer.sortdb.as_ref().unwrap();
10881088

1089-
let (mut stacks_db_tx, _) = chainstate.chainstate_tx_begin().unwrap();
1090-
10911089
for coinbase_height in 0..=((tip
10921090
.anchored_header
10931091
.as_stacks_nakamoto()
@@ -1097,7 +1095,7 @@ fn test_nakamoto_chainstate_getters() {
10971095
+ 1)
10981096
{
10991097
let header_opt = NakamotoChainState::get_header_by_coinbase_height(
1100-
&mut stacks_db_tx,
1098+
&mut chainstate.index_conn(),
11011099
&tip.index_block_hash(),
11021100
coinbase_height,
11031101
)

stackslib/src/chainstate/nakamoto/mod.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,13 @@ pub trait StacksDBIndexed {
300300
fn get(&mut self, tip: &StacksBlockId, key: &str) -> Result<Option<String>, DBError>;
301301
fn sqlite(&self) -> &Connection;
302302

303+
/// Get the ancestor block hash given a height
304+
fn get_ancestor_block_id(
305+
&mut self,
306+
coinbase_height: u64,
307+
tip_index_hash: &StacksBlockId,
308+
) -> Result<Option<StacksBlockId>, DBError>;
309+
303310
/// Get the block ID for a specific coinbase height in the fork identified by `tip`
304311
fn get_nakamoto_block_id_at_coinbase_height(
305312
&mut self,
@@ -452,6 +459,14 @@ impl StacksDBIndexed for StacksDBConn<'_> {
452459
fn sqlite(&self) -> &Connection {
453460
self.conn()
454461
}
462+
463+
fn get_ancestor_block_id(
464+
&mut self,
465+
coinbase_height: u64,
466+
tip_index_hash: &StacksBlockId,
467+
) -> Result<Option<StacksBlockId>, DBError> {
468+
self.get_ancestor_block_hash(coinbase_height, tip_index_hash)
469+
}
455470
}
456471

457472
impl StacksDBIndexed for StacksDBTx<'_> {
@@ -462,6 +477,14 @@ impl StacksDBIndexed for StacksDBTx<'_> {
462477
fn sqlite(&self) -> &Connection {
463478
self.tx().deref()
464479
}
480+
481+
fn get_ancestor_block_id(
482+
&mut self,
483+
coinbase_height: u64,
484+
tip_index_hash: &StacksBlockId,
485+
) -> Result<Option<StacksBlockId>, DBError> {
486+
self.get_ancestor_block_hash(coinbase_height, tip_index_hash)
487+
}
465488
}
466489

467490
impl<'a> ChainstateTx<'a> {
@@ -2406,22 +2429,22 @@ impl NakamotoChainState {
24062429
/// Return a Nakamoto StacksHeaderInfo at a given coinbase height in the fork identified by `tip_index_hash`.
24072430
/// * For Stacks 2.x, this is the Stacks block's header
24082431
/// * For Stacks 3.x (Nakamoto), this is the first block in the miner's tenure.
2409-
pub fn get_header_by_coinbase_height(
2410-
tx: &mut StacksDBTx,
2432+
pub fn get_header_by_coinbase_height<SDBI: StacksDBIndexed>(
2433+
conn: &mut SDBI,
24112434
tip_index_hash: &StacksBlockId,
24122435
coinbase_height: u64,
24132436
) -> Result<Option<StacksHeaderInfo>, ChainstateError> {
24142437
// nakamoto block?
24152438
if let Some(block_id) =
2416-
tx.get_nakamoto_block_id_at_coinbase_height(tip_index_hash, coinbase_height)?
2439+
conn.get_nakamoto_block_id_at_coinbase_height(tip_index_hash, coinbase_height)?
24172440
{
2418-
return Self::get_block_header_nakamoto(tx.sqlite(), &block_id);
2441+
return Self::get_block_header_nakamoto(conn.sqlite(), &block_id);
24192442
}
24202443

24212444
// epcoh2 block?
2422-
let Some(ancestor_at_height) = tx
2423-
.get_ancestor_block_hash(coinbase_height, tip_index_hash)?
2424-
.map(|ancestor| Self::get_block_header(tx.tx(), &ancestor))
2445+
let Some(ancestor_at_height) = conn
2446+
.get_ancestor_block_id(coinbase_height, tip_index_hash)?
2447+
.map(|ancestor| Self::get_block_header(conn.sqlite(), &ancestor))
24252448
.transpose()?
24262449
.flatten()
24272450
else {

stackslib/src/chainstate/nakamoto/tenure.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ impl NakamotoChainState {
372372

373373
let matured_coinbase_height = coinbase_height - MINER_REWARD_MATURITY;
374374
let matured_tenure_block_header = Self::get_header_by_coinbase_height(
375-
chainstate_tx,
375+
chainstate_tx.deref_mut(),
376376
&tip_index_hash,
377377
matured_coinbase_height,
378378
)?
@@ -964,7 +964,7 @@ impl NakamotoChainState {
964964

965965
let total_coinbase = coinbase_at_block.saturating_add(accumulated_rewards);
966966
let parent_tenure_start_header: StacksHeaderInfo = Self::get_header_by_coinbase_height(
967-
chainstate_tx,
967+
chainstate_tx.deref_mut(),
968968
&block.header.parent_block_id,
969969
parent_coinbase_height,
970970
)?

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

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,7 +1915,10 @@ fn end_of_tenure() {
19151915
let http_origin = format!("http://{}", &signer_test.running_nodes.conf.node.rpc_bind);
19161916
let long_timeout = Duration::from_secs(200);
19171917
let short_timeout = Duration::from_secs(20);
1918-
1918+
let blocks_before = signer_test
1919+
.running_nodes
1920+
.nakamoto_blocks_mined
1921+
.load(Ordering::SeqCst);
19191922
signer_test.boot_to_epoch_3();
19201923
let curr_reward_cycle = signer_test.get_current_reward_cycle();
19211924
// Advance to one before the next reward cycle to ensure we are on the reward cycle boundary
@@ -1928,15 +1931,26 @@ fn end_of_tenure() {
19281931
- 2;
19291932

19301933
// give the system a chance to mine a Nakamoto block
1931-
sleep_ms(30_000);
1934+
// But it doesn't have to mine one for this test to succeed?
1935+
let start = Instant::now();
1936+
while start.elapsed() <= short_timeout {
1937+
let mined_blocks = signer_test
1938+
.running_nodes
1939+
.nakamoto_blocks_mined
1940+
.load(Ordering::SeqCst);
1941+
if mined_blocks > blocks_before {
1942+
break;
1943+
}
1944+
sleep_ms(100);
1945+
}
19321946

19331947
info!("------------------------- Test Mine to Next Reward Cycle Boundary -------------------------");
19341948
signer_test.run_until_burnchain_height_nakamoto(
19351949
long_timeout,
19361950
final_reward_cycle_height_boundary,
19371951
num_signers,
19381952
);
1939-
println!("Advanced to nexct reward cycle boundary: {final_reward_cycle_height_boundary}");
1953+
println!("Advanced to next reward cycle boundary: {final_reward_cycle_height_boundary}");
19401954
assert_eq!(
19411955
signer_test.get_current_reward_cycle(),
19421956
final_reward_cycle - 1
@@ -1977,39 +1991,20 @@ fn end_of_tenure() {
19771991
std::thread::sleep(Duration::from_millis(100));
19781992
}
19791993

1980-
info!("Triggering a new block to be mined");
1981-
1982-
// Mine a block into the next reward cycle
1983-
let commits_before = signer_test
1984-
.running_nodes
1985-
.commits_submitted
1986-
.load(Ordering::SeqCst);
1987-
next_block_and(
1988-
&mut signer_test.running_nodes.btc_regtest_controller,
1989-
10,
1990-
|| {
1991-
let commits_count = signer_test
1992-
.running_nodes
1993-
.commits_submitted
1994-
.load(Ordering::SeqCst);
1995-
Ok(commits_count > commits_before)
1996-
},
1997-
)
1998-
.unwrap();
1999-
2000-
// Mine a few blocks so we are well into the next reward cycle
2001-
for _ in 0..2 {
1994+
while signer_test.get_current_reward_cycle() != final_reward_cycle {
20021995
next_block_and(
20031996
&mut signer_test.running_nodes.btc_regtest_controller,
20041997
10,
20051998
|| Ok(true),
20061999
)
20072000
.unwrap();
2001+
assert!(
2002+
start_time.elapsed() <= short_timeout,
2003+
"Timed out waiting to enter the next reward cycle"
2004+
);
2005+
std::thread::sleep(Duration::from_millis(100));
20082006
}
20092007

2010-
sleep_ms(10_000);
2011-
assert_eq!(signer_test.get_current_reward_cycle(), final_reward_cycle);
2012-
20132008
while test_observer::get_burn_blocks()
20142009
.last()
20152010
.unwrap()

0 commit comments

Comments
 (0)