Skip to content

test(rs-platform-wallet/e2e): ID-007 — pin contract that identity-auth addresses are unmonitored#3586

Draft
Claudius-Maginificent wants to merge 34 commits intotest/platform-wallet-e2efrom
feat/rs-platform-wallet-id-007-stub
Draft

test(rs-platform-wallet/e2e): ID-007 — pin contract that identity-auth addresses are unmonitored#3586
Claudius-Maginificent wants to merge 34 commits intotest/platform-wallet-e2efrom
feat/rs-platform-wallet-id-007-stub

Conversation

@Claudius-Maginificent
Copy link
Copy Markdown
Collaborator

Summary

Adds spec entry and a full test body for ID-007 — pins the contract that identity-auth addresses (DIP-9 subfeature 0..3 — m/9'/coinType'/5'/0..3'/identity_index'/key_index') are NOT in PlatformWalletInfo::monitored_addresses() at the pinned key-wallet revision (fe2476611f). The implementation is complete; only the runtime gating (Task #15 + Core-funded bank helper) prevents it from running today.

Tracks closed PR dashpay/rust-dashcore#554 (the parked attempt to add BlockchainIdentities* AccountType variants and flip WalletAccountCreationOptions::Default to monitor those addresses), and DET follow-up issue dash-evo-tool#692.

Why now

The PR was closed without merge or supersede pointer. Investigation confirmed: when the scenario from #554 is consumed by rs-platform-wallet, it is silently unhandled. derive_ecdsa_identity_auth_keypair_from_master is a pure function that bypasses the wallet's AccountCollection entirely; monitored_addresses() walks accounts.all_accounts(); identity-auth addresses are silently excluded from the SPV bloom filter. Any future recovery / sweep / DET-style flow that sends Dash to a user's own identity-auth address loses funds (relative to the wallet's view) until manual bootstrap. ID-007 makes that exclusion an asserted contract.

Status: BLOCKED P2 — full implementation, runtime-gated

The test body is complete and asserts the current contract end-to-end. It is #[ignore]-gated so cargo test --lib and default cargo test --tests stay green; it will fail loudly under --ignored until:

  1. Task fix(sdk): hash is not a function #15 — SPV runtime re-enablement (gates CR-001/CR-002/CR-003 too).
  2. Core-funded bank wallet helper (CR-003 prerequisite). The bank today holds Platform credits via DIP-17 platform-payment accounts, not Core duffs. BankWallet::send_core_to(..) is currently stubbed with unimplemented!(); wire it through when CR-003's Core-funded account lands.
  3. (already landed in this PR) wait_for_core_balance(wallet, expected_min, timeout) in framework/wait.rs — Layer-1-balance parallel of wait_for_balance.
  4. (optional / deferred) BLS derivation helper for the negative variant — left as a TODO(ID-007) comment in the test body.

When the prerequisites land, the assertions stay pinned to the current behaviour ("not monitored, balance unchanged"); when upstream key-wallet then ships any shape of BlockchainIdentities support and the wallet opts in, all three assertion clusters flip in that same PR.

Framework helpers

Helper Path State
wait_for_core_balance framework/wait.rs Wired — polls PlatformWallet::state().balance().spendable(). Re-exported via framework::prelude.
Bank::send_core_to framework/bank.rs Stubunimplemented!() with a docstring linking to CR-003 / ID-007. Wire when Task #15 lands.

Test plan

  • Spec entry present in TEST_SPEC.md § ID-007 (Quick index updated; counts adjusted)
  • Full test body wired in cases/mod.rs and gated with #[ignore]
  • In-test negative variant covered (identity_index = 1, unregistered slot)
  • BLS subfeature variant left as TODO(ID-007) (helper doesn't exist upstream)
  • cargo fmt --all -- --check green
  • cargo check --tests --all-features -p platform-wallet green
  • cargo clippy --tests --all-features -p platform-wallet -- -D warnings green
  • cargo test --lib -p platform-wallet green (141 passed, 0 failed)
  • Replace Bank::send_core_to stub with real Core-funded broadcast — deferred to follow-up PR once Task fix(sdk): hash is not a function #15 + CR-003's Core-funded bank land

Defensive-pin precedent

Same shape as Found-003 / Found-004 — pins a known-incomplete contract as an asserted invariant so silent drift becomes loud breakage.

🤖 Co-authored by Claudius the Magnificent AI Agent

lklimek and others added 2 commits May 5, 2026 12:19
…ddresses unmonitored contract pin

ID-007 pins the current contract that DIP-9 identity-auth addresses
(`m/9'/coinType'/5'/0..3'/identity_index'/key_index'`) are NOT in
`PlatformWalletInfo::monitored_addresses()` at the pinned `key-wallet`
revision (`fe2476611f`). `WalletAccountCreationOptions::Default` does
not create `BlockchainIdentities*` accounts, so a Core (Layer-1)
send to one of those addresses is invisible to the SPV bloom filter
and never increases the wallet's Core balance.

Tracks the scenario from closed PR `dashpay/rust-dashcore#554` (the
parked attempt to ship `BlockchainIdentities*` AccountType variants
and flip Default to monitor those addresses) and DET follow-up
issue `dash-evo-tool#692`. The PR was closed without merge or
supersede pointer; investigation confirmed the scenario is silently
unhandled when consumed by `rs-platform-wallet`.

Status BLOCKED — full test body lands alongside this entry but is
gated behind `#[ignore]` until: (1) Task #15 (SPV runtime), (2)
Core-funded bank wallet helper (CR-003 prerequisite), (3) the
`Bank::send_core_to` stub gets wired to a real Layer-1 broadcast.

Defensive-pin precedent: same shape as Found-003 / Found-004 — pin
a known-incomplete contract as an asserted invariant so silent drift
becomes loud breakage. When upstream `key-wallet` ships any shape of
`BlockchainIdentities` support and the wallet opts in, the
assertions flip in that same PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claudius the Magnificent <noreply@anthropic.com>
…-auth addresses are unmonitored

Implements the full scenario from TEST_SPEC.md § ID-007. The test is
`#[ignore]`-gated (does not run in `cargo test --lib` or default
`cargo test --tests`), so CI stays green; running it under
`--ignored` will fail today on the `unimplemented!()` stub of
`BankWallet::send_core_to` until Task #15 + the Core-funded bank
helper land.

Scenario:
1. Register one identity at slot 0 via `setup_with_n_identities`.
2. Derive the P2PKH `dashcore::Address` for `(identity_index = 0,
   key_index = 0)` via `derive_ecdsa_identity_auth_keypair_from_master`,
   plus `(identity_index = 1, key_index = 0)` for the in-test negative
   variant (registration status is irrelevant — the derivation is pure).
3. Snapshot `monitored_addresses()` before any Core send and assert
   neither address is in the set.
4. Attempt a 100_000-duff Layer-1 send via `bank().send_core_to(..)`
   (currently `unimplemented!()`).
5. Snapshot `monitored_addresses()` again and assert the contract
   still excludes both addresses.
6. `wait_for_core_balance` for 30 s expecting timeout — the SPV
   bloom filter must not carry these addresses, so the balance
   never moves.
7. Assert no UTXO matching `(value = 100_000, address = auth_addr_zero)`
   exists in the wallet's UTXO set.

Framework additions:
- `framework::wait::wait_for_core_balance(test_wallet, expected_min,
  timeout)` — Layer-1-balance parallel of `wait_for_balance`. Polls
  `PlatformWallet::state().balance().spendable()` every backstop
  interval. Re-exported via `framework::prelude`.
- `BankWallet::send_core_to(target, duffs) -> unimplemented!()` —
  CR-003 prerequisite stub. The bank today holds Platform credits
  via DIP-17 platform-payment accounts, not Core duffs on a
  DIP-9 / BIP-44 receive account; wire it through when Task #15
  exposes a Core-funded account.

The BLS subfeature negative variant is left as a `TODO(ID-007)`
comment in the test body — `derive_*_bls_identity_auth_keypair_from_master`
doesn't exist in the upstream `key-wallet` API yet.

Defensive-pin precedent: Found-003 / Found-004.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claudius the Magnificent <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7218bb80-575b-4555-aeff-e21ba382671d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rs-platform-wallet-id-007-stub

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

QuantumExplorer and others added 27 commits May 5, 2026 18:48
… presets (#3587)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The e2e test framework was constructing a wallet manager without
starting the SPV runtime, leaving identity-auth address monitoring
(and other Layer-1 dependent assertions) unable to verify their
contracts. ID-007 specifically requires SPV to be alive for the
monitored_addresses() snapshot to be meaningful.

Re-enables `SpvRuntime::start(ClientConfig::testnet())` during
`setup()`, with the existing 180s mn-list-sync deadline (which the
helper internally raises to the 600s cold-cache floor). SDK keeps
`TrustedHttpContextProvider` — proof verification doesn't need the
SPV-backed quorum lookup yet; future tests that do can swap to
`SpvContextProvider::new(spv_runtime)` via `sdk.set_context_provider`
(it's `ArcSwap`-backed, safe to call post-construction).

Verified with ID-007 on testnet: SPV mn-list synced from cold cache
in ~90s, and the test correctly proceeded through bank L1 funding
(`balance reached target observed=130000000`) before the unrelated
identity-registration headroom panic in `setup_with_n_identities`
(see follow-up: REGISTRATION_HEADROOM=100M < required ~110.86M).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent
…urrent dynamic fee

The setup_with_n_identities helper was sizing each funding address as
`funding_per + 100M`, which on the current testnet falls short of the
dynamic IdentityCreateFromAddresses fee. Marvin's diagnosis pegs that
fee at ~110.86M credits — a ~96M baseline (validate_fees_of_event_v0
PaidFromAddressInputs) plus ~14.85M for the slot-2 TRANSFER key's
storage cost. Bumping the headroom to 150M leaves a ~39M buffer for
protocol-version drift while staying well clear of bank-budget
concerns.

Unblocks every helper-using test that was previously panicking at line
75 of id_007 (and friends) on a residual-too-small registration
failure.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claudius the Magnificent <noreply@anthropic.com>
…e_to

Replaces the BankWallet::send_core_to unimplemented! stub with a real
implementation that builds, signs, and broadcasts a Layer-1 Core
transaction from the bank's BIP-44 account 0 via
CoreWallet::send_to_addresses (which delegates to the SpvBroadcaster
already wired during framework init).

Key details:

- Serialises in-process on the existing FUNDING_MUTEX so concurrent
  Core/Platform funding flows can't race UTXO selection or change-
  address derivation.
- Pre-flight balance check returns FrameworkError::Bank with an
  operator-actionable "top up at <addr>" pointer when the bank's
  confirmed Core balance is below `duffs + 10_000` (a generous fee
  reserve floor that only gates the pre-check; the wallet's coin
  selector picks the actual fee).
- Surfaces two new helpers — `core_balance_confirmed()` and
  `primary_core_receive_address()` — used by the harness pre-flight
  log and by ID-007's diagnostic surface.
- Harness now logs the bank's Core balance + primary Core receive
  address once at framework init under the `platform_wallet::e2e::bank`
  target, so operators can see at a glance whether the bank is
  Core-funded and where to send testnet duffs if it isn't. Most tests
  don't need duffs, so a zero balance is not a hard failure — only
  CR-/ID-007-class cases trip the under-funded path.

This unblocks ID-007 at the framework level. End-to-end runs still
require the bank's Core address to be funded on testnet (the address
prints during init); once funded, the test runs through and pins the
current contract that DIP-9 identity-auth addresses are NOT in
monitored_addresses().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claudius the Magnificent <noreply@anthropic.com>
Framework prerequisites for ID-007 are now resolved: SPV runtime is
live (Task #15) and BankWallet::send_core_to is implemented (CR-003).
The test runs end-to-end up to the point where it tries to send Core
duffs from the bank — gated only on operator pre-funding the bank's
BIP-44 account 0 receive address with at least
`CORE_SEND_DUFFS + ~fee` testnet duffs.

Updates:
- TEST_SPEC.md ID-007 entry: status flipped from BLOCKED to
  FRAMEWORK-READY with the new operator-funding gate documented.
- Test #[ignore] reason: same flip — points operators at the framework
  init log line where the Core receive address prints.
- Module-level doc comment + step 4 inline comment: no longer claims
  send_core_to is unimplemented; describes the current contract
  pinning rationale for the negative wait_for_core_balance window.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claudius the Magnificent <noreply@anthropic.com>
…t bank Core log

Two extensions to the CR-003 BankWallet::send_core_to landing:

1. Factor the actual Core-broadcast body into a free function
   `core_send(wallet, target, duffs)` in `framework/bank.rs`. The bank's
   send_core_to is now a thin wrapper that adds the FUNDING_MUTEX guard,
   the under-funded pre-check (with the bank's own receive address in
   the error), and the broadcast-info log; the free function is what
   the upcoming test-wallet Core sweep in cleanup.rs reuses so we have
   one Core-broadcast surface across the framework.

2. Promote the bank's Core (Layer-1) status log at framework init to a
   prominent, copy-pasteable line:

     ═══ BANK CORE ADDRESS (fund here for CR-* / ID-007 tests) ═══

   Most tests don't need duffs, so a zero balance is not fatal — but
   when a CR-/ID-007-class case runs, the operator now has a single
   visually-distinct line in the test output naming the address to
   top up. Field names switched to `bank_core_addr` / `bank_core_balance`
   for parity with the under-funded error message.

CORE_TX_FEE_RESERVE is hoisted from a per-fn const to a `pub const`
on the bank module so the cleanup-side sweep can share the same fee
reserve floor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claudius the Magnificent <noreply@anthropic.com>
Extends `cleanup::teardown_one` and `cleanup::sweep_orphans` with a
real Core (Layer-1) sweep — counterpart to the existing platform-
credit / identity-credit sweeps. Recovers Core duffs on every test
wallet's BIP-44 account 0 back to the bank's primary BIP-44 receive
address.

Mechanics:

- `sweep_core_addresses` (no longer a no-op stub) reads the wallet's
  lock-free confirmed Core balance, gates on a `CORE_SWEEP_DUST_FLOOR`
  of 100_000 duffs (so we never burn most of a balance to fee), and
  delegates the actual broadcast to `bank::core_send` — the same free
  function the bank's send_core_to wraps. Failures are logged at
  WARN and propagated; the orphan-recovery loop catches them and
  retains the registry entry for next-run retry.

- `TestWallet` gains two thin helpers — `core_balance_confirmed()`
  and `sweep_core_to(target, amount)` — that mirror the bank's
  surface for individual tests that want to broadcast a Core send
  without going through teardown. Most tests don't need them; they
  exist for completeness and for cases where the test body itself
  needs to trigger the sweep path explicitly.

For ID-007 specifically, the test wallet's Core balance stays at 0
under the negative contract (auth_addr is not in the bloom filter),
so the sweep is a no-op there — `core sweep: balance at or below
dust floor; nothing to sweep`. That's correct behaviour, not a bug.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claudius the Magnificent <noreply@anthropic.com>
…helper

Lands `setup_with_core_funded_test_wallet(duffs)` next to
`setup_with_n_identities` for cases that need an asset-lock-buildable
balance on the test wallet's own Core (Layer-1) side. Composes the
existing `setup` → `bank.send_core_to` → `wait_for_core_balance`
chain into a single guard so CR-003 (and any future Core-funded case)
doesn't re-derive the boilerplate. Surfaces `FrameworkError::Bank`
verbatim from `BankWallet::send_core_to` so the operator-actionable
"top up at <addr>" message reaches the test log unchanged on bank
under-funding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…entity registration

Wires the canonical asset-lock-funded `IdentityCreate` path:
`setup_with_core_funded_test_wallet(200M duffs)` →
`IdentityWallet::register_identity_with_funding_external_signer`
with `IdentityFundingMethod::FundWithWallet { amount_duffs = 100M }`.
The wallet internally drives `AssetLockManager::create_funded_asset_lock_proof`
(build → broadcast → wait IS / fall back to ChainLock) and submits the
`IdentityCreate` transition against the resolved proof.

Asserts:
- on-chain identity is independently fetchable with balance ≥ half lock
  amount (deterministic, fee-tolerant lower bound),
- slot-0 key on the fetched identity is MASTER+AUTHENTICATION (the
  protocol's signer-key contract for `IdentityCreate`),
- every tracked asset lock landed in `InstantSendLocked` /
  `ChainLocked` final state (no `Built` / `Broadcast` orphans).

Tagged `#[ignore]` for testnet env vars + bank Core funding. Mirrors
DET's `test_tc004_create_registration_asset_lock`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n present

Flips CR-003 from `BLOCKED — needs harness refactor` to
`STUB — full test body implemented, #[ignore]-tagged behind testnet
env vars + bank Core funding`. Documents the framework prerequisites
that landed (SPV runtime, `BankWallet::send_core_to`,
`setup_with_core_funded_test_wallet`) and the exact funding floor the
operator needs on the bank's Core address before a non-`--ignored`
run can clear: `TEST_WALLET_CORE_FUNDING + CORE_TX_FEE_RESERVE` ≈
2.0001 DASH testnet. Updates the wallet-feature-exercised pointer to
the unified `register_identity_with_funding_external_signer` flow.
Annotates the Quick Index row to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n API

Both `create_wallet_from_mnemonic` and `create_wallet_from_seed_bytes`
now take a `birth_height_override: Option<u32>` controlling the SPV
compact-filter scan window for the new wallet:

- `None` keeps the prior behaviour (seed birth height to SPV's
  current confirmed header tip — fine for fresh wallets that only
  need to see funding from now on).
- `Some(0)` requests a full historical scan from genesis, required
  when an address may have received funds before registration.
- `Some(h)` pins the scan to a specific block height.

The override flows through `register_wallet` into both the in-memory
`ManagedWalletInfo` checkpoint and the persisted `WalletMetadataEntry`
so the SPV scan window is consistent across restarts. Previously
those two carried independent values (in-memory hardcoded to 0,
persisted seeded from SPV tip), which was incoherent.

FFI bindings and the basic_usage example pass `None` to preserve
existing semantics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…storical L1 funding is visible

The bank is a long-lived testnet address that may receive Layer-1
funding before any test run starts. Pinning `birth_height` to the
current SPV tip (the previous default) made the compact-filter scan
window `[H_now, ∞)`, hiding any UTXO confirmed before init — exactly
the QA-001 / QA-002 / QA-003 finding documented in
`/tmp/bank-core-balance-diagnosis.md`. The user's confirmed 4 DASH
at `yXyzNWRRASxYzWwskmqNmb5xFjGc94bn5F` was being reported as zero
for this reason.

Pass `Some(0)` to `create_wallet_from_mnemonic` so SPV scans from
genesis. Other test callers (`TestWallet::create`, post-sweep
re-derivations, cleanup sweeps, the `spv_sync` integration test)
still pass `None` — fresh test wallets don't need historical scan.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
QA-003 LOW: the bank pre-flight log already showed `bank_core_addr`
and `bank_core_balance`, but not `birth_height` — leaving operators
unable to tell "wallet starts above your funding tx" (filter scan
window past the funding block) from "your tx hasn't confirmed yet"
(legitimate zero balance) when seeing `bank_core_balance=0`.

Add `birth_height` to both the info and warn variants of the BANK
CORE ADDRESS log line, plus a separate WARN when the balance is
zero and birth_height > 0 explaining that any funding tx confirmed
below the birth_height is invisible to SPV until re-broadcast.

The bank itself now passes `Some(0)`, so the warn is defence-in-depth
for the case where someone changes that behaviour without updating
the operator-facing diagnostic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…3591)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…word (#3590)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#3589)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Helper polls BankWallet::core_balance_confirmed until it reaches the
configured floor or the timeout elapses, and emits an info-level
progress line every 30s including the SPV compact-filter scan height
vs the chain tip — operator can tell "scan still walking" from "scan
at tip, balance genuinely zero".

Adds Config::bank_core_gate_duffs (env: PLATFORM_WALLET_E2E_BANK_CORE_GATE,
default 0 = skip). CR-* / ID-007 cases raise this floor to gate harness
init on the bank's pre-funded UTXOs being visible to SPV — Marvin's
QA-001: a cold-cache run on testnet samples core_balance ~52s in while
SPV is still ~15min from completing the genesis-to-tip filter walk and
a CR-003 / ID-007 send_core_to fails on a false-zero balance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…er scan completion

Calls wait_for_bank_funded between BankWallet::load and the bank Core
address banner so the banner reflects the post-scan balance instead of
a false-zero mid-scan (Marvin's QA-001). Default gate is 0 — most tests
don't need duffs and the wait is wasted; CR-* / ID-007 operators raise
it via PLATFORM_WALLET_E2E_BANK_CORE_GATE and accept the cold-cache
~15min wait for the first run (subsequent runs reuse the on-disk SPV
cache and clear in seconds).

Gate failure is demoted to a warn rather than a hard abort so unrelated
tests still run; tests that need bank Core funding panic at
send_core_to with the operator-actionable "top up at <addr>" message.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… + CR-003

Adds an "Operator notes" line on each entry recording the ~15min cold-
cache compact-filter scan, the PLATFORM_WALLET_E2E_BANK_CORE_GATE env
var the operator sets to gate harness init on the post-scan balance,
and the RUST_LOG target that surfaces scan-progress lines (Marvin's
QA-002).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…wait_for_mn_list_synced

Previously wait_for_mn_list_synced only polled the mn-list snapshot and
burned the full 600s cold-cache floor when dash-spv had already given
up internally — most commonly when the QRInfo retry loop hard-caps at
3 attempts with "Required rotated chain lock sig at h - 0 not present".

Two complementary signals now short-circuit the wait:

1. Event-driven: register a single-purpose PlatformEventHandler on the
   SpvRuntime's event manager that forwards SyncEvent::ManagerError
   (scoped to ManagerIdentifier::Masternode) into an mpsc channel.
   The wait loop selects on this channel ahead of the poll tick, so
   the engine signal surfaces in O(ms) with an operator-actionable
   error message ("wipe spv-data/, or wait 10-20 min for the next
   testnet ChainLock cycle").
2. Heuristic backstop: if the engine ever stops emitting the error
   (e.g. silent retry loop), the wait still bails after 120s of no
   forward progress on the mn-list snapshot.

A thin pass-through accessor SpvRuntime::event_manager() is added so
the framework can subscribe without touching dash-spv internals.

Effect: a known-stalled run that used to wait 600s now bails in well
under 120s — the event path typically in ~1s after dash-spv emits
ManagerError.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a Known Issues / Operator Notes subsection (1.3) covering the
dash-spv QRInfo retry-cap stall that wait_for_mn_list_synced now
surfaces eagerly, with operator workaround steps (wait for next
testnet ChainLock cycle, or wipe spv-data/).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pulls in any newer rs-dashcore/dash-spv revisions that may have landed
since the branch was forked. Specifically interested in any fix to
dash-spv's QRInfo retry path — the testnet rotated-quorum-cycle race
currently blocks ID-007/CR-003 testnet runs.

🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent
ID-007 verified PASS on testnet at HEAD 32ee2cd after the dash-spv
mn-list QRInfo retry-race window (cycle boundary 1471104, prior runs
1471135) cleared. Mn-list synced in 8.5s warm cache, bank Core funding
gate cleared at 1_600_000_000 duffs (gate 110_000), identity
EwATqMdBoCrDQoEBTwcammqAcGcKihzxGrW1qaLoDAJW registered, total
wall-clock 130s.

CR-003 not flipped: re-run failed at cr_003_asset_lock_funded_registration.rs:99
with "PRE-pin violated: setup_with_core_funded_test_wallet returned with
confirmed Core balance 0 < TEST_WALLET_CORE_FUNDING 200000000". The
helper observed mempool funds (target=200000000 reached at +2.0s) but
the case's PRE-pin requires confirmed balance — meaningful contract
mismatch, deferred for separate investigation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rmed balance

Marvin QA-001 HIGH: setup_with_core_funded_test_wallet was returning
~2s after broadcast on mempool-only visibility, then CR-003's PRE-pin
panicked because confirmed_core_balance was still 0. The waiter polled
state().await.balance().spendable() (mempool-inclusive) while every
caller — both the helper's own docstring and CR-003's asset-lock
builder — needs *confirmed* UTXOs to reference.

Switch wait_for_core_balance to poll TestWallet::core_balance_confirmed
(the same lock-free atomic accessor the PRE-pin checks against), drop
the stale state().await chain, and rewrite the doc comment to make the
confirmed-only contract explicit.

ID-007's pre_balance is updated in lockstep so the pin compares
against the same metric the waiter reads — the timeout still fires
because auth_addr_zero isn't in monitored_addresses(), independent of
confirmation depth.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…D-007 heading

Marvin QA-002 LOW: TEST_SPEC heading still read "(BLOCKED on Task #15)"
even though Task #15 has landed and ID-007 just passed end-to-end on
testnet. The Status field on the same entry already records the PASS
at HEAD 32ee2cd — the parenthetical is the only remaining stale
marker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lklimek and others added 5 commits May 5, 2026 17:31
…, fail until upstream fixes BlockchainIdentities

ID-007 previously pinned the broken contract — green-while-buggy. That
inverts the meaning of the test suite: a green run could mean either
"feature works" or "feature still broken in the same way as before",
and there's no way to tell at a glance.

Flip the polarity. The test now asserts the CORRECT behavior:

- identity-auth addresses ARE in `monitored_addresses()` before and
  after the Layer-1 send,
- the wallet's confirmed Core balance INCREASES after the inbound
  UTXO confirms,
- the wallet's UTXO set CONTAINS the new entry.

All three assertions currently FAIL because rust-dashcore's
`WalletAccountCreationOptions::Default` excludes
`BlockchainIdentities*` `AccountType` variants at the pinned
`key-wallet` revision (closed PR `dashpay/rust-dashcore#554` attempted
this; closed without merge). The negative-axis variant
(`identity_index = 1`, unregistered slot) carries the same
correct-behavior assertions — registration status is irrelevant to
monitoring since the derivation is pure.

Renames the test file and function from `..._not_monitored` to
`..._monitored` to match the inverted intent. Bumps
`wait_for_core_balance` timeout to 5 minutes (testnet block time
~2.5 min plus SPV bloom-filter propagation headroom) since
the assertion is now "balance reaches target", not "wait times out".
The `#[ignore]` reason now spells out "FAILS by design until
upstream lands BlockchainIdentities* support".

DET parallel: `dash-evo-tool#692`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-design

ID-007's status flipped from "Pass" (which pinned the broken contract
as-is) to "FAILING — by design until upstream lands
`BlockchainIdentities*` support". The Quick index entry, the per-entry
Status, the Assertions block, the Variants section, the Rationale
and the Notes are all rewritten to reflect: the test asserts the
CORRECT contract; green = feature works, red = feature broken;
contrast with `Found-003` / `Found-004` (defensive pins of broken
behavior, kept where the bug is the contract).

No `red` / `green` legend exists in TEST_SPEC.md to update — status
values are free-form English (Pass / IMPLEMENTED / BLOCKED / STUB /
FAILING). Quick index has no Status column.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Identity balances are denominated in credits (`dpp::fee::Credits`);
the asset-lock amount is in duffs. The previous POST-pin compared
the two without conversion, so a successful registration that landed
~99.9M duffs (≈ 99.9G credits, fees subtracted) tripped the upper
bound `observed <= ASSET_LOCK_AMOUNT (100M)` by 1000×.

Convert via `dpp::balances::credits::CREDITS_PER_DUFF` (= 1000) so
both sides of every comparison are in credits, and update the panic
message to call out the unit explicitly. Marvin's QA-001 (HIGH).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…satisfied target

Marvin's QA-002 (LOW) flagged that the helper returned in 2.002s for
CR-003 — well below testnet block time. Investigation against the
pinned `key-wallet` rev (`fe2476611fcf72d6f36f1154a39a2f9af3b6a248`)
confirmed `WalletCoreBalance::confirmed` counts mature UTXOs that
are EITHER in a block OR InstantSend-locked (per upstream rustdoc on
`balance.rs:18`). There is no separate accessor that excludes
IS-locked UTXOs at this revision; tightening the helper to require
strictly block-confirmed semantics would require an upstream API
change.

Document the actual semantics honestly in the rustdoc (the previous
"deliberately NOT counted" claim about IS-locked UTXOs was wrong),
and add a `path` field to the success-log line distinguishing
`pre_funded_workdir_cache` (target met on first poll → likely a
pre-existing UTXO, not freshly arriving funds) from
`confirmed_or_is_locked` (at least one poll observed below-target
before the threshold was reached). This lets future post-mortems on
suspiciously fast returns tell the two paths apart at a glance
without inferring it from elapsed timestamps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ified

Asset-lock-funded identity registration runs end-to-end against testnet:
asset-lock built, IS-lock observed, identity registered on-chain, balance
decrement asserted in duffs (post units fix). Test gated on
PLATFORM_WALLET_E2E_BANK_CORE_GATE. Verified at HEAD fa55e64.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants