taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

auto-refresh.rst (6942B)


      1 Automatic coin renewal
      2 ######################
      3 
      4 Wallet-core implements the September 2026 policy from
      5 :doc:`../design-documents/071-auto-refresh`, with deterministic greedy output
      6 selection. Wallet clients receive renewal information with each scoped balance.
      7 
      8 Selection and eligibility
      9 =========================
     10 
     11 For an input coin, let ``D`` be its deposit expiration, ``W`` its withdrawal
     12 expiration, ``R = D - now``, and ``E = min(90 days, (D - W) / 4)``. Days are fixed
     13 24-hour periods. Invalid or infinite lifetimes are reported; expired coins use
     14 existing expiration and recovery handling.
     15 
     16 The wallet considers compatible, verified, currently withdrawable denomination
     17 keys, excluding revoked and lost keys. It selects outputs greedily in descending
     18 face-value order, breaking ties by lower withdrawal fee, later deposit expiration,
     19 and denomination hash. The refresh protocol permits at most 64 outputs.
     20 This is deliberately best effort: it does not implement DD71's globally optimal
     21 value/lifetime/coin-count selection. Spending existing coins retains DD91's
     22 modified greedy algorithm and earliest-expiration preference.
     23 
     24 The earliest selected output expiration determines the output lifetime. Total
     25 cost includes melting fees, withdrawal fees, and unrepresentable remainder.
     26 The wallet requires positive recovered value and an extension of validity, then
     27 evaluates these strict conditions in order:
     28 
     29 * Output remaining lifetime exceeds four times the input remaining lifetime.
     30 * Input remaining lifetime is below 180 days, output remaining lifetime exceeds
     31   360 days, total cost is zero, and external power is confirmed.
     32 * Input remaining lifetime is below ``E``.
     33 
     34 Decision, accounting, and execution use the same selected outputs. Inputs reserved
     35 for payments or refreshes are unavailable for another automatic refresh. Before
     36 sending a melt, the wallet revalidates eligibility and selected keys. A request
     37 that might already have reached the exchange retains its original commitment
     38 through retry and recovery.
     39 
     40 Scheduling
     41 ==========
     42 
     43 A private random deadline per wallet and input denomination spreads renewal
     44 traffic. Before ``D - E / 10``, the delay is at most the minimum of one day,
     45 ``E / 10``, and half the time to that urgent boundary. Urgent inputs are due
     46 immediately. Restarting, updating keys, or reopening the application does not
     47 redraw or postpone a deadline. Temporarily ineligible inputs retain their deadline
     48 while the wallet waits for a valid plan. Retry backoff is randomized and capped
     49 by the time to urgency, or remaining lifetime once urgent.
     50 
     51 Background balance reporting
     52 ============================
     53 
     54 Renewal information is computed by the ``refresh-balance`` maintenance task and
     55 persisted by balance scope. A balance request only reads the saved report and its
     56 input generation; it does not load denominations, scan refresh history, or run
     57 output selection. The report survives closing and reopening the wallet.
     58 
     59 Changes to holdings, exchange keys and trust, refresh progress, and relevant
     60 retry errors invalidate the report in the same transaction as their inputs.
     61 The task reads a consistent snapshot, releases the database transaction, and
     62 computes the report while periodically yielding to other wallet work. It publishes
     63 only if the input generation is still current, then notifies balance clients.
     64 A changed generation causes another calculation instead of publishing stale data.
     65 
     66 Known warnings and recovery notices remain visible while a report is being
     67 updated. A cost bound is withheld when its generation, balance amount, or time
     68 validity no longer matches; clients see a checking indication until the new report
     69 is ready. An empty cache also returns a checking indication without blocking the
     70 balance request. The task schedules itself for the next relevant validity or key
     71 freshness boundary, with a daily upper limit between checks.
     72 
     73 Power observations
     74 ==================
     75 
     76 ``hintPowerState`` accepts ``{ powerSource: "external" | "battery" | "unknown" }``
     77 and returns an empty object. Observations are transient and expire after 60
     78 seconds: a host should refresh its current observation at least every 30 seconds.
     79 The browser integration uses supported battery observations and reports unknown
     80 for unsupported or inconclusive readings. Unknown power never enables the free
     81 opportunistic rule; necessary refreshes do not require external power.
     82 
     83 Balance warnings and recovery notices
     84 ====================================
     85 
     86 Each balance may contain ``refreshInfo`` with ``risks``, ``recoveries``, and
     87 ``annualCostBound``. Risks identify the exchange, amount and earliest expiration.
     88 They distinguish a pending renewal, a connection failure, an exchange error,
     89 unavailable suitable replacements established from fresh keys, a check in
     90 progress, and invalid validity dates. They do not assert device-wide offline
     91 status. Pending and failing renewals retain expiration indications until success.
     92 
     93 A completed group whose coins were close to expiration before melting supplies
     94 one recovery notice, including the new expiration and next relevant date.
     95 ``dismissWalletWarning`` accepts ``{ warningId: string }`` to persist dismissal.
     96 Active expiration risks cannot be dismissed. A renewal notice does not imply the
     97 wallet was previously offline.
     98 
     99 Conditional cost bound
    100 ======================
    101 
    102 The balance screen's expandable cost summary covers keeping the current balance
    103 for 365 days without payments or additional withdrawals. It is a conditional
    104 upper bound, not a predicted debit. It assumes continuously available compatible
    105 families with stable values, fees and lifetime bounds, and reveal completing
    106 before output withdrawal validity ends. Unpublished future offerings are a
    107 projection, not a signed commitment.
    108 
    109 Wallet-core checks all reachable compatible denominations, including small change,
    110 and includes actual greedy-selection losses. It establishes conservative bounds
    111 ``Gmin``, ``Hmax``, and loss fraction ``p``, then uses
    112 ``Delta = Gmin - Hmax / 4``, ``N = 1 + floor(365 days / Delta)``, and
    113 ``B * (1 - (1 - p)**N)``. Group bounds are rounded upward to Taler's supported
    114 amount precision before summing. Missing or stale information, unrefreshable
    115 change, nonpositive ``Delta`` and unsettled holdings make the estimate unavailable.
    116 Changed balances or offerings cause recomputation.
    117 
    118 The estimate excludes initial withdrawal fees, payment-related refreshes, and
    119 losses from expiration or outages. Keeping a wallet offline beyond its coin
    120 validity periods can still lose funds.
    121 
    122 Development experiments
    123 =======================
    124 
    125 With development mode enabled and an existing balance, use
    126 ``taler://dev-experiment/dd71-risk``, ``dd71-recovered``, or
    127 ``dd71-cost-unavailable`` to exercise the balance presentation. These transient
    128 fixtures do not alter coins. ``dd71-clear`` removes them. The browser demo also
    129 includes a pending risk, a dismissible recovery notice, and a cost bound.