Commit Graph
2 Commits
Author SHA1 Message Date
davideandClaude Sonnet 5.5 fd6a91e93d Give every round its own pool address (B-80, RND-35, DAT-60, DAT-11, REG-14, SEC-08, BET-12, RND-22, WDR-14, SEC-43, API-23, API-36)
All bets of all rounds paid one address (m/84'/746'/0'/1/0), so its history
grew forever, other rounds' money and stray coins mixed with a round's own, and
the payout picked from everything it held.

- hd.py: derive_pool_key/derive_pool_address(round_id) on branch 2
  (m/84'/746'/0'/2/<round_id>); no argument is the reserve address 1/0.
  derive_round_pool_key checks the key against the address stored on the round,
  so a payout can never be signed for money its key does not control.
- rounds.pool_address (migration 477bddae1a84, existing rounds backfilled with
  the reserve address since that is where their bets went; add_column, not a
  batch alter, so the expression indexes stay): written in the transaction that
  inserts the round, once its id exists.
- place_bet pays round.pool_address; the payout reads, signs and takes change at
  the round's own address; own_address_for and bump_fee's _signing_context follow
  the round (confirmation poller and reconciler pass round_id).
- Withdrawals to any round pool address, the reserve address or fee_address are
  refused (withdrawal_to_platform_address, 400, all seven languages).
- GET /rounds/current and GET /admin/rounds expose pool_address.
- RND-22/DAT-11 stay "da implementare" for B-82: the payout still spends every
  confirmed coin at the round's address, not only the participants' outpoints
  (participants carry no bet_vout yet).
- tests/unit/conftest.py: every test now gets a throwaway master key. Opening a
  round derives an address, and tests that merely opened a round were silently
  reading the real key from the local .env.
- Existing tests changed because the spec changed: payout fixtures give their
  round a pool_address; the reconciler's address-cache test uses two payouts of
  one round (rows of different rounds no longer share an address);
  own_address_for now takes the round id.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 13:52:32 +02:00
davide 4124dc08e6 Check confirmation/existence via scripthash history, not verbose replies (B-41)
poll_once and reconcile.py's existence check both called
blockchain.transaction.get(txid, verbose=True). Several Electrum server
implementations and versions reject the verbose flag outright
("verbose transactions are currently unsupported"), which would have
meant no confirmations and no reconciliation ever running against such
a server, read as a plain transport error. reconcile.py additionally
decided whether to abandon a transaction - releasing its funds - by
substring-matching the error text ("missing", "not found", ...), which
only works against ElectrumX's specific wording.

Both now ask blockchain.scripthash.get_history for the address that
owns every input of the transaction (a user's own address for a
bet/withdrawal, the pool address for a payout) and look for the txid in
the result: present with height > 0 means confirmed, present with
height <= 0 means still in the mempool, absent means the server
doesn't know it. get_history is a plain, universally-supported Electrum
method, and "not in the list" replaces the old substring-matching
entirely - no more guessing at error wording to decide whether to
release funds. History is cached per scripthash within one pass, since
every "payout" row shares the same pool address.

New app/tx/pending_address.py factors out own_address_for (the
address derivation was previously duplicated informally inside
tx/broadcast.py's signing context) so confirmation.py and reconcile.py
share one definition instead of two that could compute different
addresses for the same row.

tests/unit/test_confirmation.py and test_reconcile.py needed real User
rows and a master-key bootstrap they didn't have before, since address
derivation is now exercised for real rather than assumed. Suite grows
from 217 to 222 tests. BUGS.md moves B-41 to Previously fixed - no
Medium-severity finding remains open.
2026-07-27 15:27:58 +02:00