Keep the fee-rate ceiling below the node's maxfeerate (B-100)
MAX_FEE_RATE_SAT_VB was exactly sendrawtransaction's default maxfeerate (10 000 sat/vB); with vsize estimated upwards a rate at the ceiling would be refused. Now 5 000. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2c0e71a74c
commit
cef05943f9
5 files changed
+25
-25
No files matched your search
@@ -30,8 +30,10 @@ DUST_LIMIT_SATS = 294
|
||||
# reason MIN_PASSWORD_LENGTH is shared in auth/security.py) and tx/broadcast.py's RBF
|
||||
# bump escalation, which refuses to bump a pending_transaction past this rate (B-32) —
|
||||
# without a ceiling, a stuck transaction's fee climbed by 1 sat/vB every bump forever,
|
||||
# eating further and further into the sender's change with no limit.
|
||||
MAX_FEE_RATE_SAT_VB = 10_000
|
||||
# eating further and further into the sender's change with no limit. B-100: half of the node's own
|
||||
# `sendrawtransaction` maxfeerate (0.1 PLM/kvB = 10 000 sat/vB, palladiumcore rpc/rawtransaction.cpp):
|
||||
# vsize is estimated upwards, so a rate sitting exactly on the node's limit would be refused.
|
||||
MAX_FEE_RATE_SAT_VB = 5_000
|
||||
|
||||
# Ceiling on how many UTXOs one *user* transaction (bet, withdrawal) may spend (B-48).
|
||||
# Every extra input costs ~68 vbytes of fee, and that fee comes out of the amount being
|
||||
|
||||
+4
-4
@@ -50,7 +50,7 @@ esiste una API separata per l'amministrazione, solo un'autenticazione diversa.
|
||||
| `GET` | `/admin/pending-transactions` | admin | [API-38](#get-adminpending-transactions) |
|
||||
| `GET` | `/admin/bug-reports` | admin | [API-39](#get-adminbug-reports) |
|
||||
| `POST` | `/admin/bug-reports/{report_id}/status` | admin | [API-40](#post-adminbug-reportsreport_idstatus) |
|
||||
| `GET` | `/admin/electrum` | admin | [API-47](#get-adminelectrum) — *da implementare (B-86, B-92)* |
|
||||
| `GET` | `/admin/electrum` | admin | [API-47](#get-adminelectrum) — *da implementare (B-92)* |
|
||||
| `GET` | `/health` | nessuna | [API-41](#get-health) |
|
||||
| `GET` | `/health/ready` | nessuna | [API-46](#get-healthready) — *da implementare (B-92)* |
|
||||
| `GET` | `/`, `/admin`, `/guida`, `/report-bug` | nessuna | [API-42](#pagine-e-file-statici) |
|
||||
@@ -770,7 +770,7 @@ dei parametri operativi in
|
||||
| `bet_amount_sats` | > 0 e ≤ 10 000 000 000 000 (100 000 PLM) |
|
||||
| `round_duration_seconds` | 30 – 604 800 (7 giorni) |
|
||||
| `round_cooldown_seconds` | 0 – 86 400 |
|
||||
| `fee_rate_sat_vb` | 1 – 10 000 (`MAX_FEE_RATE_SAT_VB`) |
|
||||
| `fee_rate_sat_vb` | 1 – 5 000 (`MAX_FEE_RATE_SAT_VB`) |
|
||||
| `rbf_timeout_seconds` | 60 – 604 800 |
|
||||
| `draw_animation_seconds` | 0 – 600 |
|
||||
| `deposit_confirmations` | 1 – 100 |
|
||||
@@ -941,7 +941,7 @@ dei parametri operativi in
|
||||
ferma, [connessione-electrum.md](connessione-electrum.md) ELC-21).
|
||||
*Codice:* `app/api/routes/admin.py`, `app/electrum/listener.py:ElectrumListener.current_endpoint` ·
|
||||
*Test:* —
|
||||
*Stato:* da implementare (B-86, B-92) · *Oggi:* l'endpoint non esiste;
|
||||
*Stato:* da implementare (B-92) · *Oggi:* l'endpoint non esiste;
|
||||
`/admin` mostra solo l'altezza della catena letta da `GET /rounds/current`.
|
||||
|
||||
#### GET /admin/bug-reports
|
||||
@@ -986,7 +986,7 @@ dei parametri operativi in
|
||||
**tutte** queste condizioni sono vere, altrimenti `503` con lo stesso corpo e
|
||||
`"status": "not_ready"`:
|
||||
- la connessione Electrum è attiva (`listener.client` non nullo);
|
||||
- l'ultimo header è stato accettato da meno di 360 secondi
|
||||
- l'ultimo header è stato accettato da meno di 1800 secondi
|
||||
([connessione-electrum.md](connessione-electrum.md) ELC-29);
|
||||
- lo scheduler dei round ha battuto da meno di 30 secondi (il battito si
|
||||
aggiorna a ogni giro e a ogni iterazione dell'attesa del blocco di
|
||||
|
||||
+13
-15
@@ -53,8 +53,8 @@ leggono dalla rete, non da una tabella:
|
||||
| Riserva del pool (il "pool" unico di oggi) | `m/84'/746'/0'/1/0` | nessuna tabella; `app/wallet/hd.py:derive_pool_key` |
|
||||
| Montepremi di un round | `m/84'/746'/0'/2/<round_id>` | `rounds.pool_address` ([DAT-60]) |
|
||||
|
||||
Il diagramma descrive lo schema **atteso**; le colonne e la tabella marcate
|
||||
"da implementare" non esistono ancora (vedi le tabelle di dettaglio).
|
||||
Il diagramma descrive lo schema **atteso**; ciò che non esiste ancora è
|
||||
marcato *da implementare* nelle tabelle di dettaglio.
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
@@ -103,11 +103,11 @@ erDiagram
|
||||
bigint max_round_pool_sats "snapshot"
|
||||
int draw_confirmations "snapshot"
|
||||
string pool_address
|
||||
string server_seed_enc "cifrato fino alla rivelazione (da implementare)"
|
||||
string server_seed "in chiaro solo dopo la rivelazione (da implementare)"
|
||||
string server_seed_hash "da implementare"
|
||||
string participants_hash "da implementare"
|
||||
int draw_height "da implementare"
|
||||
string server_seed_enc "cifrato fino alla rivelazione"
|
||||
string server_seed "in chiaro solo dopo la rivelazione"
|
||||
string server_seed_hash
|
||||
string participants_hash
|
||||
int draw_height
|
||||
datetime drawing_started_at
|
||||
int draw_block_height
|
||||
string draw_block_hash
|
||||
@@ -118,7 +118,7 @@ erDiagram
|
||||
bigint fee_amount_sats
|
||||
bigint bump_reserve_sats
|
||||
string payout_txid
|
||||
datetime payout_blocked_at "da implementare"
|
||||
datetime payout_blocked_at
|
||||
}
|
||||
round_participants {
|
||||
int id PK
|
||||
@@ -126,10 +126,10 @@ erDiagram
|
||||
int user_id FK
|
||||
bigint bet_amount_sats
|
||||
string bet_txid
|
||||
int bet_vout "da implementare"
|
||||
int bet_vout
|
||||
datetime broadcast_at
|
||||
datetime confirmed_at
|
||||
int draw_position "UK con round_id (da implementare)"
|
||||
int draw_position "UK con round_id"
|
||||
string status "building broadcast confirmed reorged_out"
|
||||
}
|
||||
round_config {
|
||||
@@ -142,10 +142,10 @@ erDiagram
|
||||
int fee_rate_sat_vb
|
||||
int rbf_timeout_seconds
|
||||
int deposit_confirmations
|
||||
int draw_confirmations "da implementare"
|
||||
int draw_confirmations
|
||||
bigint max_round_pool_sats
|
||||
bool paused
|
||||
string paused_reason "da implementare"
|
||||
string paused_reason
|
||||
datetime updated_at
|
||||
}
|
||||
pending_transactions {
|
||||
@@ -709,8 +709,6 @@ Una scommessa: un utente in un round.
|
||||
`app/tx/reconcile.py:_abandon` · `app/bets/confirmation.py:_on_bet_confirmed` ·
|
||||
*Test:* `tests/unit/test_bets.py`, `tests/unit/test_confirmation.py`,
|
||||
`tests/unit/test_reconcile.py`, `tests/unit/test_pool_verification.py`
|
||||
*Stato:* da implementare (B-76) · *Oggi:* qualunque eccezione del broadcast
|
||||
cancella la riga come un rifiuto.
|
||||
|
||||
- **[DAT-25]** `broadcast_at` è l'istante della fase 1 di `place_bet`, appena
|
||||
prima del broadcast, e non viene mai riscritto (nemmeno da un bump RBF). Non
|
||||
@@ -774,7 +772,7 @@ senza riavviare (vedi [limiti-noti.md](limiti-noti.md)).
|
||||
| `round_duration_seconds` | Integer | `600` | 30 s – 7 giorni | Durata del round | Dal round **successivo** ([RND-05](ciclo-di-vita-del-round.md)) |
|
||||
| `round_cooldown_seconds` | Integer | `30` | 0 s – 24 h | Pausa dopo la chiusura | Dal round **successivo**: la pausa dopo il round in corso è quella copiata alla sua apertura ([RND-05](ciclo-di-vita-del-round.md)) |
|
||||
| `draw_animation_seconds` | Integer | `20` | 0 – 600 s | Durata minima dell'animazione dell'estrazione nel frontend; non condiziona l'estrazione vera | Subito (letto da `GET /rounds/current`) |
|
||||
| `fee_rate_sat_vb` | Integer | `1` | 1 – `MAX_FEE_RATE_SAT_VB` (10 000) | Commissione di rete delle nuove transazioni | Subito, per le transazioni costruite dopo; quelle in volo tengono il proprio `fee_rate_sat_vb` |
|
||||
| `fee_rate_sat_vb` | Integer | `1` | 1 – `MAX_FEE_RATE_SAT_VB` (5 000) | Commissione di rete delle nuove transazioni | Subito, per le transazioni costruite dopo; quelle in volo tengono il proprio `fee_rate_sat_vb` |
|
||||
| `rbf_timeout_seconds` | Integer | `900` | 60 s – 7 giorni | Dopo quanto senza conferme si fa un bump RBF | Subito, anche per le transazioni già in volo (il bumper lo rilegge a ogni giro) |
|
||||
| `deposit_confirmations` | Integer | `6` | 1 – 100 | Conferme richieste per accreditare un deposito ([DAT-62]) | Subito, per gli accrediti successivi; gli output già accreditati restano |
|
||||
| `draw_confirmations` | Integer | `3` | 1 – 20 | Conferme richieste sul blocco di estrazione ([DAT-62]) | Dal round **successivo**, copiato all'apertura ([DAT-61]) |
|
||||
|
||||
+2
-2
@@ -618,7 +618,7 @@ con `docker compose logs app` ([architettura.md](architettura.md) ARC-09).
|
||||
e il suo valore va in commissione, e quella sostituzione è l'ultima
|
||||
(`change_too_small` ai tentativi successivi). Non si può fare nemmeno se
|
||||
l'uscita non esiste o non basta all'aumento minimo, o se la commissione è già
|
||||
al massimo (10.000 sat/vB, `max_fee_rate`); `replacement_rejected` è una
|
||||
al massimo (5.000 sat/vB, `max_fee_rate`); `replacement_rejected` è una
|
||||
sostituzione che la rete ha rifiutato esplicitamente. Un pagamento ha un'uscita di riserva
|
||||
(B-79) che l'aumento riduce; la riserva è dimensionata per arrivare a circa
|
||||
10 sat/vB, oltre la quale (o per un pagamento costruito prima di B-79, che
|
||||
@@ -894,7 +894,7 @@ proposito.
|
||||
| 6 | Riorganizzazione di 1 blocco | Solo su una rete di prova con due minatori, se disponibile | La punta segue il ramo nuovo senza chiudere la sessione; `chain_reorg_detected` con profondità 1; nessuna pausa. Con profondità 2: pausa con motivo `reorg` (B-85, B-74) |
|
||||
| 7 | Cronologia molto lunga | Indirizzo con risposta oltre 64 KiB (per esempio mille piccoli invii a un indirizzo di prova) | La connessione resta aperta (limite di 16 MiB); le uscite sotto `DUST_LIMIT_SATS` non vengono accreditate (B-75) |
|
||||
| 8 | Tutte le riserve giù | Bloccare con il firewall ogni server di `ELECTRUM_FALLBACK_SERVERS` | Accrediti rinviati, estrazione in attesa, nessuna spesa esterna registrata, nessun denaro mosso; al ritorno dei server tutto riprende. Un avvio con meno di 2 riserve è rifiutato (B-84) |
|
||||
| 9 | Server connesso ma fermo | Un server Electrum di prova che smette di seguire la catena | Dopo 360 secondi senza avanzamento il listener passa a un server con una punta più alta (B-86); `GET /health/ready` risponde 503 nel frattempo (B-92) |
|
||||
| 9 | Server connesso ma fermo | Un server Electrum di prova che smette di seguire la catena | Dopo 360 secondi senza avanzamento il listener passa a un server con una punta più alta (B-86); `GET /health/ready` risponde 503 solo oltre 1800 secondi senza header (B-92) |
|
||||
| 10 | Salto dell'orologio | Portare avanti l'orologio dell'host di 7 ore con transazioni `pending` | Nessuna transazione abbandonata per il solo tempo trascorso (B-78) |
|
||||
| 11 | Disco pieno | Riempire il filesystem di `./data/db` durante l'attività | Nessuna transazione trasmessa senza la sua riga salvata prima; scommesse e prelievi falliscono prima dell'invio; liberato lo spazio, il sistema riprende senza interventi sul database |
|
||||
| 12 | Ripristino da backup | Backup, poi un round completo e una registrazione, poi [OPS-07] | Avvio in pausa con `START_PAUSED=true`; `restore_gap_detected` e registrazioni rifiutate; il round rigiocato non viene pagato una seconda volta (B-90, B-80, B-82) |
|
||||
|
||||
@@ -217,10 +217,10 @@ sostituibilità fin dal primo invio.
|
||||
*Codice:* `app/tx/broadcast.py:RbfBumper._tick`, `app/tx/broadcast.py:should_bump` ·
|
||||
*Test:* `tests/unit/test_broadcast.py`
|
||||
- **[TX-10]** La nuova commissione punta a 1 sat/vB in più della tariffa
|
||||
registrata (`_FEE_RATE_INCREMENT`), senza superare 10.000 sat/vB
|
||||
registrata (`_FEE_RATE_INCREMENT`), senza superare 5.000 sat/vB
|
||||
(`MAX_FEE_RATE_SAT_VB`); l'aumento assoluto non è mai inferiore alla
|
||||
dimensione stimata della transazione per 1 sat/vB, il minimo richiesto da
|
||||
BIP125 per una sostituzione. Una riga già a 10.000 sat/vB non viene più
|
||||
BIP125 per una sostituzione. Una riga già a 5.000 sat/vB non viene più
|
||||
accelerata. Gli importi delle monete spese sono letti dalle transazioni
|
||||
precedenti come interi in satoshi.
|
||||
*Codice:* `app/tx/broadcast.py:bump_fee`, `app/tx/broadcast.py:_prevout_amount` ·
|
||||
|
||||
Reference in new issue
Block a user