Skip to content

dash(G1): deterministic equal-feerate tx selection (byte-parity seam) - #623

Merged
frstrtr merged 2 commits into
masterfrom
dash/g1-txselect-determinism
Jul 4, 2026
Merged

dash(G1): deterministic equal-feerate tx selection (byte-parity seam)#623
frstrtr merged 2 commits into
masterfrom
dash/g1-txselect-determinism

Conversation

@frstrtr

@frstrtr frstrtr commented Jul 3, 2026

Copy link
Copy Markdown
Owner

G1 byte-parity — next non-deterministic seam after curtime (#622)

The embedded-GBT template builder serializes txs in the order get_sorted_txs_with_fees() returns. That index was a std::multimap<double,uint256>, so equal-feerate txs stayed in mempool insertion order — node-dependent. Two nodes with identical mempool contents but different arrival order produced different template bytes: a non-deterministic seam breaking G1 byte-parity vs the p2pool-dash / dashcore oracle. Independent of #622 (does not touch curtime).

Fix

Replace the index with a FeeKey set sorting feerate-desc, then txid-asc — matching dashcore CompareTxMemPoolEntryByAncestorFee (breaks feerate ties by GetHash()). Selection is byte-reproducible regardless of tx arrival order; removal becomes O(log n) direct erase.

Scope / safety

  • Fenced to src/impl/dash/coin/mempool.hpp + test/test_dash_mempool.cpp. No shared/other-coin tree.
  • No consensus-value change: same tx set, same fees; only tie-order among equal-feerate txs is now deterministic (and oracle-conformant).

Verify (non-hollow, Linux x86_64, from build/)

  • ctest -R DashMempool -> 10/10 passed, 0 failed out of 10.
  • New KAT EqualFeerateSelectionIsTxidAscendingAndInsertionOrderIndependent: identical equal-feerate sets added in opposite orders yield the SAME selection, txid-ascending.

No self-merge — surfacing for integrator verify (oracle tiebreak + full rollup) then operator tap.

frstrtr added 2 commits July 3, 2026 22:49
Block-template tx ordering was the next non-deterministic seam after the
curtime seam (#622): get_sorted_txs_with_fees streamed a
std::multimap<double,uint256>, so equal-feerate txs kept mempool
INSERTION order — node-dependent, breaking G1 byte-parity of the
embedded-GBT template projection against the p2pool-dash/dashcore oracle.

Replace the index with a FeeKey set sorting feerate-desc then txid-asc,
matching dashcore CompareTxMemPoolEntryByAncestorFee (GetHash tiebreak).
Selection is now byte-reproducible regardless of arrival order.

Fenced to src/impl/dash/coin/mempool.hpp + test. No shared/other-coin
tree, no consensus-value change (same txs, deterministic order). KAT
pins equal-feerate ties resolve txid-ascending, insertion-independent.
…vided double

FeeKey keyed the sorted index on a pre-divided double (fee/base_size).
That division rounds, so it can collapse a strict dashcore order into a
tie -- or split a dashcore tie into a strict order -- diverging the
selection order (and thus template byte-serialization) from the
p2pool-dash/dashcore oracle. dashcore CompareTxMemPoolEntryByAncestorFee
avoids division by cross-multiplying (fee, size) as doubles; FeeKey now
carries (fee, base_size) and reproduces that exact comparison. Equal
feerate still breaks by txid ascending (GetHash), as the oracle does.

Adds an exhaustive-search divergence-vector KAT that pins the
cross-multiply against an independent oracle reimplementation and the
real std::set<FeeKey> index. Fenced to src/impl/dash/coin/mempool.hpp +
test/test_dash_mempool.cpp; no shared/other-coin/consensus reach.
@frstrtr
frstrtr merged commit 45e1cae into master Jul 4, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant