feat(lite): lite wallet foundation (inherited working-tree state)

Preserve the previously-uncommitted lite wallet implementation and related dev WIP
under version control:
- src/wallet/ lite services: client bridge, bridge runtime, connection, lifecycle,
  sync, gateway, result parsers, state mapper, artifact contract/resolver, refresh
  services, UI adapters, wallet_backend/capabilities. (Includes two small M1 fixes:
  lifecycle walletReady now parses the response; default chain name -> "main".)
- src/chat/ chat protocol; tests/fixtures/ (lite + hushchat); tools/hushchat_fixture_check.cpp;
  scripts/build-lite-backend-artifact.sh.
- Pre-existing modified app_network/security/wizard, network_refresh_service, sidebar,
  mining_tab, bootstrap dialog, and version headers captured as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-04 21:15:28 -05:00
parent a78a13edf3
commit 863d015628
69 changed files with 39458 additions and 85 deletions

View File

@@ -0,0 +1,27 @@
# HushChat Capture Manifest
The capture manifest is a redacted provenance file for a staged directory of real, disposable, non-sensitive SilentDragonXLite HushChat vectors. It does not replace fixture validation; it records that the staged directory was handled under the safety rules required before the Batch 11 strict replacement dry run.
Copy `templates/capture-manifest.template.json` into the staged fixture directory as `capture-manifest.json`, then change `status` to `staged` and each category `status` to `ready`. Keep the file limited to provenance, handling flags, category filenames, and the dry-run command.
Validate only the manifest metadata with:
```sh
./build/bin/HushChatFixtureCheck --validate-capture-manifest /path/to/staged/hushchat-fixtures
```
The validator accepts a directory containing `capture-manifest.json` or a direct manifest file path. It prints only a redacted report with schema status, category coverage, handling-flag counts, basenames, and error names.
The manifest must include:
- schema `dragonx.hushchat.capture-manifest.v1`
- status `staged`
- a redacted manifest id
- staged fixture directory name
- dry-run command containing `HushChatFixtureCheck --replacement-dry-run`
- provenance fields for source client, source client version or commit, capture date, network, and capture method
- all required handling flags set to `true`
- exactly one entry for each required fixture category
The manifest must not include passphrases, plaintext, memo contents, private keys, wallet files, ciphertext byte dumps, stored chat key fields, public-key fields, secretstream headers, derived keys, session keys, or any fixture object. The manifest validator rejects known prohibited field names, but it is still a metadata guard rather than a secret scanner.
After the manifest validates, run the strict replacement dry run against the same staged directory. Pending checked-in fixtures must not be replaced until both commands succeed.

View File

@@ -0,0 +1,40 @@
# HushChat Fixture Import Checklist
This checklist is for replacing the pending placeholders with real, non-sensitive SilentDragonXLite compatibility vectors.
Do not commit passphrases, plaintext, memo contents from real wallets, private keys, wallet files, or arbitrary ciphertext dumps. Use only disposable test wallets and non-sensitive test messages. The checked-in ready files must contain only the schema fields required by the loader.
Required categories:
- `incoming_memo`: received encrypted Memo vector, expected `ClientRx`
- `outgoing_memo`: outgoing-history encrypted Memo vector, expected `ServerTx`
- `seed_public_key_projection`: vector proving the SDXL UTF-8-hex seed projection matches the recorded local public key
- `corrupted_auth_failure`: structurally valid Memo vector reserved for future authentication-failure verification
- `cont_exclusion`: contact request vector that remains excluded from encrypted Memo decrypt preparation
Capture rules:
- Use disposable SilentDragonXLite wallets only.
- Use a fixed non-sensitive test phrase and record only its hash if a plaintext expectation is needed.
- Do not store decrypted message text in fixture files.
- Do not include private keys, viewing keys, spending keys, wallet seed phrases, or wallet database contents.
- Keep the top-level `schema` value as `dragonx.hushchat.compat-fixture.v1`.
- Change `status` from `pending` to `ready` only when the fixture has the full `fixture` object documented in the protocol spec.
- Preserve one fixture file per required category.
- For every ready non-`Cont` vector, the stored SDXL chat key string must project to the declared local public key using SDXL's first-32-UTF-8-bytes seed behavior.
- The projection check records only byte lengths and match status; it must not write passphrases, plaintext, derived secret keys, memo contents, or ciphertext bytes.
- A ready `corrupted_auth_failure` vector must be structurally valid through the same loader, verifier, and projection checks, then marked as requiring a future secretstream authentication failure.
- The corrupted-auth marker is not a decrypt result and is not an authentication result.
- Run the strict replacement dry-run report against a staged directory before copying any ready files over the checked-in pending placeholders.
- The dry-run report must remain redacted; it may contain category names, basenames, status/error names, boolean flags, and counts only.
- Add `capture-manifest.json` to the staged directory from `templates/capture-manifest.template.json` and validate it before strict replacement dry-run checks.
- The capture manifest records provenance, handling flags, category filenames, and dry-run instructions only; it must not contain fixture objects or sensitive fields.
Verification flow:
```sh
./build/bin/HushChatFixtureCheck --allow-pending tests/fixtures/hushchat
./build/bin/HushChatFixtureCheck --validate-capture-manifest /path/to/staged/hushchat-fixtures
./build/bin/HushChatFixtureCheck --replacement-dry-run /path/to/staged/hushchat-fixtures
./build/bin/HushChatFixtureCheck tests/fixtures/hushchat
```
The first command is for the current scaffold state and allows pending files. The manifest command validates only redacted staged-directory metadata. The dry-run command is strict, refuses `--allow-pending`, performs no file replacement, and must fail until the staged directory contains all five real ready vectors with no pending, malformed, mismatched, projection-failed, auth-not-ready, or Cont-not-excluded entries. The final command is the post-copy strict check on the checked-in fixture directory; it must report `future_auth_required=1` and `auth_structural_ready=1`. A ready import is acceptable only when the manifest command and both strict fixture commands exit successfully.

31
tests/fixtures/hushchat/README.md vendored Normal file
View File

@@ -0,0 +1,31 @@
# HushChat Compatibility Fixtures
This directory contains the checked-in fixture-file schema for non-sensitive HushChat compatibility vectors.
The current files are intentionally marked `pending`. They define the exact vector categories and required fields without pretending that real SilentDragonXLite compatibility data has been captured yet.
Use the developer checker after building:
```sh
./build/bin/HushChatFixtureCheck --allow-pending tests/fixtures/hushchat
```
The command above is expected to pass while files are still pending. Before replacing pending placeholders with real `ready` vectors, run the same command without `--allow-pending`; it exits successfully only when all five required categories are supplied exactly once, pass the fixture loader/import checklist, satisfy the seed/public-key projection verifier, and mark the corrupted-auth vector as structurally ready for a future authentication-failure check.
For a strict replacement dry run against a staged directory of real vectors, use:
```sh
./build/bin/HushChatFixtureCheck --replacement-dry-run /path/to/staged/hushchat-fixtures
```
The dry-run mode refuses pending vectors and prints only a redacted replacement report with categories, basenames, status/error names, boolean flags, and aggregate counts. It does not copy files or print key material, memo contents, plaintext, ciphertext bytes, or hashes.
Before running the strict replacement dry run on real staged vectors, add a redacted capture manifest and validate it:
```sh
./build/bin/HushChatFixtureCheck --validate-capture-manifest /path/to/staged/hushchat-fixtures
```
The manifest template lives at `templates/capture-manifest.template.json`. See `CAPTURE_MANIFEST.md` for the metadata rules.
See `IMPORT_CHECKLIST.md` for the capture rules.

View File

@@ -0,0 +1,7 @@
{
"schema": "dragonx.hushchat.compat-fixture.v1",
"status": "pending",
"kind": "cont_exclusion",
"id": "sdxl-cont-exclusion",
"pending_reason": "Needs a non-sensitive Cont fixture proving contact requests remain outside encrypted Memo decrypt handling."
}

View File

@@ -0,0 +1,7 @@
{
"schema": "dragonx.hushchat.compat-fixture.v1",
"status": "pending",
"kind": "corrupted_auth_failure",
"id": "sdxl-corrupted-auth-failure",
"pending_reason": "Needs a non-sensitive Memo vector that passes structural Batch 1-6 validation but is expected to fail future secretstream authentication."
}

