Skip to content

Reject prioritisetransaction on pooled dust like Core - #593

Draft
metaphorics wants to merge 1 commit into
cursor/mining-prioritise-dummy-1522from
cursor/mining-prioritise-dust-1522
Draft

Reject prioritisetransaction on pooled dust like Core#593
metaphorics wants to merge 1 commit into
cursor/mining-prioritise-dummy-1522from
cursor/mining-prioritise-dust-1522

Conversation

@metaphorics

Copy link
Copy Markdown
Contributor

Stacked on #589 (cursor/mining-prioritise-dummy-1522). Merge order: #428#436#442#451#479#499#514#535#553#557#565#566#581#586#589 → this.

Why

Core v31 prioritisetransaction refuses to modify the fee overlay of a mempool transaction with dust outputs when require_standard is set:

Priority is not supported for transactions with dust outputs.

require_standard defaults on except regtest (-acceptnonstdtxn). Absent txids are overlay-only and are not checked.

Contract (API-20)

Owner: prioritisetransaction in crates/rpc/src/handlers/mining.rs. Dust classification is tx_has_dust_outputs in crates/mempool/src/standardness.rs.

Proof

  • prioritisetransaction_rejects_dust_outputs_like_core
  • prioritisetransaction_allows_dust_overlay_on_regtest
  • prioritisetransaction_allows_absent_txid_overlay
  • dust_relay_fee_changes_the_boundary

Not in this PR

Open in Web Open in Cursor 

Core v31 refuses to modify the fee overlay of a mempool transaction with
dust outputs when require_standard is set. That flag defaults on except
regtest. Absent txids are overlay-only and are not checked.

Co-authored-by: metaphorics <metaphorics@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 2f63e0aa-a4ec-4d27-a4b6-9b465961e85c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor

cursor Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_467380bc-4962-44d5-aedd-d2c92a277b1b)

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Match Core dust rejection in prioritisetransaction

🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Rejects fee prioritisation for pooled dust transactions outside regtest, matching Bitcoin Core
 v31.
• Uses active mempool dust-relay policy while preserving absent-txid overlays.
• Documents API-20 and tests rejection, regtest, and dust-boundary behavior.
Diagram

graph TD
  RPC["prioritisetransaction"] --> Network{"Regtest?"} -->|No| Lookup["Mempool lookup"] --> Found{"Tx pooled?"} -->|Yes| Policy["Dust policy"] --> Dust{"Dust outputs?"} -->|Yes| Reject["RPC error -8"]
  Network -->|Yes| Overlay["Fee overlay"]
  Found -->|No| Overlay
  Dust -->|No| Overlay
Loading
High-Level Assessment

The RPC-boundary check is appropriate because the rule depends on network-specific require-standard behavior and must preserve generic overlays for absent transaction IDs. Enforcing it inside the mempool prioritisation primitive was considered but would couple generic fee-overlay storage to RPC and network policy.

Files changed (7) +113 / -5

Bug fix (3) +91 / -1
lib.rsExport the transaction dust-classification helper +3/-1

Export the transaction dust-classification helper

• Re-exports tx_has_dust_outputs so RPC handlers can use the mempool's canonical standardness logic.

crates/mempool/src/lib.rs

standardness.rsAdd reusable transaction-level dust detection +13/-0

Add reusable transaction-level dust detection

• Adds tx_has_dust_outputs to detect any output below the supplied dust-relay threshold. Extends the relay-fee boundary test to verify classification changes with policy.

crates/mempool/src/standardness.rs

mining.rsReject prioritisation of pooled dust transactions +75/-0

Reject prioritisation of pooled dust transactions

• Checks non-regtest mempool entries against the active dust-relay fee before applying a fee delta and returns Core-compatible error -8 for dust. Adds tests for mainnet rejection, regtest allowance, and absent transaction overlays.

crates/rpc/src/handlers/mining.rs

Documentation (4) +22 / -4
registry.rsRecord prioritisetransaction dust semantics +1/-1

Record prioritisetransaction dust semantics

• Updates the live RPC registry description to state that pooled dust is rejected outside regtest.

crates/rpc/src/registry.rs

