Skip to content

Commit f75b916

Browse files
committed
fix: do not break UTXO chain
Bad timing between the Stacks node's processing and the Bitcoin network including a block commit can cause a miner to submit a block commit which breaks the UTXO chain, severly hurting its chances of winning blocks. It is better to just miss this commit than to break the UTXO chain.
1 parent d23c861 commit f75b916

File tree

2 files changed

+30
-37
lines changed

2 files changed

+30
-37
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to the versioning scheme outlined in the [README.md](README.md).
77

8+
## Unreleased
9+
10+
### Changed
11+
12+
- When a previous block commit is unable to be RBFed, the miner will now just wait for it to be confirmed instead of submitting a new block commit which breaks the miner's UTXO chain.
13+
814
## [3.1.0.0.11]
915

1016
- Hotfix for p2p stack misbehavior in mempool syncing conditions

testnet/stacks-node/src/burnchains/bitcoin_regtest_controller.rs

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,12 @@ impl BitcoinRegtestController {
15391539
Ok(true)
15401540
);
15411541
if ongoing_tx_confirmed {
1542+
if ongoing_op.payload == payload {
1543+
info!("Abort attempt to re-submit confirmed LeaderBlockCommit");
1544+
self.ongoing_block_commit = Some(ongoing_op);
1545+
return Err(BurnchainControllerError::IdenticalOperation);
1546+
}
1547+
15421548
debug!("Was able to retrieve confirmation of ongoing burnchain TXID - {txid}");
15431549
let res = self.send_block_commit_operation(
15441550
epoch_id,
@@ -1600,49 +1606,30 @@ impl BitcoinRegtestController {
16001606
}
16011607

16021608
// An ongoing operation is in the mempool and we received a new block. The desired behaviour is the following:
1603-
// 1) If the ongoing and the incoming operation are **strictly** identical, we will be idempotent and discard the incoming.
1604-
// 2) If the 2 operations are different, we will try to avoid wasting UTXOs, and attempt to RBF the outgoing transaction:
1605-
// i) If UTXOs are insufficient,
1606-
// a) If no other UTXOs, we'll have to wait on the ongoing operation to be mined before resuming operation.
1607-
// b) If we have some other UTXOs, drop the ongoing operation, and track the new one.
1608-
// ii) If UTXOs initially used are sufficient for paying for a fee bump, then RBF
1609-
1610-
// Let's start by early returning 1)
1609+
// (1) If the ongoing and the incoming operation are **strictly** identical, we will be idempotent and discard the incoming.
1610+
// (2) If the 2 operations are different, attempt to RBF the outgoing transaction:
1611+
1612+
// Let's start by early returning (1)
16111613
if payload == ongoing_op.payload {
16121614
info!("Abort attempt to re-submit identical LeaderBlockCommit");
16131615
self.ongoing_block_commit = Some(ongoing_op);
16141616
return Err(BurnchainControllerError::IdenticalOperation);
16151617
}
16161618

1617-
// Let's proceed and early return 2) i)
1618-
let res = if ongoing_op.fees.estimated_amount_required() > ongoing_op.sum_utxos() {
1619-
// Try to build and submit op, excluding UTXOs currently used
1620-
info!("Attempt to submit another leader_block_commit, despite an ongoing (outdated) commit");
1621-
self.send_block_commit_operation(
1622-
epoch_id,
1623-
payload,
1624-
signer,
1625-
None,
1626-
Some(ongoing_op.utxos.clone()),
1627-
None,
1628-
&[],
1629-
)
1630-
} else {
1631-
// Case 2) ii): Attempt to RBF
1632-
info!(
1633-
"Attempt to replace by fee an outdated leader block commit";
1634-
"ongoing_txids" => ?ongoing_op.txids
1635-
);
1636-
self.send_block_commit_operation(
1637-
epoch_id,
1638-
payload,
1639-
signer,
1640-
Some(ongoing_op.utxos.clone()),
1641-
None,
1642-
Some(ongoing_op.fees.clone()),
1643-
&ongoing_op.txids,
1644-
)
1645-
};
1619+
// If we reach this point, we are attempting to RBF the ongoing operation (2)
1620+
info!(
1621+
"Attempt to replace by fee an outdated leader block commit";
1622+
"ongoing_txids" => ?ongoing_op.txids
1623+
);
1624+
let res = self.send_block_commit_operation(
1625+
epoch_id,
1626+
payload,
1627+
signer,
1628+
Some(ongoing_op.utxos.clone()),
1629+
None,
1630+
Some(ongoing_op.fees.clone()),
1631+
&ongoing_op.txids,
1632+
);
16461633

16471634
if res.is_err() {
16481635
self.ongoing_block_commit = Some(ongoing_op);

0 commit comments

Comments
 (0)