Skip to content
2 changes: 1 addition & 1 deletion TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ A cell that names a crate-local test describes the witness that exists today. It
| `serve_after_restart_via_reconstruct` | P2P (**default**) | Cold serve via reconstruct. Restart RAM body queue is empty. Same-process `rehydrate_block_queue_residue` drops at/below tip, skips empty payloads, keeps above-tip wire, unknown height stays queued. `has_block` / known-archived keep and tip+1 gap `missing` stay `bq_rehydrate_residue_keep_drop_gap_and_unknown` |
| `ibd_skips_dead_peer` | P2P (**default**) | Live seeder + `127.0.0.1:1` |
| `reorg_to_longer_branch` | P2P/chain (default) | Most-work reorg (hub only — no IBD hang risk). With the filter index on, the disconnect truncates basic filters and the branch's filters replace them. Then 20 side blocks received one at a time beat 19 tip-extends (`mempool_reorg.py`), the loser is a `valid-fork` that reconstructs from Class A (not held), an equal-work received branch waits for `preciousblock`, and invalidate / reconsider move between them without parking the old tip |
| `reorg_same_height_then_multi_block_branch` | P2P/chain (default) | Mature pad + competing-spend reorg (third spend is prevout-spent, not `multi-spender`); same-height rival then multi-block reorg near tip; `getchaintips` `active` vs `valid-fork`; 16 vs 17 equal-work siblings park as `valid-headers` (product held cap 320 does not FIFO at 17); `precious_block` the loser; less work ignored; unknown hash `Block not found` for precious and reconsider. Invalidating the tip picks the first-seen equal-work held sibling, precious of the invalidated hash is a no-op that reconsider does not honor. A lone side block is `SideBlock`, a weaker branch is ignored, and an unknown parent errors on submit but is held from a peer. Held cap FIFO stays `hold_body_caps_fifo` |
| `reorg_same_height_then_multi_block_branch` | P2P/chain (default) | Mature pad + competing-spend reorg (third spend is prevout-spent, not `multi-spender`); same-height rival then multi-block reorg near tip; `getchaintips` `active` vs `valid-fork`; 16 vs 17 equal-work siblings park as `valid-headers` (product held cap 320 does not FIFO at 17); `precious_block` the loser; less work ignored; unknown hash `Block not found` for precious and reconsider. Invalidating the tip with no precious preference picks the first-seen equal-work held sibling. With precious set, invalidate adopts that precious equal-work branch, and more total work still beats precious. Precious of an invalidated hash is a no-op that reconsider does not honor. A lone side block is `SideBlock`, a weaker branch is ignored, and an unknown parent errors on submit but is held from a peer. Held cap FIFO stays `hold_body_caps_fifo` |
| `three_node_relay_path` | P2P (**default**) | Leaf IBD-syncs from a mid node that already synced (hop serve) |
| `ibd_two_peers` | P2P (**default**) | Dual live seeders, 8-block IBD |
| `tip_follow_after_ibd` | P2P (**default**) | After IBD, follow + one new tip via inv/headers. With the filter index on, IBD confirm writes no basic filters; `rbtc-idx-wb` materializes them to the tip (its caught-up callback fires once, at the tip), then seals the followed block. With `--sp-tweaks` too: the builder brings both indexes to 5 and is stopped; a followed block with no builder running moves neither (no confirm path writes index data); a new builder seals 6, then follows 7 |
Expand Down
13 changes: 7 additions & 6 deletions changelog.d/core-functional-closer.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ Fixed
challenge is exactly `OP_TRUE` (signet bits, empty BIP325 solution).
`getblockchaininfo.signet_challenge` is present on signet. A signet
solution failure is reported as `bad-signet-blksig`.
- **`getblockfilter` serves a stored block that is not sealed yet.** A
best-chain height already in the index still uses that row. A known
block that is stale or not sealed is rebuilt from the body, and its
header is the BIP157 chain from the last sealed header or from genesis.
An unknown `filtertype` is `-5`. REST `/rest/blockfilter/` stays
watermark-only.
- **`getblockfilter` serves a sealed row, or one block past a sealed
parent.** A best-chain height already in the index uses that row. A
block whose parent filter header is sealed, including a stale branch
walked back to that fork point, is rebuilt from the body. An unsealed
best-chain gap is “Filter not found. Block filters are still in the
process of being indexed.” An unknown `filtertype` is `-5`. REST
`/rest/blockfilter/` stays watermark-only.
- **`submitpackage` package-evaluates a child-with-parents remainder.**
Members that failed static min relay, the dynamic mempool floor, or
missing inputs are retried together, including when the child spends a
Expand Down
7 changes: 7 additions & 0 deletions changelog.d/getblockfilter-unsealed-gap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Fixed

