test(fake-daemon): add slow rescan and key-import methods

fake_dragonxd now answers rescan, importprivkey, z_importkey and
z_importviewingkey, so the GUI's long wallet RPCs can be reproduced
without a real node.

- Each one holds cs_main for FAKE_RESCAN_SECS (default 0). The lock-free
  getrescaninfo reports the scan while it runs, and, like v1.3.0, the
  scan stops early when a shutdown is requested.
- Argument checks, error codes and return values follow dragonxd
  (z_importkey returns null, importprivkey the t-address, the default
  "whenkeyisnew" skips a known key, z_importviewingkey needs its zaddr).
  Keys are only prefix-checked and never stored or logged; an imported
  spending key gets a made-up address that the address lists then show.
- FAKE_ENCRYPTED=1 / FAKE_WALLET_PASSPHRASE: an encrypted wallet that
  starts locked, with walletpassphrase (-14 on a wrong passphrase),
  walletpassphrasechange, walletlock and getwalletinfo unlocked_until;
  the imports answer -13 while it is locked. As in dragonxd, the right
  passphrase with a non-integer timeout unlocks first and only then
  fails (-1): the wallet stays unlocked with no relock timer of its
  own. A timer pending from an earlier unlock keeps running; otherwise
  only walletlock locks it again. Without FAKE_ENCRYPTED, those three
  methods answer -15 like dragonxd.
- FAKE_METHODS_ALL call events show keys and passphrases as <redacted>.

A plain run is unchanged: the same 63 GUI calls before and after, and
identical replies to every one of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 13:22:00 -05:00
co-authored by Claude Opus 5.5
parent 78e38570a8
commit b3a57b07ad
2 changed files with 323 additions and 3 deletions
+23 -1
View File
@@ -37,6 +37,22 @@ What it copies from the real daemon (DragonX v1.3.0):
Its replies are canned: `getinfo` reports version `1030050`, the balance is fixed, and there are two
peers on TEST-NET addresses. Unknown methods get the real `-32601 Method not found` (HTTP 404).
Rescan, key imports and wallet encryption follow dragonxd's argument checks, error codes and return values:
- `rescan`, `importprivkey`, `z_importkey` and `z_importviewingkey` run a wallet scan that holds `cs_main`
for `FAKE_RESCAN_SECS`. While it runs, `getrescaninfo` (lock-free) reports `rescanning` with its progress,
and a `Still rescanning` line is logged once a minute. Like v1.3.0, the scan stops early when a shutdown
is requested. `z_importviewingkey` needs its 4th argument (the zaddr), as in dragonxd.
- Keys are only prefix-checked: a 51/52-character base58 WIF, `secret-extended-key-main1…` or `zivks1…`.
Only a fingerprint is kept; the keys are never stored or logged. An imported spending key gets a
made-up address, which `z_listaddresses`/`getaddressesbyaccount` list from then on. A second import of
the same key with the default `whenkeyisnew` returns at once, with no scan.
- With `FAKE_ENCRYPTED=1` the wallet is encrypted and starts locked. `walletpassphrase` (a wrong passphrase
gives `-14`), `walletpassphrasechange` and `walletlock` work, `getwalletinfo` carries `unlocked_until`,
and the imports answer `-13` while the wallet is locked. As in dragonxd, the right passphrase with a
non-integer timeout unlocks first and then fails (`-1`), so the wallet stays unlocked with no relock.
Without it those three methods answer `-15` ("running with an unencrypted wallet"), like dragonxd.
## Events file
Everything that matters for a test is appended to `<datadir>/fake_dragonxd.events`, one
@@ -54,6 +70,10 @@ Everything that matters for a test is appended to `<datadir>/fake_dragonxd.event
| `http-interrupted`, `shutdown-begin` | shutdown progress |
| `stats ...` | counters, every 30 s when they change |
| `methods ...` | the 10 most-requested JSON-RPC methods with counts (with `stats`, and at exit): what the GUI is polling |
| `rescan-begin m= from=`, `rescan-end m= ms=` | a wallet scan (`rescan` or an import) took and released `cs_main` |
| `rescan-interrupted m= at= ms=` | a shutdown request ended the scan early |
| `import m= addr= rescan=` | a key was imported (`known=1`: it was already in the wallet) |
| `walletpassphrase result=`, `walletpassphrasechange result=`, `walletlock` | `FAKE_ENCRYPTED` wallet calls (`ok` or `-14`) |
| `clean-exit ...` | **graceful exit**, with final counters. If this is missing, the process was killed. |
## Build
@@ -124,11 +144,13 @@ inherits the GUI's environment.
| `FAKE_MERGE_SECS` | 6 | how long a `z_mergetoaddress` operation runs before it succeeds |
| `FAKE_MERGE_SERIAL` | 0 | `1` = ops run one at a time, like dragonxd's single async worker: a new op is `queued` until the previous one finishes |
| `FAKE_MERGE_FAIL` | (off) | `syncing:N` (the Nth and later merges fail with the THROW_IF_SYNCING text), `lockedkey:N` (-8 "Could not find spending key…" after the scan), `opfail:N` (the Nth and later ops end `failed`, their notes unlocked) |
| `FAKE_RESCAN_SECS` | 0 | `rescan` and the key imports (`importprivkey`, `z_importkey`, `z_importviewingkey`) hold cs_main this long; `rescan-*` events |
| `FAKE_ENCRYPTED` / `FAKE_WALLET_PASSPHRASE` | 0 / `fake passphrase one` | `1` = an encrypted wallet, locked at start, with this passphrase |
| `FAKE_SCAN_SECS` | 0 | the GUI's wallet scans (`z_listunspent`, `listunspent`, `z_gettotalbalance`, `z_listreceivedbyaddress`, `z_mergetoaddress`) hold cs_main this long; `scan-begin`/`scan-end` events |
| `FAKE_TIP_UNKNOWN_SECS` | 0 | `longestchain` reads 0 this long after `Done Loading` (a node that hasn't seen an UpdateTip yet) |
| `FAKE_LONGEST_AHEAD` / `FAKE_CATCHUP_SECS` | 0 / 0 | the network tip (`longestchain`, `headers`) is N blocks ahead, for that long after `Done Loading` (0 = for good) |
| `FAKE_TXCOUNT` | 42 | `getwalletinfo` `txcount` (the GUI's connect gate waits for the tip on wallets of 500+) |
| `FAKE_METHODS_ALL` | 0 | `1` = one `call m=<method> p=<params>` event per request (the GUI's RPC cadence; the `methods` lines keep only the top 10 counts) |
| `FAKE_METHODS_ALL` | 0 | `1` = one `call m=<method> p=<params>` event per request (the GUI's RPC cadence; the `methods` lines keep only the top 10 counts). Keys and passphrases show as `<redacted>` |
| `FAKE_HEIGHT`, `FAKE_REBUILD_TOTAL`, `FAKE_NOTES`, `FAKE_VERSION` | 3327145, 62583, 13632, 1030050 | cosmetic numbers |
## Test cases