View File

@@ -0,0 +1,7 @@
{
"schema": "dragonx.hushchat.compat-fixture.v1",
"status": "pending",
"kind": "incoming_memo",
"id": "sdxl-incoming-memo",
"pending_reason": "Needs a non-sensitive incoming Memo vector captured from SilentDragonXLite with stored chat key hex, public keys, header memo, ciphertext memo, expected role, byte lengths, and plaintext hash only."
}

View File

@@ -0,0 +1,7 @@
{
"schema": "dragonx.hushchat.compat-fixture.v1",
"status": "pending",
"kind": "outgoing_memo",
"id": "sdxl-outgoing-memo",
"pending_reason": "Needs a non-sensitive outgoing-history Memo vector captured from SilentDragonXLite with stored chat key hex, local and peer public keys, header memo, ciphertext memo, expected server_tx role, byte lengths, and plaintext hash only."
}

View File

@@ -0,0 +1,7 @@
{
"schema": "dragonx.hushchat.compat-fixture.v1",
"status": "pending",
"kind": "seed_public_key_projection",
"id": "sdxl-seed-public-key-projection",
"pending_reason": "Needs a non-sensitive vector proving the SilentDragonXLite UTF-8-hex seed projection produces the observed local public key without storing the original passphrase or plaintext."
}

View File

@@ -0,0 +1,54 @@
{
"schema": "dragonx.hushchat.capture-manifest.v1",
"status": "template",
"id": "replace-with-redacted-capture-manifest-id",
"fixture_directory": "replace-with-staged-fixture-directory",
"dry_run_command": "./build/bin/HushChatFixtureCheck --replacement-dry-run replace-with-staged-fixture-directory",
"provenance": {
"source_client": "SilentDragonXLite",
"source_client_version": "replace-with-release-or-commit",
"capture_date": "YYYY-MM-DD",
"network": "replace-with-disposable-test-network",
"capture_method": "replace-with-redacted-capture-procedure-name"
},
"handling": {
"disposable_wallets_only": true,
"non_sensitive_vectors_only": true,
"no_passphrases": true,
"no_plaintext": true,
"no_memo_contents": true,
"no_private_keys": true,
"no_wallet_files": true,
"no_ciphertext_byte_dumps": true,
"no_derived_keys": true,
"no_session_keys": true,
"redacted_report_only": true
},
"categories": [
{
"kind": "incoming_memo",
"staged_filename": "incoming-memo.ready.json",
"status": "template"
},
{
"kind": "outgoing_memo",
"staged_filename": "outgoing-memo.ready.json",
"status": "template"
},
{
"kind": "seed_public_key_projection",
"staged_filename": "seed-public-key-projection.ready.json",
"status": "template"
},
{
"kind": "corrupted_auth_failure",
"staged_filename": "corrupted-auth-failure.ready.json",
"status": "template"
},
{
"kind": "cont_exclusion",
"staged_filename": "cont-exclusion.ready.json",
"status": "template"
}
]
}

View File

