poll_once marked a transaction confirmed on one server's `height > 0`, and
reinstate_reappeared_utxos restored a coin written off as spent outside the platform on
the active server's word alone, so a hostile active server could report a
never-relayed payout as confirmed (winner unpaid, round closed) or put a spent coin
back into a balance.
- electrum/merkle.py: pure merkle-branch verification against a block header.
- ElectrumListener.confirmation_proven(txid, height): the *other* servers are asked for
blockchain.transaction.get_merkle; a strict majority of at least the quorum minimum
must return a proof that recomputes to the merkle root of that block's header (block
height and position checked too). The header is the tip the listener holds, or for an
older block the one a majority of the quorum agrees on and that meets its own target;
a height above our tip cannot be proven. Quorum rules are _corroborate_majority's.
- poll_once takes the listener as `network`: the active server's history only nominates
a candidate (txid, height); the row confirms only when the proof holds, and stays
pending otherwise. With no network nothing confirms. ConfirmationPoller wires it.
- The reconciler's late-confirmation check of failed rows (B-78) now puts each claimed
(txid, height) to the same proof instead of counting histories.
- refresh_user splits reinstatement like a credit: find_reinstate_candidates (read-only;
same outpoint, recorded amount, confirmed) -> corroborate_utxo_reinstatement (same
quorum as a credit) -> reinstate_reappeared_utxos writes only what was corroborated,
rechecking the mark under the lock. Nothing is committed in the read phase any more.
- Broadcast fan-out, the third part of the finding, shipped with B-76.
Tests changed because the spec changed: every poll_once call now passes a network that
proves (FakeNetwork) — the confirmation tests are otherwise unchanged; the failed-row
"quorum does not confirm" test now asserts the claim goes to the proof.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Una decisione di progetto = un file. Ogni ADR spiega perché una scelta è stata fatta (contesto, alternative scartate, conseguenze); le regole verificabili che la attuano restano nei documenti di dominio con il loro PREFISSO-NN. Così ogni informazione ha un solo proprietario: l'ADR possiede il perché, il requisito possiede il cosa, il codice il come. Regole: processo-di-modifica.md. Modello per i nuovi: TEMPLATE.md.
Gli identificativi ADR-NN sono stabili e non si riusano (i primi 52 coincidono con i vecchi DEC-NN). Un ADR superato non si cancella: passa a Sostituita da ADR-MM.
I depositi richiedono deposit_confirmations conferme (6 per default, configurabile in round_config), le uscite coinbase 120; ogni altra transazione ne richiede 1
Ogni transazione utente conserva un'uscita di resto verso l'utente, e un'accelerazione che porterebbe quel resto sotto DUST_LIMIT_SATS (294 sat) lo elimina