README.mdExtend the external API contract index through API-20 +1/-1

Extend the external API contract index through API-20

• Updates the contract range, scope summary, and proof references to include prioritisetransaction pooled-dust refusal.

docs/contracts/README.md

external-api.mdDefine the API-20 pooled-dust contract +19/-1

Define the API-20 pooled-dust contract

• Documents the Core-compatible error, network exception, absent-txid behavior, dust policy source, and proving tests.

docs/contracts/external-api.md

rpc-reference.mdDocument prioritisetransaction dust rejection +1/-1

Document prioritisetransaction dust rejection

• Updates the generated RPC reference to identify pooled dust as error -8 except on regtest.

docs/rpc-reference.md

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (1)

Grey Divider


Action required

1. Dust check is non-atomic 🐞 Bug
Description
prioritisetransaction releases the mempool read lock after checking for dust and then reacquires a
separate write lock to apply the overlay. A reorg can resurrect a dust transaction between those
operations, causing the RPC to successfully prioritise a pooled dust transaction that should return
-8.
Code

crates/rpc/src/handlers/mining.rs[R182-185]

+        let pool = ctx.mempool.read();
+        if let Some(entry) = pool.entry_by_txid(&txid) {
+            let dust_relay_fee = pool.policy_snapshot().standardness.dust_relay_fee;
+            if tx_has_dust_outputs(&entry.tx, dust_relay_fee) {
Relevance

●● Moderate

Atomicity concerns have accepted precedents, but no close prior precedent addresses this exact
mempool prioritisation race.

PR-#49
PR-#316

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The handler checks membership under a temporary read guard, but MempoolGateway::prioritise later
acquires an independent write guard. Production reorg handling constructs disconnected transactions
as mempool entries and inserts them through reconsider_disconnected, so a dust transaction can
enter during this gap; the pool's prioritisation implementation then updates the overlay before
consulting current membership.

crates/rpc/src/handlers/mining.rs[181-192]
crates/mempool/src/gateway.rs[775-780]
crates/mempool/src/pool.rs[962-980]
crates/node/src/reorg.rs[623-642]
crates/mempool/src/gateway.rs[501-504]
crates/mempool/src/gateway.rs[523-559]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Make the pooled-dust check and fee-overlay update one atomic mempool operation. The current read-lock check followed by a separate write-lock prioritisation permits reorg resurrection to insert a dust transaction between them.

## Issue Context
`MempoolGateway::prioritise` currently acquires its own write lock. Add an operation that checks the entry under that same write guard and applies the overlay only if the entry is absent or non-dust, while preserving overflow and absent-txid behavior.

## Fix Focus Areas
- crates/rpc/src/handlers/mining.rs[179-192]
- crates/mempool/src/gateway.rs[775-780]
- crates/mempool/src/pool.rs[962-993]
- crates/node/src/reorg.rs[623-642]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 18 rules
✅ Web pages:
  +2 more
Review mode: ⚖️ Balanced: This changes public RPC behavior and mempool dust classification across multiple code paths, creating genuine compatibility and policy risks, but the logic is not broad or defect-dense enough to justify extended review.
ⓘ  4 issues published inline · 1 in summary

Grey Divider

Comment on lines +179 to +180
// Core `require_standard` defaults on except regtest (`-acceptnonstdtxn`).
// Dust in the pool cannot have its fee overlay modified afterwards.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. require_standard rule copied in comments 📘 Rule violation ⚙ Maintainability

The new comments restate the network-dependent standardness rule already defined by AcceptContext
and the API-20 contract instead of referencing its authoritative definition. This creates another
textual copy that can drift when standardness configuration is wired as a node option.
Agent Prompt
## Issue description
The comments duplicate the documented `require_standard` and pooled-dust business rules.

## Issue Context
`AcceptContext` already documents the network default, while `docs/contracts/external-api.md` defines the authoritative `API-20` behavior. Replace the restatement with a brief contract reference.

## Fix Focus Areas
- crates/rpc/src/handlers/mining.rs[179-180]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1577 to +1578
#[test]
fn prioritisetransaction_rejects_dust_outputs_like_core() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. api-20 tests lack contract markers 📘 Rule violation ▣ Testability

The three new RPC tests and the modified dust-boundary test are listed as durable proof for
API-20, but none identifies that contract in its test name or an adjacent test-level comment.
Future maintainers cannot determine the documented contract from the tests themselves.
Agent Prompt
## Issue description
Tests serving as permanent proof for `API-20` do not carry an explicit contract marker.

## Issue Context
The contract documentation maps these tests to `API-20`, but rule 3086699 requires the test name, test-level comment, or metadata to reference the current contract directly. Add an adjacent `CONTRACT: API-20` comment or include `api_20` in each relevant test name.

## Fix Focus Areas
- crates/rpc/src/handlers/mining.rs[1577-1624]
- crates/mempool/src/standardness.rs[879-895]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +182 to +185
let pool = ctx.mempool.read();
if let Some(entry) = pool.entry_by_txid(&txid) {
let dust_relay_fee = pool.policy_snapshot().standardness.dust_relay_fee;
if tx_has_dust_outputs(&entry.tx, dust_relay_fee) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Dust check is non-atomic 🐞 Bug ≡ Correctness

prioritisetransaction releases the mempool read lock after checking for dust and then reacquires a
separate write lock to apply the overlay. A reorg can resurrect a dust transaction between those
operations, causing the RPC to successfully prioritise a pooled dust transaction that should return
-8.
Agent Prompt
## Issue description
Make the pooled-dust check and fee-overlay update one atomic mempool operation. The current read-lock check followed by a separate write-lock prioritisation permits reorg resurrection to insert a dust transaction between them.

## Issue Context
`MempoolGateway::prioritise` currently acquires its own write lock. Add an operation that checks the entry under that same write guard and applies the overlay only if the entry is absent or non-dust, while preserving overflow and absent-txid behavior.

## Fix Focus Areas
- crates/rpc/src/handlers/mining.rs[179-192]
- crates/mempool/src/gateway.rs[775-780]
- crates/mempool/src/pool.rs[962-993]
- crates/node/src/reorg.rs[623-642]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +537 to +540
pub fn tx_has_dust_outputs(tx: &Tx, dust_relay_fee: u64) -> bool {
tx.outputs
.iter()
.any(|output| is_dust(output, dust_relay_fee))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

4. Dust threshold rounds down 🐞 Bug ≡ Correctness

The new tx_has_dust_outputs API delegates to minimal_non_dust, which floors fee × size / 1000,
while Core v31's CFeeRate::GetFee rounds fractional fees up. For non-integral custom dust relay
rates, boundary outputs can therefore be accepted and prioritised here even though Core classifies
them as dust.
Agent Prompt
## Issue description
Update dust-threshold calculation to use Core v31's upward fee rounding rather than floor division, and add a boundary test using a dust relay rate whose product with the output size is not divisible by 1000.

## Issue Context
The default 3000 sat/kvB rate produces integral thresholds, masking the discrepancy. Preserve the zero threshold for unspendable outputs and avoid overflow while implementing ceiling division.

## Fix Focus Areas
- crates/script/src/script.rs[330-346]
- crates/mempool/src/standardness.rs[527-540]
- crates/mempool/src/standardness.rs[880-895]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-code-review

Copy link
Copy Markdown
Contributor

Qodo Fixer

🍒 Ready to be cherry-picked — ✅ Merged (0) · ☑ Fixed (4)

Grey Divider

🔗 Fix PR: #594

This fix PR was closed automatically. Its branch is preserved so you can cherry pick the changes into the original PR.

Prompt for coding agent

This is an automated fix prepared on a separate branch (#594). It is NOT applied to this PR.
To use it: review Fix PR #594 (https://github.com/gosuda/bitcoin-rs/pull/594), evaluate each change critically against your local context, and cherry-pick the changes that are correct into this branch. Do not accept them blindly.
Process — 4 fixed
  • ☑ Fixed: Dust check is non-atomic
  • ☑ Fixed: Dust threshold rounds down
  • ☑ Fixed: require_standard rule copied in comments
  • ☑ Fixed: API-20 tests lack contract markers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants