Started Walet RPC auth work without adding MD5 Digest support

This commit is contained in:
2026-10-21 17:33:33 -04:00
parent f00ea55dfd
commit 40f4aa6d4e
7 changed files with 467 additions and 22 deletions
+2 -4
View File
@@ -19,9 +19,7 @@ The operator has authorized proceeding with implementation instead of the previo
**Financial storage update:** [ADR 003](postgres-financial-storage.md) selects PostgreSQL and records the integrated asynchronous custody backend, restricted runtime/schema roles, deferred accounting constraints, explicit SQLite freeze/import, and full dump/restore rehearsal. SQLite remains an opt-in-compatible local sandbox default, not an automatic fallback. Real custody and production operating acceptance remain blocked.
**Monero observation and deposit-address allocation groundwork:** [server/market/monero-observer.ts](../server/market/monero-observer.ts) keeps the existing observer client strictly read-only: mainnet wallet validation and bounded incoming scans, authenticated requests, strict HTTPS/literal-loopback-only HTTP, no redirects, bounded response/deadline, JSON-RPC ID validation and lossless integer handling. A separate, narrow `createMoneroDepositAddressRpc()` capability verifies a mainnet primary address with `get_address` plus `validate_address`, then derives a domain-separated fingerprint. It can inspect one indexed subaddress or request exactly one labeled subaddress; it exposes no transfer, relay, sweep or withdrawal operation. Actual testing against the verified Monero v0.18.5.4 Wallet RPC found that `get_wallet_info` returns JSON-RPC “Method not found” despite appearing in current docs; the implementation therefore does not depend on it. The allocator [server/market/monero-deposit-allocation-store.ts](../server/market/monero-deposit-allocation-store.ts) combines PostgreSQL v3 beneficiary/index reservations with this capability: it reserves first, serializes cooperating allocators per wallet/account, checks that the live wallet fingerprint matches the durable generation, checks the exact reserved index, and recovers a lost `create_address` response by looking up the deterministic allocation label before retrying creation. Actual v0.18.5.4 testing also confirmed that an unused address index returns RPC error `-15` (“address index is out of bound”), rather than an empty `addresses` array; the client recognizes only that exact error as “not created” and fails closed for other errors. Address registration is immutable and performed only after the wallet returns the expected index/address/label. The installed v0.18.5.4 interface does not provide a supported `get_wallet_info` query to attest the wallet type, so watch-only provisioning is an operator/deployment requirement, not a property this RPC client can prove. If another wallet client consumes indexes outside this allocator, the operation fails for reconciliation rather than reassigning an address; the wallet RPC must therefore be dedicated to the allocator. The configured wallet-generation UUID still requires controlled operator enrollment and backup. Neither client nor orchestration is wired to startup, routes, UI, deposit scans or financial posting. The registry remains inaccessible to both custody API and observer roles. Observation storage continues to record reorg/reappearance evidence only; no credit, debit, reversal or journal can be posted. Schema v1→v3 is explicit and additive. The test-target build succeeded; **185/185** offline tests and **35/35** disposable PostgreSQL tests passed, including rejection of wallet identity mismatch and simulated create-success/response-loss/recovery without duplicate address creation or journal posting. An actual wallet-RPC rehearsal on the authenticated official v0.18.5.4 archive passed in Docker `--network none`, `--stagenet`, `--offline`, loopback-only mode: it created a disposable watch-only wallet, allocated/labeled one subaddress, recovered by index after discarding the create response, and verified the same address/label after RPC restart. No daemon/network peers, funds, or production credentials were used; all generated wallet files were deleted with the temporary container. This remains test groundwork, not a public deposit allocator or live processor; mainnet payments remain disabled.
Validation: TypeScript/Vite build and 144 offline tests passed in the serial native-RandomX test run; the initial parallel run encountered a peer-gossip timeout. Browser smoke verified a disposable wallet's signed test credit, withdrawal hold and cancellation restoring the exact balance, plus a 390px viewport without horizontal overflow. No real funds were used. Tests and remaining acceptance gates are below; this is not launch readiness.
**Monero observation and deposit-address allocation groundwork:** [server/market/monero-observer.ts](../server/market/monero-observer.ts) keeps the existing observer client strictly read-only: mainnet wallet validation and bounded incoming scans, authenticated requests, strict HTTPS/literal-loopback-only HTTP, no redirects, bounded response/deadline, JSON-RPC ID validation and lossless integer handling. A separate, narrow `createMoneroDepositAddressRpc()` capability verifies a mainnet primary address with `get_address` plus `validate_address`, then derives a domain-separated fingerprint. It can inspect one indexed subaddress or request exactly one labeled subaddress; it exposes no transfer, relay, sweep or withdrawal operation. Actual testing against the verified Monero v0.18.5.4 Wallet RPC found that `get_wallet_info` returns JSON-RPC “Method not found” despite appearing in current docs; the implementation therefore does not depend on it. The allocator [server/market/monero-deposit-allocation-store.ts](../server/market/monero-deposit-allocation-store.ts) combines PostgreSQL v3 beneficiary/index reservations with this capability: it reserves first, serializes cooperating allocators per wallet/account, checks that the live wallet fingerprint matches the durable generation, checks the exact reserved index, and recovers a lost `create_address` response by looking up the deterministic allocation label before retrying creation. Actual v0.18.5.4 testing also confirmed that an unused address index returns RPC error `-15` (“address index is out of bound”), rather than an empty `addresses` array; the client recognizes only that exact error as “not created” and fails closed for other errors. Address registration is immutable and performed only after the wallet returns the expected index/address/label. The installed v0.18.5.4 interface does not provide a supported `get_wallet_info` query to attest the wallet type, so watch-only provisioning is an operator/deployment requirement, not a property this RPC client can prove. If another wallet client consumes indexes outside this allocator, the operation fails for reconciliation rather than reassigning an address; the wallet RPC must therefore be dedicated to the allocator. The configured wallet-generation UUID still requires controlled operator enrollment and backup. Neither client nor orchestration is wired to startup, routes, UI, deposit scans or financial posting. The registry remains inaccessible to both custody API and observer roles. Observation storage continues to record reorg/reappearance evidence only; no credit, debit, reversal or journal can be posted. Schema v1→v3 is explicit and additive. The test-target build succeeded; **187/187** offline tests and **35/35** disposable PostgreSQL tests passed, including rejection of wallet identity mismatch and simulated create-success/response-loss/recovery without duplicate address creation or journal posting. The mTLS gateway method allowlist and config guard have unit coverage; an end-to-end certificate handshake remains open.
**Security claim:** operator-custodied XMR, seller-authorized and host-attested NFT sale completion, with durable accounting and recoverable coordination. Not trustless, not an atomic Monero/NFT swap, not insured, and not an independently consensus-verified Monero payment. The operator can steal, censor, become insolvent or lose keys; segregation and review reduce but do not remove that risk.
@@ -154,4 +152,4 @@ Required failure outcomes: duplicate deposit credits are impossible; insufficien
Source review: 2026-10-20; documentation is capability evidence, not an audited implementation of this design. No wallet/RPC credentials or funds were accessed.
**Actual RPC integration blocker:** The v0.18.5.4 process rehearsal confirmed a login-protected wallet RPC returns HTTP 401 with a Digest challenge; sending Basic auth still returns 401. The current client therefore cannot authenticate to that configuration. Keep authenticated wallet RPC disabled until a reviewed compatible transport is implemented; do not disable authentication outside a strictly isolated test.
**Actual RPC integration blocker:** The v0.18.5.4 process rehearsal confirmed a login-protected Wallet RPC returns HTTP 401 with a Digest challenge; Basic auth also returns 401. The app does not implement legacy MD5 Digest. New groundwork replaces that idea with a local TLS 1.3 mTLS gateway and a client transport that emits no Authorization header. The gateway binds only to an explicitly configured private IP (never a wildcard/public interface), authenticates an allowlisted client certificate, permits only schema-bounded address/observation methods, and forwards to a fixed loopback Wallet RPC upstream. Wallet RPC would run without its own HTTP login only inside that protected boundary. This gateway is not deployed or wired to the application, and actual mTLS interoperability remains to be tested; do not enable wallet RPC access until the end-to-end certificate and isolation fixture passes.
+2 -2
View File
@@ -20,7 +20,7 @@ Status: active engineering plan; **not launch or payment authorization**. Update
**Current design deliverable:** [custodial market design](custodial-market-design.md). Read the workstreams below with this update: pooled customer liabilities replace per-order incoming invoices and external sale payouts in the proposed architecture. Earlier trustless-first research gates are historical, not a prerequisite to investigating custody. Exact ledger, withdrawal, fee, custody/legal and host-attested NFT consensus rules still require approval and evidence; the existing mock domain cannot authorize real balance debits.
**Monero observation and allocation groundwork:** the disabled-by-default observer remains read-only. The separate address RPC capability verifies a mainnet primary address using `get_address` and `validate_address` and derives a wallet fingerprint; it does not claim to attest wallet type. Actual testing found `get_wallet_info` is unavailable as JSON-RPC in v0.18.5.4, and Monero’s `--rpc-login` requires HTTP Digest while the current client sends Basic auth. Therefore authenticated RPC integration is **not yet compatible**; do not enable the client against a login-protected RPC. Watch-only wallet provisioning and isolated network placement must be enforced by deployment until a reviewed compatible auth/provisioning design is implemented. The internal allocator checks the primary-address fingerprint against the durable generation before creating, reserves beneficiary/index first, serializes cooperating allocators, and recovers create-success/lost-response by checking a stable label at the reserved index. It recognizes only the observed “address index is out of bound” error as an unused slot and fails closed on other RPC errors. Actual RPC verification is limited to the offline disposable rehearsal below; no application startup/routes/UI/scans or financial posting are wired, and the registry remains inaccessible to custody API and observer roles. Operational assumptions still include a dedicated wallet RPC, controlled generation enrollment/backups, and wallet/database reconciliation. The registry cannot establish unique output identity. Missing scans remain review evidence, not automatic balance changes. Verification passed: Docker test-target build; **185/185** offline tests; **35/35** disposable PostgreSQL tests, including v1/v2 migrations, allocator concurrency, replay, immutable registration, role isolation, zero journal postings, wallet mismatch rejection, the official -15 index response, and simulated response-loss recovery. No live RPC credentials, funds or mainnet wallet were used. Remaining deposit milestone: resolve authenticated RPC transport and watch-only provisioning, establish durable wallet-generation enrollment and recovery, pin per-output identity and canonical inclusion/lock/reorg semantics, then implement idempotent credit journals and audited reversal/hold handling before stagenet deposit-credit rehearsal or any real deposits.
**Monero observation and allocation groundwork:** the disabled-by-default observer remains read-only. The separate address RPC capability verifies a mainnet primary address using `get_address` and `validate_address` and derives a wallet fingerprint; it does not claim to attest wallet type. Actual testing found `get_wallet_info` is unavailable as JSON-RPC in v0.18.5.4, and `--rpc-login` requires legacy HTTP Digest/MD5. The app does not implement Digest or send Basic credentials; the new mTLS gateway/transport described below is not yet deployed or wired. Do not enable Wallet RPC until that end-to-end path passes its certificate and isolation tests. Watch-only wallet provisioning and network isolation must be enforced by deployment. The internal allocator checks the primary-address fingerprint against the durable generation before creating, reserves beneficiary/index first, serializes cooperating allocators, and recovers create-success/lost-response by checking a stable label at the reserved index. It recognizes only the observed “address index is out of bound” error as an unused slot and fails closed on other RPC errors. Actual RPC verification is limited to the offline disposable rehearsal below; no application startup/routes/UI/scans or financial posting are wired, and the registry remains inaccessible to custody API and observer roles. Operational assumptions still include a dedicated wallet RPC, controlled generation enrollment/backups, and wallet/database reconciliation. The registry cannot establish unique output identity. Missing scans remain review evidence, not automatic balance changes. Verification passed: Docker test-target build; **187/187** offline tests; **35/35** disposable PostgreSQL tests, including v1/v2 migrations, allocator concurrency, replay, immutable registration, role isolation, zero journal postings, wallet mismatch rejection, the official -15 index response, and simulated response-loss recovery. New gateway allowlist/config tests pass; no actual mTLS certificate handshake has yet been tested. No live RPC credentials, funds or mainnet wallet were used. Remaining deposit milestone: complete the mTLS gateway interoperability/isolation rehearsal, establish durable wallet-generation enrollment and recovery, pin per-output identity and canonical inclusion/lock/reorg semantics, then implement idempotent credit journals and audited reversal/hold handling before stagenet deposit-credit rehearsal or any real deposits.
**Initial actual-wallet rehearsal blocker (2026-10-21, superseded below):** no Monero wallet binary or pinned image was present locally, so the RPC contract could not yet be exercised against a real process. This was resolved by obtaining and verifying the official v0.18.5.4 archive and running the disposable offline Stagenet rehearsal recorded below. The recorded evidence does not authorize mainnet access, deposits, credits, or payments.
@@ -85,7 +85,7 @@ Acceptance: exact-amount property/boundary tests, versioned signature tests, zer
Can run alongside P0/P1. Addresses SEC-01/SEC-06 rather than adding more fixed caps.
**Implemented M2 increments, 2026-10-20–21:** [canonical indexes and durable market observation](canonical-indexes.md). Canonical ownership/transaction SQL indexes now serve NFT, deck, custody availability and mock-market queries; per-block undo and anchored connect/disconnect events commit with ledger updates. Market checkpoint/reorg holds persist atomically and bounded catch-up blocks new mutations. Order/listing reconciliation advances in durable, stable-ID keyset batches of at most 32 records per table, resumes after restart, and re-fences when the chain tip/revision changes. The HTTP process now uses a single worker thread to select/evaluate bounded row batches, read canonical facts using its own read-only Ledger connection, and atomically persist changes with cursor progress. The offline suite has **182 passing tests**; focused market tests passed 27/27; the disposable PostgreSQL suite passed 31/31 in the previous run. Regressions verify a main-loop timer runs during worker backlog and that a second server process cannot start against the same data directory. A synthetic 10,000 confirmed-delivery run with 160 loopback health/market requests measured worker HTTP p50/p95/max of 285/322/324 ms versus 1,416/2,844/2,971 ms synchronously. This single local run is preliminary (no repeated confidence intervals or realistic request arrivals), not an SLO. Main-thread event-page acquisition/post-batch fencing, realistic concurrent HTTP load, multi-process fencing beyond the existing exclusive directory lock, target hardware/data, production financial storage/recovery, retained-DAG capacity and operator SLO decisions remain open.
**Implemented M2 increments, 2026-10-20–21:** [canonical indexes and durable market observation](canonical-indexes.md). Canonical ownership/transaction SQL indexes now serve NFT, deck, custody availability and mock-market queries; per-block undo and anchored connect/disconnect events commit with ledger updates. Market checkpoint/reorg holds persist atomically and bounded catch-up blocks new mutations. Order/listing reconciliation advances in durable, stable-ID keyset batches of at most 32 records per table, resumes after restart, and re-fences when the chain tip/revision changes. The HTTP process now uses a single worker thread to select/evaluate bounded row batches, read canonical facts using its own read-only Ledger connection, and atomically persist changes with cursor progress. The offline suite has **187 passing tests**; focused market tests passed 27/27; the disposable PostgreSQL suite passed 31/31 in the previous run. Regressions verify a main-loop timer runs during worker backlog and that a second server process cannot start against the same data directory. A synthetic 10,000 confirmed-delivery run with 160 loopback health/market requests measured worker HTTP p50/p95/max of 285/322/324 ms versus 1,416/2,844/2,971 ms synchronously. This single local run is preliminary (no repeated confidence intervals or realistic request arrivals), not an SLO. Main-thread event-page acquisition/post-batch fencing, realistic concurrent HTTP load, multi-process fencing beyond the existing exclusive directory lock, target hardware/data, production financial storage/recovery, retained-DAG capacity and operator SLO decisions remain open.
**Next financial-storage increment:** [ADR 003 — PostgreSQL](postgres-financial-storage.md) selects and integrates the custody SQL backend with existing HTTP callers, exact constrained accounting, explicit migration/runtime roles, source-freezing SQLite import and dump/restore rehearsal. The adapter remains on the fictitious sandbox domain; it is not a production deposit/withdrawal worker. SQLite node-only backup deliberately refuses PostgreSQL-bound financial state. Production hardware/SLO tests, coordinated backup/PITR/failover, real payment schema/worker controls and independent review remain open, so this does not close M2/M4 or authorize funds.