proxy wallet: sweep quotes across per-epoch currency units #23
Loading…
Reference in a new issue
No description provided.
Delete branch "agent/multi-unit-sweeper"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The proxy's quote sweeper now mints quotes in every per-epoch currency unit, not just the
hashunit its wallet was built with.Before this, after the first epoch rotation the sweeper fetched new-unit quotes from the mint, stored them, and silently never minted them.
Discovery unions two quote sources: the unit-agnostic pubkey lookup and one unit-blind read of the wallet DB's unissued quotes, so a failing lookup endpoint cannot hide DB backlog; units are never derived from mint info.
The sweeper builds a cheap per-unit wallet handle on first sight of a unit and runs the same sweep (status check, then P2PK-locked batch mint) once per unit; all handles share the one wallet database, seed, and mint metadata cache, so nothing changes on disk.
The faucet, web UI, and quote notification path keep using the single
hash-unit wallet exactly as before.Per unit and pass the whole pipeline is bounded: at most 200 quotes are selected (locally-mintable-looking first) and processed in chunks of 50 per batch call, so one bad quote id can wedge at most its own chunk; a rotation backlog drains over successive 15-second passes.
The reconcile log reports unissued counts per unit, which is the standing signal for fetched-but-never-minted divergence.
Proof: cargo check, test, and clippy are green with 12 unit tests on the discovery and selection logic; the end-to-end rotation witness still needs the mint-side epoch branch (#16) and runs on the dev stack after both land.
If it misbehaves, revert the two commits on this branch; the wallet DB schema is untouched, so rollback is safe.
Closes vnprc/hashpool#17. Refs vnprc/hashpool#13.
Risk
Walletinstances run over one store in this process.Found N pending quotesto a per-unit summary line; anything scraping the old string would need updating.Validation
cargo check -p translator_sv2: clean.cargo test -p translator_sv2: 32 passed, 0 failed (20 pre-existing, 12 new: unit-set derivation including the DB-backlog union, sweep planning covering ready-first ordering, cap and chunk boundaries and edge cases, per-unit unissued summary formatting).cargo clippy -p translator_sv2 --all-targets: no new warnings. One pre-existing warning in untouchedchannel_manager.rstest code remains; a pre-existing useless-conversion warning inwallet.rswas removed by the rewrite.lib/mod.rsthe edited region was formatted and two pre-existing drift spots elsewhere in the file were deliberately left alone to keep the diff minimal.Adversarial review findings (read-only pass; fixes queued on this branch):
should-fix — unit discovery is hostage to the pubkey lookup. The sweep's unit set is fetched-quotes ∪ tracked-map ∪ base; the wallet DB is never enumerated. After a restart (tracked map empty), a persistent lookup failure that spares other endpoints (e.g. mint stops advertising a NUT-06 pubkey →
MissingPubkey, or a NUT-XX regression — it's a fork-only extension) leaves foreign-unit unissued quotes in the DB unswept forever, while the base unit sweeps normally — and the per-unit reconcile log only covers units in the sweep set, so the advertised "fetched but never minted" divergence signal is blind to exactly this case. Transient failures are genuinely fine (quotes stay mintable server-side; next pass recovers). Fix: union in units from one unit-blindlocalstore.get_unissued_mint_quotes()call (zero network; the design doc forbids deriving from mint info, not from the local store) — this also makes the reconcile log cover every unit with DB backlog.should-fix — the 200/unit cap bounds only
batch_mint; stamping andbatch_check_mint_quote_statusstay unbounded. A large rotation backlog (the motivating case) produces one giant status-check POST; if that call fails (size limits, future mint-side batch cap), the unit retries the identical unbounded call every 15s with zero progress — and mint-sidecheck_mint_quotesfails the whole batch on one unknown quote id, so a single pruned quote can block all other mintable value in its unit. Inherited shape, but this PR introduces the boundedness claim. Fix: cap/chunk the pending set before stamping and status-check; add per-unit backoff or poisoned-quote eviction.nits — units with permanently-unmintable (e.g. expired-unpaid) quotes are tracked forever, scanning + batch-checking + logging every 15s across epochs (fold terminal-state eviction into the above); the
tokio::sync::Mutex<HashMap>has exactly one holder ever — safe, verified no deadlock — but&mutowned by the loop would express the truth;WalletBuilder::build()writesset_ttl(Some(3600))on the shared metadata cache per handle build (no-op today, silently resets any future custom TTL); two Risk bullets mischaracterize: "a lookup outage delays foreign-unit sweeping until the mint is reachable again" conflates endpoint-specific failure with mint unreachability, and "unpaid foreign-unit quotes are only re-checked once the mint reports them mintable" is false while a unit is tracked (they're batch-checked every pass — safe direction, still wrong).Verified clean: eviction is provably safe under transient errors (drop only on a successful zero-row DB read); the metadata cache and localstore are genuinely shared (Arc identity, keyed by data pointer); faucet/notification wiring bitwise-equivalent; P2PK conditions and SplitTarget identical per-unit; all body validation claims reproduced exactly (29/0 tests, the clippy and fmt statements, 3-file diff, single revertable commit); zero file overlap with #24 so merge order is free — but note the merged system needs #24's cdk pin (
3dea7086) for old-epoch quotes to stay checkable after processor retirement, and the e2e rotation witness (honestly disclosed as not-run) is what covers the combination.Verdict: mergeable — no blockers; land the two should-fixes before #18 makes big backlogs routine.
Both should-fixes landed in
c38658bf; PR body updated to match.localstore.get_unissued_mint_quotes()call (verified at cba8469b the unit filter is a wallet-level retain, not SQL), so DB backlog is swept and shows in the per-unit reconcile log even when the lookup endpoint fails persistently.The two mischaracterized Risk bullets are corrected in the body. Tests now 32/0 for the package (12 sweeper units covering the union and the selection/chunk planner); clippy and fmt unchanged. Terminal-state eviction and the remaining nits are left as-is per scope.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.