@@ -0,0 +1,60 @@
{
"schema": "dragonx.lite.release-package-manifest.v1",
"source": "generated-package-manifest-fixture",
"generated": true,
"packages": [
{
"name": "ObsidianDragon-full-linux-fixture",
"build_kind": "full-node",
"format": "linux-zip",
"pool_mining_supported": true,
"solo_mining_available": true,
"full_node_lifecycle_actions_available": true,
"expect": {
"dragonxd": true,
"dragonx_cli": true,
"dragonx_tx": true,
"sapling_params": true,
"asmap": true,
"xmrig_when_available": true
},
"assets": [
{ "kind": "app-binary", "path": "ObsidianDragon", "present": true, "executable": true },
{ "kind": "dragonxd", "path": "usr/bin/dragonxd", "present": true, "executable": true },
{ "kind": "dragonx-cli", "path": "usr/bin/dragonx-cli", "present": true, "executable": true },
{ "kind": "dragonx-tx", "path": "usr/bin/dragonx-tx", "present": true, "executable": true },
{ "kind": "sapling-spend.params", "path": "usr/bin/sapling-spend.params", "present": true, "executable": false },
{ "kind": "sapling-output.params", "path": "usr/bin/sapling-output.params", "present": true, "executable": false },
{ "kind": "asmap.dat", "path": "usr/bin/asmap.dat", "present": true, "executable": false },
{ "kind": "xmrig", "path": "usr/bin/xmrig", "present": true, "executable": true },
{ "kind": "resources", "path": "usr/share/ObsidianDragon/res", "present": true, "executable": false }
]
},
{
"name": "ObsidianDragonLite-linux-fixture",
"build_kind": "lite",
"format": "linux-zip",
"pool_mining_supported": true,
"solo_mining_available": false,
"full_node_lifecycle_actions_available": false,
"assets": [
{ "kind": "app-binary", "path": "ObsidianDragonLite", "present": true, "executable": true },
{ "kind": "xmrig", "path": "xmrig", "present": true, "executable": true },
{ "kind": "resources", "path": "res", "present": true, "executable": false }
]
},
{
"name": "ObsidianDragonLite-windows-fixture",
"build_kind": "lite",
"format": "windows-zip",
"pool_mining_supported": true,
"solo_mining_available": false,
"full_node_lifecycle_actions_available": false,
"assets": [
{ "kind": "app-binary", "path": "ObsidianDragonLite.exe", "present": true, "executable": true },
{ "kind": "other", "path": "tools/xmrig.exe", "present": true, "executable": true },
{ "kind": "resources", "path": "res", "present": true, "executable": false }
]
}
]
}

107
tests/fixtures/lite/result_parsers.json vendored Normal file
View File

@@ -0,0 +1,107 @@
{
"info": {
"chain_name": "dragonx",
"version": "0.1.0",
"vendor": "SilentDragonXLite",
"latest_block_height": 250001,
"difficulty": 42,
"longestchain": 250003,
"notarized": 249990
},
"height_object": {
"height": 250004
},
"height_number": 250005,
"balance": {
"tbalance": 125000000,
"zbalance": 230000000,
"unconfirmed": 5000000,
"verified_zbalance": 180000000,
"spendable_zbalance": 170000000
},
"addresses": {
"z_addresses": [
"zs1parserfixture0000000000000000000000000000000000000000000000000000",
"zs1parserfixture1111111111111111111111111111111111111111111111111111"
],
"t_addresses": [
"RParserFixtureTransparentAddress0000000000001"
]
},
"notes": {
"unspent_notes": [
{
"address": "zs1parserfixture0000000000000000000000000000000000000000000000000000",
"created_in_block": 249900,
"created_in_txid": "note-txid-1",
"value": 100000000,
"spent": false,
"unconfirmed_spent": false
}
],
"utxos": [
{
"address": "RParserFixtureTransparentAddress0000000000001",
"created_in_block": 249901,
"created_in_txid": "utxo-txid-1",
"value": 25000000,
"spent": false,
"unconfirmed_spent": true
}
],
"pending_notes": [
{
"address": "zs1parserfixture1111111111111111111111111111111111111111111111111111",
"created_in_block": 0,
"created_in_txid": "pending-note-txid-1",
"value": 30000000,
"spent": false,
"unconfirmed_spent": false
}
],
"pending_utxos": [
{
"address": "RParserFixtureTransparentAddress0000000000001",
"created_in_block": 0,
"created_in_txid": "pending-utxo-txid-1",
"value": 12000000,
"spent": false,
"unconfirmed_spent": false
}
]
},
"list": [
{
"txid": "sent-txid-1",
"datetime": 1710000000,
"block_height": 249950,
"unconfirmed": false,
"outgoing_metadata": [
{
"address": "zs1recipientfixture0000000000000000000000000000000000000000000000",
"value": 75000000,
"memo": "outgoing memo"
},
{
"address": "RRecipientTransparentFixture000000000000001",
"value": 5000000,
"memo": "transparent memo"
}
]
},
{
"txid": "receive-txid-1",
"datetime": 1710001000,
"block_height": 0,
"unconfirmed": true,
"address": "zs1parserfixture1111111111111111111111111111111111111111111111111111",
"amount": 42000000,
"memo": "incoming memo",
"position": 2
}
],
"syncstatus": {
"synced_blocks": 125002,
"total_blocks": 250004
}
}