- **`getblockfilter` does not rebuild an unsealed index gap.** A best-chain
block whose parent filter header is not sealed returns “Filter not found.
Block filters are still in the process of being indexed.” A block whose
parent header is already sealed is still built, and a stale branch is
rebuilt only back to that sealed fork point.
7 changes: 7 additions & 0 deletions changelog.d/held-header-before-disconnect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Fixed

- **A side branch with a bad header no longer rewinds the tip.** Headers on a
held branch are checked before any disconnect. A later block that claims
enormous work without a valid proof of work is remembered invalid, and a
heavier valid held branch can still become the tip. A store fault during
that check is not cached as an invalid block.
5 changes: 5 additions & 0 deletions changelog.d/invalidate-precious-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Fixed

- **`invalidateblock` of the tip honors `preciousblock` on an equal-work fork.**
The same tie rule as an ordinary reorg applies: more total work still wins,
then the precious branch, then the earlier held tip.
7 changes: 7 additions & 0 deletions changelog.d/package-trim-once.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Fixed

- **A package is trimmed once, after every member is in.** A parent that is
under the fee floor alone is not evicted before its paying child commits,
so `submitpackage` does not answer `mempool full` for a package that fits.
A package that does not survive that trim is rolled back, so the conflicts
it replaced stay.
6 changes: 6 additions & 0 deletions changelog.d/proposal-fee-overflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Fixed

- **A block proposal whose fees do not fit in `u64` is rejected.** Output
totals, input totals, and the fee sum use checked addition. An overflowing
sum is `bad-txns-txouttotal-toolarge`, `bad-txns-inputvalues-outofrange`,
or `bad-txns-fee-outofrange` instead of a successful template check.
6 changes: 6 additions & 0 deletions changelog.d/proposal-script-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Fixed

- **A block proposal with a failing script is rejected.** After the coinbase
amount check, proposal mode runs the block's script flags on the prevouts
it already resolved. No second parent decode and no UTXO write. P2SH and
witness sigops count toward the 80_000 block limit.
6 changes: 6 additions & 0 deletions changelog.d/pure-rbfr-u128.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Fixed

- **Pure replace-by-fee-rate compares the full product.** A replacement whose
`new_fee * 4 * old_vsize` or `direct_fee * 5 * new_vsize` exceeds `u64`
is held to 1.25× in `u128`, instead of a saturating multiply that can
accept a rate below the rule.
11 changes: 7 additions & 4 deletions crates/rbitcoin-mempool/src/accept.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2111,10 +2111,8 @@ pub fn pure_rbfr_pays(new_fee: u64, new_weight: u64, direct_fee: u64, direct_wei
if new_v == 0 || old_v == 0 {
return false;
}
new_fee.saturating_mul(RBFR_RATIO_DEN).saturating_mul(old_v)
>= direct_fee
.saturating_mul(RBFR_RATIO_NUM)
.saturating_mul(new_v)
u128::from(new_fee) * u128::from(RBFR_RATIO_DEN) * u128::from(old_v)
>= u128::from(direct_fee) * u128::from(RBFR_RATIO_NUM) * u128::from(new_v)
}

/// Admit replacement if BIP125-style rules **or** pure RBFR (Libre).
Expand Down Expand Up @@ -3036,6 +3034,11 @@ mod tests {
assert!(rbf_allows_replacement(
2_000, 4000, 50_000, 40_000, 1_000, 4000
));
// TESTING.md True journeys: pure arithmetic. A session cannot reach
// this product without a near-supply fee. Equal fees are not 1.25×.
// Saturating `u64` products both become `u64::MAX` and would pass.
let near = u64::MAX / 4 + 1;
assert!(!pure_rbfr_pays(near, 4000, near, 4000));
}

#[test]
Expand Down
Loading
Loading