Skip to content

Commit ca39248

Browse files
committed
fix: query nakamoto burnchain operations by tenure-start block ID, and only do so on tenure-start (not tenure-extend)
1 parent 0b4f3b2 commit ca39248

File tree

1 file changed

+160
-14
lines changed
  • stackslib/src/chainstate/nakamoto

1 file changed

+160
-14
lines changed

stackslib/src/chainstate/nakamoto/mod.rs

Lines changed: 160 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// You should have received a copy of the GNU General Public License
1515
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

17-
use std::collections::HashMap;
17+
use std::collections::{HashMap, HashSet};
1818
use std::fs;
1919
use std::ops::{Deref, DerefMut, Range};
2020
use std::path::PathBuf;
@@ -104,7 +104,9 @@ use crate::clarity_vm::clarity::{
104104
ClarityInstance, ClarityTransactionConnection, Error as ClarityError, PreCommitClarityBlock,
105105
};
106106
use crate::clarity_vm::database::SortitionDBRef;
107-
use crate::core::{BOOT_BLOCK_HASH, NAKAMOTO_SIGNER_BLOCK_APPROVAL_THRESHOLD};
107+
use crate::core::{
108+
BOOT_BLOCK_HASH, BURNCHAIN_TX_SEARCH_WINDOW, NAKAMOTO_SIGNER_BLOCK_APPROVAL_THRESHOLD,
109+
};
108110
use crate::net::stackerdb::{StackerDBConfig, MINER_SLOT_COUNT};
109111
use crate::net::Error as net_error;
110112
use crate::util_lib::boot;
@@ -3251,14 +3253,18 @@ impl NakamotoChainState {
32513253
if let Some(block_reward) = block_reward {
32523254
StacksChainState::insert_miner_payment_schedule(headers_tx.deref_mut(), block_reward)?;
32533255
}
3254-
StacksChainState::store_burnchain_txids(
3255-
headers_tx.deref(),
3256-
&index_block_hash,
3257-
burn_stack_stx_ops,
3258-
burn_transfer_stx_ops,
3259-
burn_delegate_stx_ops,
3260-
burn_vote_for_aggregate_key_ops,
3261-
)?;
3256+
3257+
// NOTE: this is a no-op if the block isn't a tenure-start block
3258+
if new_tenure {
3259+
StacksChainState::store_burnchain_txids(
3260+
headers_tx.deref(),
3261+
&index_block_hash,
3262+
burn_stack_stx_ops,
3263+
burn_transfer_stx_ops,
3264+
burn_delegate_stx_ops,
3265+
burn_vote_for_aggregate_key_ops,
3266+
)?;
3267+
}
32623268

32633269
if let Some(matured_miner_payouts) = mature_miner_payouts_opt {
32643270
let rewarded_miner_block_id = StacksBlockId::new(
@@ -3360,6 +3366,145 @@ impl NakamotoChainState {
33603366
.map_err(ChainstateError::from)
33613367
}
33623368

3369+
/// Find all of the TXIDs of Stacks-on-burnchain operations processed in the given Stacks fork.
3370+
/// In Nakamoto, we index these TXIDs by the tenure-start block ID
3371+
pub(crate) fn get_burnchain_txids_in_ancestor_tenures<SDBI: StacksDBIndexed>(
3372+
conn: &mut SDBI,
3373+
tip_consensus_hash: &ConsensusHash,
3374+
tip_block_hash: &BlockHeaderHash,
3375+
search_window: u64,
3376+
) -> Result<HashSet<Txid>, ChainstateError> {
3377+
let tip = StacksBlockId::new(tip_consensus_hash, tip_block_hash);
3378+
let mut cursor = tip_consensus_hash.clone();
3379+
let mut ret = HashSet::new();
3380+
for _ in 0..search_window {
3381+
let Some(tenure_start_block_id) = conn.get_tenure_start_block_id(&tip, &cursor)? else {
3382+
break;
3383+
};
3384+
let txids = StacksChainState::get_burnchain_txids_for_block(
3385+
conn.sqlite(),
3386+
&tenure_start_block_id,
3387+
)?;
3388+
ret.extend(txids.into_iter());
3389+
3390+
let Some(parent_tenure_id) = conn.get_parent_tenure_consensus_hash(&tip, &cursor)?
3391+
else {
3392+
break;
3393+
};
3394+
3395+
cursor = parent_tenure_id;
3396+
}
3397+
Ok(ret)
3398+
}
3399+
3400+
/// Get all Stacks-on-burnchain operations that we haven't processed yet
3401+
pub(crate) fn get_stacks_on_burnchain_operations<SDBI: StacksDBIndexed>(
3402+
conn: &mut SDBI,
3403+
parent_consensus_hash: &ConsensusHash,
3404+
parent_block_hash: &BlockHeaderHash,
3405+
sortdb_conn: &Connection,
3406+
burn_tip: &BurnchainHeaderHash,
3407+
burn_tip_height: u64,
3408+
) -> Result<
3409+
(
3410+
Vec<StackStxOp>,
3411+
Vec<TransferStxOp>,
3412+
Vec<DelegateStxOp>,
3413+
Vec<VoteForAggregateKeyOp>,
3414+
),
3415+
ChainstateError,
3416+
> {
3417+
let cur_epoch = SortitionDB::get_stacks_epoch(sortdb_conn, burn_tip_height)?
3418+
.expect("FATAL: no epoch defined for current burnchain tip height");
3419+
3420+
// only consider transactions in Stacks 3.0
3421+
if cur_epoch.epoch_id < StacksEpochId::Epoch30 {
3422+
return Ok((vec![], vec![], vec![], vec![]));
3423+
}
3424+
3425+
let epoch_start_height = cur_epoch.start_height;
3426+
3427+
let search_window: u8 =
3428+
if epoch_start_height + u64::from(BURNCHAIN_TX_SEARCH_WINDOW) > burn_tip_height {
3429+
burn_tip_height
3430+
.saturating_sub(epoch_start_height)
3431+
.try_into()
3432+
.expect("FATAL: search window exceeds u8")
3433+
} else {
3434+
BURNCHAIN_TX_SEARCH_WINDOW
3435+
};
3436+
3437+
debug!(
3438+
"Search the last {} sortitions for burnchain-hosted stacks operations before {} ({})",
3439+
search_window, burn_tip, burn_tip_height
3440+
);
3441+
let ancestor_burnchain_header_hashes = SortitionDB::get_ancestor_burnchain_header_hashes(
3442+
sortdb_conn,
3443+
burn_tip,
3444+
search_window.into(),
3445+
)?;
3446+
let processed_burnchain_txids =
3447+
NakamotoChainState::get_burnchain_txids_in_ancestor_tenures(
3448+
conn,
3449+
parent_consensus_hash,
3450+
parent_block_hash,
3451+
search_window.into(),
3452+
)?;
3453+
3454+
// Find the *new* transactions -- the ones that we *haven't* seen in this Stacks
3455+
// fork yet. Note that we search for the ones that we have seen by searching back
3456+
// `BURNCHAIN_TX_SEARCH_WINDOW` tenures, whose sortitions may span more
3457+
// than `BURNCHAIN_TX_SEARCH_WINDOW` burnchain blocks. The inclusion of txids for
3458+
// burnchain transactions in the latter query is not a problem, because these txids
3459+
// are used to *exclude* transactions from the last `BURNCHAIN_TX_SEARCH_WINDOW`
3460+
// burnchain blocks. These excluded txids, if they were mined outside of this
3461+
// window, are *already* excluded.
3462+
3463+
let mut all_stacking_burn_ops = vec![];
3464+
let mut all_transfer_burn_ops = vec![];
3465+
let mut all_delegate_burn_ops = vec![];
3466+
let mut all_vote_for_aggregate_key_ops = vec![];
3467+
3468+
// go from oldest burn header hash to newest
3469+
for ancestor_bhh in ancestor_burnchain_header_hashes.iter().rev() {
3470+
let stacking_ops = SortitionDB::get_stack_stx_ops(sortdb_conn, ancestor_bhh)?;
3471+
let transfer_ops = SortitionDB::get_transfer_stx_ops(sortdb_conn, ancestor_bhh)?;
3472+
let delegate_ops = SortitionDB::get_delegate_stx_ops(sortdb_conn, ancestor_bhh)?;
3473+
let vote_for_aggregate_key_ops =
3474+
SortitionDB::get_vote_for_aggregate_key_ops(sortdb_conn, ancestor_bhh)?;
3475+
3476+
for stacking_op in stacking_ops.into_iter() {
3477+
if !processed_burnchain_txids.contains(&stacking_op.txid) {
3478+
all_stacking_burn_ops.push(stacking_op);
3479+
}
3480+
}
3481+
3482+
for transfer_op in transfer_ops.into_iter() {
3483+
if !processed_burnchain_txids.contains(&transfer_op.txid) {
3484+
all_transfer_burn_ops.push(transfer_op);
3485+
}
3486+
}
3487+
3488+
for delegate_op in delegate_ops.into_iter() {
3489+
if !processed_burnchain_txids.contains(&delegate_op.txid) {
3490+
all_delegate_burn_ops.push(delegate_op);
3491+
}
3492+
}
3493+
3494+
for vote_op in vote_for_aggregate_key_ops.into_iter() {
3495+
if !processed_burnchain_txids.contains(&vote_op.txid) {
3496+
all_vote_for_aggregate_key_ops.push(vote_op);
3497+
}
3498+
}
3499+
}
3500+
Ok((
3501+
all_stacking_burn_ops,
3502+
all_transfer_burn_ops,
3503+
all_delegate_burn_ops,
3504+
all_vote_for_aggregate_key_ops,
3505+
))
3506+
}
3507+
33633508
/// Begin block-processing and return all of the pre-processed state within a
33643509
/// `SetupBlockResult`.
33653510
///
@@ -3432,10 +3577,11 @@ impl NakamotoChainState {
34323577
};
34333578

34343579
let (stacking_burn_ops, transfer_burn_ops, delegate_burn_ops, vote_for_agg_key_ops) =
3435-
if new_tenure || tenure_extend {
3436-
StacksChainState::get_stacking_and_transfer_and_delegate_burn_ops(
3437-
chainstate_tx,
3438-
&parent_index_hash,
3580+
if new_tenure {
3581+
NakamotoChainState::get_stacks_on_burnchain_operations(
3582+
chainstate_tx.as_tx(),
3583+
&parent_consensus_hash,
3584+
&parent_header_hash,
34393585
sortition_dbconn.sqlite_conn(),
34403586
&burn_header_hash,
34413587
burn_header_height.into(),

0 commit comments

Comments
 (0)