test(rs-platform-wallet): e2e suite, Found-025 fix + triage pins#3549
test(rs-platform-wallet): e2e suite, Found-025 fix + triage pins#3549Claudius-Maginificent wants to merge 295 commits into
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughAn end-to-end testing framework for Changes
Sequence Diagram(s)sequenceDiagram
participant Test as E2E Test
participant Harness as E2eContext Harness
participant Registry as Wallet Registry
participant Bank as BankWallet
participant TWallet as TestWallet
participant Manager as PlatformWalletManager
participant SDK as SDK/PlatformWallet
participant Cleanup as Cleanup
Test->>Harness: init() first call
Harness->>Registry: open(test_wallets.json)
Harness->>Cleanup: sweep_orphans()
Cleanup->>Registry: list_orphans()
Cleanup->>Manager: create from orphan seed
Cleanup->>SDK: sync & drain to bank
Cleanup->>Registry: remove_orphan_entry
Harness->>Bank: load from mnemonic
Harness->>Bank: sync_balances()
Harness->>Bank: fund_address(test_addr1, credits)
Harness->>SDK: transfer via bank wallet
Test->>Test: setup() generates seed
Test->>Manager: create TestWallet
Test->>TWallet: create(seed)
Test->>TWallet: next_unused_address() → addr2
Test->>Bank: fund_address(addr2, TRANSFER_CREDITS)
Test->>SDK: transfer via bank
Test->>TWallet: wait_for_balance(addr2, expected)
TWallet->>SDK: sync_balances()
Test->>SDK: transfer(addr2 → addr1, TRANSFER_CREDITS)
SDK->>SDK: execute, compute fee
Test->>TWallet: verify balances & fee
Test->>Test: teardown()
Test->>Cleanup: teardown_one(test_wallet)
Cleanup->>TWallet: drain all addresses to bank
Cleanup->>Registry: remove_entry
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Pull request overview
Adds an end-to-end (wallet → SDK → broadcast) integration test harness to rs-platform-wallet and introduces the first live test case (address-funds transfer), alongside a production fix to InputSelection::Auto input selection so generated transitions satisfy protocol structure rules.
Changes:
- Added a reusable E2E framework under
packages/rs-platform-wallet/tests/e2e/(workdir slot locking, bank wallet, persistent registry, cleanup/sweep, wait hub, signer, SDK wiring). - Added the first E2E test case: transferring credits between two platform-payment addresses in a test wallet (ignored by default).
- Fixed
auto_select_inputsin production code to avoid selecting full balances as “input credits”, and added unit tests for the selection logic.
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/rs-platform-wallet/src/wallet/platform_addresses/transfer.rs | Fixes auto input selection; adds pure helper + unit tests for selection behavior. |
| packages/rs-platform-wallet/tests/e2e.rs | Adds the integration test crate root and module wiring for the e2e suite. |
| packages/rs-platform-wallet/tests/e2e/README.md | Operator/setup documentation for running live e2e tests. |
| packages/rs-platform-wallet/tests/e2e/cases/mod.rs | Declares e2e test modules. |
| packages/rs-platform-wallet/tests/e2e/cases/transfer.rs | First e2e test exercising funding + self-transfer + teardown. |
| packages/rs-platform-wallet/tests/e2e/framework/mod.rs | Framework public surface (setup, errors, prelude) and module layout. |
| packages/rs-platform-wallet/tests/e2e/framework/harness.rs | E2eContext singleton init: config, workdir locking, SDK, manager, bank, registry, startup sweep. |
| packages/rs-platform-wallet/tests/e2e/framework/config.rs | Env/.env configuration loader for the harness. |
| packages/rs-platform-wallet/tests/e2e/framework/sdk.rs | Constructs dash_sdk::Sdk with TrustedHttpContextProvider and DAPI address resolution. |
| packages/rs-platform-wallet/tests/e2e/framework/workdir.rs | Cross-process workdir slot selection via flock. |
| packages/rs-platform-wallet/tests/e2e/framework/panic_hook.rs | Installs panic hook to cancel background work on panic. |
| packages/rs-platform-wallet/tests/e2e/framework/wait_hub.rs | Notify-based hub bridging wallet/SPV/platform events to async waiters. |
| packages/rs-platform-wallet/tests/e2e/framework/wait.rs | Async waiting helpers (event-driven balance wait + generic polling). |
| packages/rs-platform-wallet/tests/e2e/framework/signer.rs | Seed-backed Signer<PlatformAddress> with eager DIP-17 key cache. |
| packages/rs-platform-wallet/tests/e2e/framework/wallet_factory.rs | Test wallet factory + SetupGuard (panic-safe registry-backed lifecycle). |
| packages/rs-platform-wallet/tests/e2e/framework/registry.rs | JSON-backed persistent registry for panic-safe orphan recovery. |
| packages/rs-platform-wallet/tests/e2e/framework/cleanup.rs | Startup sweep + per-test teardown draining funds back to bank. |
| packages/rs-platform-wallet/tests/e2e/framework/bank.rs | Loads and syncs a pre-funded bank wallet; serialized funding API. |
| packages/rs-platform-wallet/tests/e2e/framework/context_provider.rs | Retained (disabled) SPV-backed SDK context provider module for future re-enable. |
| packages/rs-platform-wallet/tests/e2e/framework/spv.rs | Retained (disabled) SPV startup/readiness helpers for future re-enable. |
| packages/rs-platform-wallet/Cargo.toml | Adds dev-dependencies needed by the e2e harness. |
| Cargo.lock | Locks new/updated dependencies for the added test tooling. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@coderabbitai review all |
|
🧠 Learnings used✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 9
♻️ Duplicate comments (1)
packages/rs-platform-wallet/tests/e2e/framework/cleanup.rs (1)
57-75:⚠️ Potential issue | 🟠 Major | ⚡ Quick winKeep sub-threshold wallets recoverable.
If
0 < total <= SWEEP_DUST_THRESHOLD, both cleanup paths skipsweep_platform_addressesand still delete the registry entry. That permanently abandons the remaining credits and will slowly drain the shared bank across repeated runs. Either sweep every positive balance withReduceOutput(0)or only remove the entry once the wallet is actually empty.Also applies to: 109-121, 145-163
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/rs-platform-wallet/tests/e2e/framework/cleanup.rs` around lines 57 - 75, The cleanup currently deletes registry entries even when 0 < total <= SWEEP_DUST_THRESHOLD, abandoning recoverable credits; update the logic in the sweep_one match branches (the block that calls registry.remove and registry.set_status) to: if the wallet balance is > 0 but <= SWEEP_DUST_THRESHOLD, call sweep_platform_addresses with ReduceOutput(0) (or otherwise perform a full sweep for any positive balance) and only call registry.remove when the wallet is actually empty; ensure failed-path still sets EntryStatus::Failed when sweep fails and that successful-path only increments swept and removes the registry entry when the post-sweep balance is zero (reference symbols: sweep_one, sweep_platform_addresses, SWEEP_DUST_THRESHOLD, ReduceOutput(0), registry.remove, registry.set_status, EntryStatus::Failed).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/rs-platform-wallet/tests/e2e/cases/transfer.rs`:
- Line 31: Rename the test function transfer_between_two_platform_addresses to
follow the convention by renaming it to
should_transfer_between_two_platform_addresses; update the async fn declaration
(and any internal references or usages of
transfer_between_two_platform_addresses) to the new name so the test name begins
with "should" while keeping the function body and attributes unchanged.
- Around line 51-79: This test performs real network calls via
s.ctx.bank().fund_address and s.test_wallet.transfer / wait_for_balance; change
it to comply with the "no network in unit/integration tests" rule by either (A)
moving this file/case to an e2e-only suite (so it runs under an e2e test runner)
or (B) refactoring to inject mocked implementations for the bank client and
wallet observer used by wait_for_balance and transfer (replace s.ctx.bank() and
any network-dependent wait_for_balance calls with test doubles that simulate
funding/transfer and observable balance updates); update references to
next_unused_address, transfer, and wait_for_balance to use the mocks or the
e2e-only harness accordingly.
In `@packages/rs-platform-wallet/tests/e2e/framework/config.rs`:
- Around line 34-50: Config currently derives Debug and will print sensitive
bank_mnemonic; replace the automatic derive with a manual impl Debug for Config
that omits or redacts bank_mnemonic (e.g., display "REDACTED" or hide its value)
and prints the other fields normally; implement Debug in the same module
referencing the struct name Config and its fields (bank_mnemonic, network,
dapi_addresses, min_bank_credits, workdir_base, trusted_context_url) so future
secret fields can also be redacted consistently.
In `@packages/rs-platform-wallet/tests/e2e/framework/registry.rs`:
- Around line 225-259: Rename the three test functions to follow the "should …"
naming convention: change missing_file_opens_empty to a descriptive name like
should_open_empty_if_file_missing, change insert_remove_round_trip_persists to
should_persist_insert_remove_round_trip, and change
corrupt_file_falls_back_to_empty to should_fall_back_to_empty_on_corrupt_file;
update the fn identifiers in
packages/rs-platform-wallet/tests/e2e/framework/registry.rs (the tests currently
named missing_file_opens_empty, insert_remove_round_trip_persists,
corrupt_file_falls_back_to_empty) and run cargo test to ensure no references
break.
In `@packages/rs-platform-wallet/tests/e2e/framework/wallet_factory.rs`:
- Around line 291-293: Rename the test function
default_spec_matches_pinned_constants to follow the repository "should …"
convention (e.g., should_default_spec_match_pinned_constants or
should_match_pinned_constants_by_default) so the test name starts with "should";
update the function declaration fn default_spec_matches_pinned_constants() to
the new name and keep the body (including PlatformPaymentAccountSpec::default())
unchanged so references and assertions remain valid.
In `@packages/rs-platform-wallet/tests/e2e/framework/workdir.rs`:
- Line 92: Rename the test function
first_call_takes_slot_zero_second_falls_through to follow the required "should
..." convention (for example
should_first_call_take_slot_zero_and_second_fall_through); update the function
identifier wherever referenced (the test declaration itself and any uses in
attributes or calls) so the Rust test name begins with "should_" and keep the
original behavior and test annotation (e.g., #[test]) unchanged.
- Around line 50-61: The current error handling in the lock acquisition loop
treats every Err(err) as a busy slot; update the branch in the function that
opens/locks `lock_file` (the block that logs "workdir slot busy, trying next")
to inspect the IO error kind: if the error indicates contention (e.g.,
would-block / ErrorKind::WouldBlock or the platform-specific WouldBlock
equivalent), keep the existing tracing::debug and continue; for any other errors
(permission, other IO), log an error and propagate/return the error instead of
retrying so real failures aren’t swallowed.
In `@packages/rs-platform-wallet/tests/e2e/README.md`:
- Around line 99-106: The fenced code blocks in the e2e README (the blocks
starting with the "Bank wallet under-funded." message and the "SetupGuard
dropped without explicit teardown — wallet <id>" message) lack language tags,
causing MD040 lint failures; update those fenced blocks to include a language
specifier (e.g., change ``` to ```text) for both occurrences (the block
containing "Bank wallet under-funded." and the later block containing
"SetupGuard dropped without explicit teardown") so the markdown linter accepts
them.
- Around line 233-235: Update the stale troubleshooting example to match the
current error shape emitted by the pick_available_workdir routine: replace the
quoted `No available workdir slots (tried 0..10)` text with the actual error
text produced by pick_available_workdir (copy exact current message/format), and
note that this occurs when all 10 workdir slots are locked so operators search
logs for the correct string; reference pick_available_workdir in the note so
maintainers can locate the implementation for future changes.
---
Duplicate comments:
In `@packages/rs-platform-wallet/tests/e2e/framework/cleanup.rs`:
- Around line 57-75: The cleanup currently deletes registry entries even when 0
< total <= SWEEP_DUST_THRESHOLD, abandoning recoverable credits; update the
logic in the sweep_one match branches (the block that calls registry.remove and
registry.set_status) to: if the wallet balance is > 0 but <=
SWEEP_DUST_THRESHOLD, call sweep_platform_addresses with ReduceOutput(0) (or
otherwise perform a full sweep for any positive balance) and only call
registry.remove when the wallet is actually empty; ensure failed-path still sets
EntryStatus::Failed when sweep fails and that successful-path only increments
swept and removes the registry entry when the post-sweep balance is zero
(reference symbols: sweep_one, sweep_platform_addresses, SWEEP_DUST_THRESHOLD,
ReduceOutput(0), registry.remove, registry.set_status, EntryStatus::Failed).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0379415c-b6af-4b82-b05c-635af13cb042
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (23)
packages/rs-platform-wallet/Cargo.tomlpackages/rs-platform-wallet/tests/.env.examplepackages/rs-platform-wallet/tests/e2e.rspackages/rs-platform-wallet/tests/e2e/README.mdpackages/rs-platform-wallet/tests/e2e/cases/mod.rspackages/rs-platform-wallet/tests/e2e/cases/transfer.rspackages/rs-platform-wallet/tests/e2e/framework/bank.rspackages/rs-platform-wallet/tests/e2e/framework/cleanup.rspackages/rs-platform-wallet/tests/e2e/framework/config.rspackages/rs-platform-wallet/tests/e2e/framework/context_provider.rspackages/rs-platform-wallet/tests/e2e/framework/harness.rspackages/rs-platform-wallet/tests/e2e/framework/mod.rspackages/rs-platform-wallet/tests/e2e/framework/registry.rspackages/rs-platform-wallet/tests/e2e/framework/sdk.rspackages/rs-platform-wallet/tests/e2e/framework/spv.rspackages/rs-platform-wallet/tests/e2e/framework/wait.rspackages/rs-platform-wallet/tests/e2e/framework/wait_hub.rspackages/rs-platform-wallet/tests/e2e/framework/wallet_factory.rspackages/rs-platform-wallet/tests/e2e/framework/workdir.rspackages/rs-sdk/src/platform/transition.rspackages/rs-sdk/src/platform/transition/address_inputs.rspackages/simple-signer/Cargo.tomlpackages/simple-signer/src/signer.rs
|
✅ Review complete (commit 921833f) |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 24 changed files in this pull request and generated 9 comments.
Comments suppressed due to low confidence (2)
packages/rs-sdk/src/platform/transition/address_inputs.rs:39
- Now that this helper is public,
nonce + 1can overflow whennonce == u32::MAX, which will panic in debug builds and wrap in release builds. Consider usingchecked_add(1)and returning an error (or otherwise handling the overflow) so callers can't accidentally produce an invalid/wrapping nonce.
pub fn nonce_inc(
data: BTreeMap<PlatformAddress, (AddressNonce, Credits)>,
) -> BTreeMap<PlatformAddress, (AddressNonce, Credits)> {
data.into_iter()
.map(|(address, (nonce, credits))| (address, (nonce + 1, credits)))
.collect()
packages/rs-sdk/src/platform/transition/address_inputs.rs:18
fetch_inputs_with_nonceis now public but has no doc comment explaining (1) that it performs existence/balance checks and (2) that callers typically need to applynonce_incbefore building a transfer (astransfer_address_fundsdoes). Please document the intended call pattern (or provide a single public helper that returns the incremented nonces) to reduce misuse from external callers.
pub async fn fetch_inputs_with_nonce(
sdk: &Sdk,
amounts: &BTreeMap<PlatformAddress, Credits>,
) -> Result<BTreeMap<PlatformAddress, (AddressNonce, Credits)>, Error> {
if amounts.is_empty() {
return Err(Error::from(TransitionNoInputsError::new()));
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…-platform-wallet-e2e
…rant transfer fixture
* `transfer.rs` — funding/transfer fixtures handle `[ReduceOutput(0)]`
fee deduction via post-fee floors and split-fee assertions
(bank_fee + transfer_fee), so the test no longer asserts the gross
amount lands intact. Module doc points at the actual error path
(`FrameworkError::Bank` for missing mnemonic, panic for under-funded
bank) per Copilot's `transfer.rs:7` note.
* `config.rs` — replace `derive(Debug)` with a manual impl that
redacts `bank_mnemonic` so a stray `{config:?}` log or panic
backtrace can't leak the shared funding seed (CodeRabbit `config.rs:50`).
* `workdir.rs` — match `ErrorKind::WouldBlock` as slot-busy and
propagate every other IO error as `FrameworkError::Io`, instead of
swallowing them all as "slot busy" (CodeRabbit `workdir.rs:50`).
* `registry.rs` — drop the never-set `EntryStatus::Sweeping` variant +
doc references; the per-slot workdir lock already serialises the
only writer, so no transient cross-process state is required
(Copilot `registry.rs:35`, `cleanup.rs:75`).
* `cleanup.rs` — replace the hardcoded `SWEEP_DUST_THRESHOLD` constant
with the protocol's `min_input_amount` from `PlatformVersion`, so
the sweep gate stays in lock-step with whatever `address_funds`
validation requires.
* `wait_hub.rs` — fix stale `platform_address_sync` import path; the
module moved to `manager::platform_address_sync` in PR #3564 and
is re-exported at the crate root.
* `README.md` — fenced-code-block language tags (MD040), corrected
workdir-exhausted error string, first-run timing reflects
`TrustedHttpContextProvider` default (no SPV in critical path),
troubleshooting note rescoped, teardown step list no longer claims
to wait for the bank to observe credits.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…network-seeds Replaces the hardcoded `TESTNET_DAPI_ADDRESSES` list in `framework/sdk.rs` with a `default_address_list_for_network` helper that mirrors PR #3533's upstream `default_address_list_for_network` byte-for-byte: pulls `dash_network_seeds::evo_seeds(network)`, filters seeds with a `platform_http_port`, and constructs DAPI URLs from the seed IPs. Once PR #3533 (`feat(sdk): source mainnet/testnet bootstrap from dash-network-seeds`) lands in `v3.1-dev` and exposes `SdkBuilder::new_testnet()` properly (currently `unimplemented!()` on this branch's base), the helper collapses into a single `SdkBuilder::new_testnet()` call with no behavioural delta. `framework/spv.rs::seed_p2p_peers` follows suit: testnet peer IPs come from `dash_network_seeds::evo_seeds(Testnet)` when the operator hasn't supplied an explicit DAPI list. Also drops the dead `TESTNET_DAPI_ADDRESSES` re-import. Adds `dash-network-seeds` as a dev-dependency, pinned to the same rust-dashcore rev as the workspace `dashcore` to keep all sibling crates in lock-step. Resolves the `sdk.rs:41` review thread. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…3040 Bumps `FUNDING_CREDITS` 50M -> 100M and `TRANSFER_CREDITS` 10M -> 50M (plus matching floors) so `output[0]` comfortably exceeds Drive's chain-time fee. Issue #3040 (`calculate_min_required_fee` is too low) causes `[ReduceOutput(0)]` selections with small `output[0]` to fail at chain time despite passing the static-fee check. Picking output amounts well above the empirical chain-time ceiling sidesteps the bug until the dpp-layer fix lands. Bumps `DEFAULT_MIN_BANK_CREDITS` 100M -> 500M to keep the bank covering several runs at the larger per-run cost (also follows DET's 5x safety-factor pattern from dash-evo-tool#513). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ct-inputs' into feat/rs-platform-wallet-e2e
… Found-025 sync-discard race TK-001 and TK-014 failed in the v53 14-thread run, both timing out in the SETUP FUNDING gate before any token logic ran (tk_001_token_transfer.rs:67 setup_with_token_and_two_identities; tk_014_token_group_action.rs:109 setup_with_per_identity_funding). In both, bank.fund_address chain-confirmed the funding (nonce streak 2/2) before the wait, then the rs-sdk address-sync silently discarded the fetched balance update because the target address was not yet in pending_addresses — Found-025, amplified by 14-thread concurrency. Not production defects: transfer/group-action/co-sign code never executed and siblings (TK-001b/c, TK-009/010/012) were green in the same run. Root cause in the shared chokepoint framework/mod.rs::setup_with_per_identity_funding: it gated on wait_for_balance, whose proof-verified hand-off only runs AFTER the Found-025-poisoned local sync map (balances().get(addr)) first reaches target — so under Found-025 the proof gate was never reached and the budget expired in the local-view branch (60-62 polls, no chain-confirmed line). Fix: observe funding directly via the proof-verified AddressInfo::fetch path (wait_for_address_balance_chain_confirmed_n, CHAIN_CONFIRMED_CONSECUTIVE_SUCCESSES) — the same chain-state read the validator walks and the family PA-009c adopted — bypassing the poisoned map entirely. The existing strong wait_for_address_known_to_platform gate is unchanged. Only the funding-observation mechanism changed: no funding amounts, identity counts, contract publish, propose/co-sign, or token/identity assertions altered. Deterministic and concurrency-independent, so it hardens the whole setup-helper blast radius (all 22 TK-*/ID-*/CR-003/DPNS-001 cases routing through setup_with_per_identity_funding). No new Found-NNN pin and no upstream issue (Found-025 already owns the root cause). A TK-wave serialization / worker-pool cap remains a documented fallback only — not implemented, since the proof-verified read-back structurally bypasses the poisoned map. TEST_SPEC.md: TK-001 (quick-index + body) and TK-014 (quick-index + body) reclassified green -> red-real-fail mirroring TK-007 wording, cross-linked to Found-025; one changelog entry added. All three references per test are mutually consistent (no stale green/PASS-in-v47 drift). Live e2e requires a bank-funded node (yarn start) unavailable in this environment; verified by inspection + cargo build --tests + cargo clippy (both clean). Live re-validation deferred to the combined v54 run. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ound-008 env-mask FIX 1 (#475): the e2e README documented the opt-in invocation with `--ignored`, which runs ONLY the `#[ignore]`-attributed subset (~40/108) and silently skips owned-fix cases. Corrected to `--include-ignored` so the full suite runs, with a one-line note explaining why `--ignored` alone is wrong. FIX 2 (#474, CLAUDE.md infra-blocker rule): added a `// TODO(env):` marker in al_001 near the Core-funded setup gate and a brief note in TEST_SPEC.md's AL-001/Found-008 entry recording that the Found-008 pin is env-masked when the e2e testnet Core L1 bank is depleted (al_001 dies at the setup gate, not at the designed FinalityTimeout; same depletion also fails cr_003 + id_002b). Funding address phrased generically — the specific address is being verified separately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…of-band) User will top up the e2e Core L1 bank wallet directly, so the env-mask documentation is unnecessary. Removes the FIX 2 content added in the previous commit: the `// TODO(env):` marker in al_001 near the Core-funded setup gate and the AL-001/Found-008 "pin coverage degraded under Core-bank depletion" bullet in TEST_SPEC.md. Net effect of this commit pair is README-only — the `--ignored` -> `--include-ignored` run-flag correction (#475). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ter store-error wallet loss) register_wallet logs and swallows the registration-round persister `store` error (manager/wallet_lifecycle.rs:276-282) then inserts the wallet into self.wallets unconditionally (wallet_lifecycle.rs:347-349). A successful-looking import leaves no persisted record and vanishes on the next launch — HIGH-severity silent data loss. Note the asymmetry: the load_persisted / initialize_from_persisted failure paths in the same function already roll back and return Err; the registration store does not. Deterministic pin (no live network, no concurrency): injects a StoreFailsPersister whose `store` returns Err while `load`/`flush` succeed (so the already-correct load_persisted rollback path does not mask the defect), drives create_wallet_from_seed_bytes through a mock-SDK manager, and asserts the correct atomic-failure contract — the call returns Err AND the wallet is absent from wallet_ids(). Fails today for the real reason; flips green once the registration store is treated as load-bearing. #[ignore]d — live run deferred. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… for post-snapshot addresses (Found-025) `incremental_catch_up` built its `key_to_tag` lookup once from a single pre-RPC `provider.pending_addresses()` snapshot and passed it by immutable reference into both apply loops. The `if let Some(..) = address_lookup.get(..)` predicate had no `else`, so any balance change the platform returned for an address derived *after* the snapshot was dropped with no log, metric, or error — `result.found` never got it and `on_address_found` was never called. Under concurrent multi-identity funding the derive-fund-sync interleave is routine, which is why e2e gates TK-001/007/013/014 and id_005 flaked here. Extract the two inline apply loops into a pure `pub(crate) apply_address_changes` seam (no Sdk, no network, no async) that returns applied updates plus the addresses absent from the snapshot. The new `apply_block_changes` re-polls `pending_addresses()` when an unknown address appears (mirroring the tree-scan refresh) and replays only the previously-unknown subset, so a fresh receive address is recovered and known-address `AddToCredits` deltas are never double-counted. An address still unknown after the refresh is logged at `warn` — observable, never silently dropped. Known-address behavior is byte-for-byte identical. Adds three deterministic `#[cfg(test)]` regression guards on the pure seam (no proof/Sdk needed): unknown-address surfacing, post-snapshot recovery through the refresh, and delta double-count safety. All three fail on the pre-fix silent-discard logic and pass post-fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> (cherry picked from commit 35925f8) (cherry picked from commit 5c590341f65c89221e043ef89720fa948250e187)
…ex 0 `primary_core_receive_address` routed through `CoreWallet::next_receive_address_for_account(0)`, whose pool advances its "next unused" cursor off index 0 as soon as a UTXO lands there — so the operator-funded Core top-up address drifted run-to-run, stranding duffs on stale empty addresses. Mirror the existing `derive_platform_address_at_index` pattern with `derive_core_receive_address_at_index`: derive a deterministic `m/44'/coin'/0'/0/0` address via the live wallet's `derive_public_key`, reconstructing the P2PKH address exactly as key-wallet's own address pool does. The under-funded preflight now reports this same stable address; `CORE_TX_FEE_RESERVE` semantics and the under-funded arithmetic are unchanged. <sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub> (cherry picked from commit 07f160c1d09eebfed320dbd0408195ee7bd5ea19)
…down with preflight The Core-bank auto-refill defaults were 3-4 orders of magnitude too low to keep the bank funded. A FULL e2e pass burns ~13 tDASH ≈ 1.3e9 duffs (1 DASH = 1e8 duffs); the old defaults were 100_000 / 1_000_000 duffs (0.001 / 0.01 DASH) — not even 0.1% of one pass. Re-anchor sizing on the measured per-pass burn (CORE_BURN_PER_FULL_PASS_DUFF = 1_300_000_000): - threshold: 2_000_000_000 duffs (~20 tDASH) — one full pass + ~0.5-pass margin so the bank is topped up before it can starve mid-pass. - target: 5_000_000_000 duffs (~50 tDASH ≈ 3.8 passes) — one slow Platform→Core withdrawal buys several passes of runway. Run the refill on BOTH ends of the lifecycle: - setup: existing call (harness.rs, unchanged) fires first. - teardown: new call in SetupGuard::teardown after the sweep returns this test's funds to the bank — the cheapest point to refill for the next pass. Below-threshold-guarded inside the helper, so it's a no-op when already funded; best-effort, never fails a teardown. Add a setup preflight (assert_core_funded_for_one_pass): after the refill attempt, if confirmed Core is still below one full pass (CORE_REFILL_OPERATIONAL_MIN_DUFF), fail fast with a FrameworkError::Bank naming the fixed index-0 top-up address and the exact shortfall — mirrors the existing send_core_to under-funded error shape — instead of silently entering a doomed run. Unit test pins the defaults to the measured burn (threshold ≥1 pass, target ≥3 passes, preflight floor == 1 pass). <sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub> (cherry picked from commit 6662725c4c95a8866eb62014fc070ca23ca38310)
…nfirmed (Found-025) The funding-gate `wait_for_balance` in the identity/address state-transition tests checks the wallet's local sync map before handing off to the proof-verified chain gate. Under multi-thread churn the rs-sdk address-sync silently drops a fetched balance update when the address isn't yet in `pending_addresses` (Found-025), poisoning that local map so the precondition never reaches target and the proof-verified hand-off never runs — the gate times out before the immediately-following broadcast. Swap the 9 funding-then-broadcast gates (register_identity_from_addresses / top_up_from_addresses inputs) to `wait_for_address_balance_chain_confirmed_n` with `CHAIN_CONFIRMED_CONSECUTIVE_SUCCESSES`, mirroring the `setup_with_per_identity_funding` precedent exactly. Post-broadcast `wait_for_balance` sites whose assertion subject IS the wallet's local `.balances()` view (id_005 dest readback, all PA self-transfer tests) are left untouched — swapping them would un-sync the local map those assertions depend on. <sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub> (cherry picked from commit bf4779e288ed2b22f52680b22543f57fc8690848)
…unmask QA-501/502 (id_005:127, id_002:117): Found-025 fix unmasked a downstream Found-026-family production cursor race — next_unused_address() returns a DUPLICATE under 14-thread churn. RED-by-design pins + TEST_SPEC reclass (green → red-by-design concurrency-only). No production fix; assertions stay genuinely RED for the real reason. Same root component + concurrency trigger as Found-026 (PA-008b); distinct observable mechanism (duplicate-derivation vs enqueue-miss) — linked to Found-026 family, no new Found-NNN (#496 holds filing; Found-026 still suspected). QA-503 (id_sweep:167): HARNESS test-defect, minimal fix. The secondary bank-identity post<=pre invariant is structurally unobservable under concurrent harness bank_rebalance core-refill (which by design tops up the bank identity; growth delta exactly matches topup_credits). Sweep correctness already pinned by the race-immune swept_identity_credits assertion — same flaw class QA-V39-001 fixed for the primary check. Removed the unobservable invariant (not green-paint: no real check weakened, no production source touched). QA-504 (pa_006b:83): Found-025-family known-fail under documented multi-thread conditions; un-swapped wait_for_balance reads the poisoned local map (#480 intentional non-swap). TEST_SPEC status corrected (green → red-real-fail multi-thread only). Flagged a swap-scope recommendation (swap ONLY the funding gate) — NOT applied (out of code scope). <sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub> (cherry picked from commit e53d543a8f24e3ff3dbb917fd122f71322d52e67)
… chain-confirmed (QA-504) Corrects a #480 mis-scoping: pa_006b:81 is a funding PRECONDITION gate, not a post-broadcast `.balances()` assertion, so the #480 local-map rationale never applied. Swapped ONLY :81 to `wait_for_address_balance_chain_confirmed_n` (same pattern / arg-order / CHAIN_CONFIRMED_CONSECUTIVE_SUCCESSES as the #480 funding-gate swaps) — resolves the v-run's documented deterministic 14-thread funding-gate timeout. Post-broadcast `wait_for_balance(&addr_dst)` at :170 stays correctly un-swapped per #480. TEST_SPEC PA-006b reclassified `red-real-fail` → `partially-fixed (QA-504)`: the documented failure is fixed, but a clean multi-thread pass is NOT claimed — :170 retains residual Found-025-family exposure and no live re-run was possible (no bank-funded node). Honest, not green-washed. <sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub> (cherry picked from commit 92881fde6cce24ccc47123ef7982e5b961682184)
…-scoping across PA-* (QA-001/#508) #480 swapped 9 identity funding gates to wait_for_address_balance_chain_confirmed_n but excluded ALL PA-* tests wholesale. That was wrong for funding-PRECONDITION gates: a wait_for_balance that gates a funding/source address BEFORE a broadcast that consumes it is the Found-025 poisoned-local-map hazard (stale 0 → 60s timeout). pa_006b:81 was instance #1 (already fixed). #506 found pa_001b:66 as instance #2 (PASS→FAIL regression). This pass systematically classifies EVERY wait_for_balance site in cases/ and swaps the 11 remaining funding-precondition gates: pa_001:103, pa_001b:64, pa_001b:139, pa_001c:57, pa_002:111, pa_002b:64, pa_003:138, pa_004:96, pa_004b:125, pa_006:75, pa_009:171 Post-broadcast / local-view waits whose balance IS the assertion subject, and RED-by-design pins (pa_3040, found_*, id_005, PA-005/007/008* concurrency- observability), stay correctly un-swapped per the legitimate #480 KEEP rationale. Every timeout / expected / expect-message preserved; no assertion weakened. Also fixes the PA-001b TEST_SPEC internal inconsistency (index row said `blocked` while the detail body claimed `PASS`): both now consistently and honestly state `precondition-fixed` — subcase_a no longer Found-025-times-out, but the deliberately-kept post-broadcast waits at :95/:223 retain residual Found-025- family multi-thread exposure (same posture as PA-006b:170); not an unproven clean multi-thread pass. <sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub> (cherry picked from commit 2abd21182a4d154f247f007a406f4a138688a595)
…e refs (PROJ-001) Independent verify found the PA-001b index row (~:181) and detail body (~:488) cited drifted source line numbers. Corrected against the actual current pa_001b_change_address_branch.rs after the #508 swap-block insertion shifted lines down: subcase_a funding-precondition gate (now `_n`): :64 -> :70 subcase_b funding-precondition gate (now `_n`): :139 -> :154 subcase_a kept post-broadcast wait (addr_2): :95 -> :107 subcase_b kept post-broadcast wait (change_addr)::223 -> :244 `:95` had drifted onto the `transfer_with_change_address(` call; `:223` had likewise drifted off the kept change_addr wait (true line :244). Line-number refs only — every semantic claim is verbatim unchanged. Doc-only; no code touched. <sub>🤖 Co-authored by [Claudius the Magnificent](https://github.com/lklimek/claudius) AI Agent</sub> (cherry picked from commit 54ec95baf3271ac7d7543a7926dd018a67512727)
…ound-026-family RED (proven 14-thread v-run) Index + body Status for PA-001/PA-002/PA-003 said green/IMPLEMENTED-passing while a funded canonical 14-thread v-run at e83a43c shows them panicking deterministically on assert_ne! duplicate-address — the same Found-026-family next_unused_address pool-cursor race already pinned by ID-002/ID-005. Mirrors the existing ID-002/ID-005 red-by-design (concurrency-only) classification, adds the trio to the Found-026 detail family-members list, and removes the index/body inconsistency the V28-303 concession already conceded. Doc-only; no cases/*.rs, assertions, or test behaviour touched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
E2E test-results record — consolidated (authoritative)Branch:
CI reading guidanceThe expected-red set SHRANK with the Found-026/QA-001/gate-fix/Found-017/reclass chain ( Now GREEN (was red/masked, fixed by this chain)
Remaining expected non-green — upstream / tracked only
Found-025 WARN seam — expected, not a regressionThe Campaign fix-set — landed on feat HEAD
|
| Item | Commit | State |
|---|---|---|
#516 dead event_manager() removal + Lagged-stall (+ carried Found-025, #480/#508) |
9e24f1f343 |
prior base |
| Found-026 reserve platform receive address on hand-out | 0618e6eba8 |
FIXED |
| QA-001 align slot-0 consumption w/ native reserve-on-hand-out | cba5125a29 |
FIXED |
chain-confirmed-gate vs stale-local-cache (5 cases sync_balances) |
00437dbeed |
FIXED |
| Found-017 fail-closed register-wallet persist error | 0e547b02fe |
FIXED |
reclass: Found-026/017 FIXED, PA-005 Inv-1 assert_ne!, pa_001/002/003/id_002/id_005 re-attributed, found_017 pin→regression |
76baafda3f |
FIXED (HEAD) |
Validation evidence (no green-paint)
Found-026 + Found-017 proven via a focused 3/3 14-thread re-run on the affected sites + a fully-clean full-suite R2 + architecture adjudication of the PA-005 Invariant-1 re-spec. The masked PA-001/002/003 + id_002/id_005 went genuinely green once the duplicate-address race was eliminated at the production layer (0618e6eba8). Integration was Adams-verified scope-clean (byte-faithful ff 9e24f1f343..76baafda3f, no stray production files).
Conclusion
Found-026 and Found-017 are FIXED in landed code, not pinned. PA-001/002/003 + id_002/id_005 + found_017 + pa_005 are green. Remaining expected non-green = found_006/found_021/found_022 (rust-dashcore #762/#763/#764), pa_3040 (#3040), al_001 (#3641) — all upstream/tracked. Found-025 WARN seam expected-present. Zero unexplained reds, zero new regressions; campaign fix-set landed. v3.1-dev backports tracked as separate sibling PRs (semantic re-apply — regions diverged).
🤖 Generated with Claude Code
…structor-inject handler set Replace PlatformEventManager's ArcSwap+add_handler with an immutable Arc<[handler]> set fixed at construction, matching dash-spv's own immutable event_handlers; PlatformWalletManager::new now takes a Vec<app_handlers>. The e2e mn-list ManagerError observer is built up front and threaded in via that vec (broadcast-subscribed per wait) instead of late-registered through the deleted accessor. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…signal (QA-516-001/002) dash-spv emits one Masternode ManagerError per failed inbound message, so a persistent stall bursts past the 16-slot ring; the recv match now returns the stall FrameworkError on RecvError::Lagged instead of silently dropping it, restoring the O(ms) fast-fail. RecvError::Closed is handled explicitly. Comments corrected to the per-failed-message emission model. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… (Found-026) key-wallet AddressPool::next_unused returns the first address whose `used == false`; for platform-payment addresses `used` only flips on a positive synced balance, so under thread churn a concurrent next_unused_receive_address re-handed the same unsynced index (duplicate address, collision, balance stuck 0). Now select-and-reserve atomically inside the already-held wallet_manager.write() guard: next_unused_with_info + mark_index_used(info.index); a later real sync hit on the reserved index is an idempotent no-op so highest_used/gap-limit accounting isn't double-counted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…erve-on-hand-out (QA-001) The reserve-on-hand-out contract is now native in next_unused_receive_address. Harness manual mark retired; slot-0 + pa_001b distinct-address assumers updated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ound-017) register_wallet swallowed the load-bearing store() Err then committed+returned Ok -> silent wallet loss on restart; now rolls back the in-memory insert and propagates the error, mirroring the load_persisted rollback. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…A-005 Invariant-1 + correct chain-gate attribution Found-026/QA-001/gate-fix/Found-017 proven (3/3 focused + R2-clean + Nagatha-adjudicated): the reserve-on-hand-out fix and fail-closed registration are genuinely correct. PA-005 Invariant-1 re-specified assert_eq->assert_ne per adjudication (A) — back-to-back next_unused_address now reserves on hand-out and returns pairwise-distinct addresses; pa_001/002/003/id_002/id_005 re-attributed from the now-fixed Found-026 next_unused race to the chain-confirmed-gate-vs-stale-local-map test-sequencing defect fixed by the gate-fix. found_017 pin reclassed red-by-design -> passing-as-regression (pin file byte-untouched; positive companion guards the success path). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ccess evidence wait_for_core_balance / bank Core funding gate 300/900->180s (worst cold success ~100s, ~1.8x margin); over-sized ceilings only padded the FAIL path. mn-list cold floor, tk_013, tk_002, al_001 deliberately untouched (env / protocol-epoch / RED-by-design); FUNDING_TX_CONFIRMATION_TIMEOUT left at 120s — in-source 75s contention evidence exceeds a 60s cap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Issue being fixed or feature implemented
End-to-end test suite for
rs-platform-wallet, now carrying — as FIXED, landed code (not pinned, not deferred) — the Found-026 platform-receive-address reserve-on-hand-out defect and the Found-017 register-wallet persist-error fail-closed defect, on top of the Found-025 rs-sdk address-sync fix and the #516 dead-accessor removal. The duplicate-address race that previously masked PA-001/002/003 and id_002/id_005 is gone; those cases are now green. The branch is at landed HEAD76baafda3f.What was done?
Chain atop the prior #516 base (
9e24f1f343):9e24f1f343—fix(rs-platform-wallet/e2e)(chore(release): bump version to v0.22.15 and update changelog #516, QA-516-001/002): prior base. Deletes the deadSpvRuntime::event_manager()accessor, replacesPlatformEventManager's mutableArcSwap+add_handlerwith an immutable construction-fixedArc<[handler]>set; treats broadcastRecvError::Laggedas the mn-list stall signal, fast-fails instead of silently dropping. Also carries the Found-025 rs-sdk address-sync fix (separately PR'd as fix(sdk): address-sync no longer silently discards balance changes for post-snapshot addresses (Found-025) #3650 againstv3.1-dev) and the earlier fix(dashmate): docker undefined error #480/test(dapi): fix froken subscribeToNewBlockHeaders test #508 funding-gate triage.0618e6eba8—fix(rs-platform-wallet)(Found-026, FIXED): reserve the platform receive address on hand-out sonext_unused_address()cannot return a duplicate under concurrency. Production fix insrc/wallet/platform_addresses/wallet.rs(+150/-2) plus two guard tests.cba5125a29—fix(rs-platform-wallet/e2e)(QA-001, post-condition): align slot-0 consumption with the native reserve-on-hand-out semantics (wallet_factory.rs,gap_limit.rs,pa_001b_change_address_branch.rs).00437dbeed—fix(rs-platform-wallet/e2e)(chain-confirmed-gate vs stale-local-cache, post-test(dapi): fix froken subscribeToNewBlockHeaders test #508): sync wallet cache after the chain-confirmed funding gate before consume, across 5 cases (pa_001,pa_002,pa_003,id_002,id_005—sync_balancesinsertion). This corrects the test-sequencing defect that the reclass below re-attributes those cases to.0e547b02fe—fix(rs-platform-wallet)(Found-017, FIXED): fail-closed on registration persist error insrc/manager/wallet_lifecycle.rs(+14); adds thefound_017_register_wallet_store_ok_persistsregression case (+119) and registers it incases/mod.rs.76baafda3f—docs(rs-platform-wallet/e2e)(gated reclass, HEAD): reclassify Found-026/Found-017 as FIXED in TEST_SPEC; re-spec PA-005 Invariant-1assert_eq!→assert_ne!per architecture adjudication (now correct, passes); RE-ATTRIBUTE pa_001/002/003/id_002/id_005 from the Found-026-family race to the now-fixed chain-confirmed-gate test-sequencing defect (now green); convert thefound_017pin from red-by-design to passing-as-regression.v3.1-dev backports are tracked as separate sibling PRs — Found-026 and Found-017 require semantic re-apply because the target regions diverged at
v3.1-dev; they are not clean cherry-picks and are not part of this PR.How Has This Been Tested?
CI posture — READ THIS BEFORE THE e2e LINE (honest pre-statement):
The expected-red set SHRANK with this chain. PA-001/002/003, id_002/id_005, QA-501/QA-502 (the Found-026-family race) and
found_017are no longer expected red — they are FIXED and green (found_017now passes as a regression test). Thers-platform-wallete2e job may still be non-green, but the remaining non-green set is now strictly:found_006,found_021,found_022— RED-by-design upstream-behavior pins against rust-dashcore feat(dpp): wasm-dpp: integration tests for document #762 / fix wasm-dpp for identity v2 #763 / refactor: renamed a few query methods and added a few to query Drive … #764 (the failure IS the proof).pa_3040— tracked as AddressFundsTransferTransition::calculate_min_required_fee is too low #3040.al_001— Found-008 / tracked as Found-008:LockNotifyHandler::notify_waiters()drops lock events arriving inwait_for_proof's check/await gap (concurrent asset-lock builds stall on FinalityTimeout) #3641.pa_005— re-spec'd toassert_ne!per adjudication; now correct and passes (listed for transparency, not as a red).The
dash_sdk … (Found-025)WARN seam is still EXPECTED-present — it is the Found-025 fix's observability working as designed (address-sync surfacing the balance-change reconciliation it previously discarded silently), NOT a regression.Validation status (stated precisely — no green-paint):
Found-026 and Found-017 were proven via a focused 3/3 14-thread re-run on the affected sites plus a fully-clean full-suite R2 and an architecture adjudication of the PA-005 Invariant-1 re-spec. No flake-masking, no green-paint — the previously-masked PA-001/002/003 + id_002/id_005 went genuinely green once the duplicate-address race was eliminated at the production layer. The Found-025 fix remains AUTHENTIC under the prior 14-thread v-run (#501; 1845 upstream WARNs still emit). The integration onto feat was Adams-verified scope-clean (byte-faithful fast-forward
9e24f1f343..76baafda3f, no stray production files, no injection). This PR remains DRAFT pending the operator's final disposition.Remaining non-green is INTENTIONAL (the failure IS the proof), NOT failures to fix in this PR:
found_006/found_021/found_022(rust-dashcore #762/#763/#764, RED-by-design),pa_3040(#3040),al_001(Found-008/#3641). PA-005 is green post-re-spec.Breaking Changes
None. The Found-026 fix (
0618e6eba8) and Found-017 fix (0e547b02fe) are correctness fixes inrs-platform-walletwith no external API-surface change. The #516 refactor (carried in the9e24f1f343base) changesPlatformWalletManager::newto take aVec<app_handlers>and deletes the unusedSpvRuntime::event_manager()accessor — an internal-handler-wiring change with no external API consumer; all in-tree call sites and examples are updated in the same commit. The Found-025 rs-sdk fix is separately PR'd as #3650 againstv3.1-dev.Related Issues & PRs
All entries verified read-only via
ghagainstdashpay/platformanddashpay/rust-dashcore. State as of refresh.Carve-out / backport PRs (v3.1-dev)
v3.1-dev) — fix(sdk): address-sync no longer silently discards balance changes for post-snapshot addresses (Found-025) #3650v3.1-dev); semantic re-apply of0618e6eba8, region diverged at v3.1-dev — fix(rs-platform-wallet): reserve platform receive address on hand-out (Found-026) [backport] #3658v3.1-dev); semantic re-apply of0e547b02feat v3.1-devwallet_lifecycle.rs— fix(rs-platform-wallet): fail-closed on registration persist error (Found-017) [backport] #3659v3.1-dev); itsevent_manager()accessor was dropped, superseded by chore(release): bump version to v0.22.15 and update changelog #516's deletion carried in this PR — feat(platform-wallet): SPV cancel_background/identity_ids accessors + FFI no-selectable-inputs error mapping #3651v3.1-dev) — fix(platform-wallet): local-ledger ownership guard (V27-007) #3648v3.1-dev); relevant to the Found-026 rebase-watch — feat(platform-wallet): watermark monotonic-merge #3647v3.1-dev); immediate stack base of this PR (test(rs-platform-wallet): e2e suite, Found-025 fix + triage pins #3549 targetsfix/rs-platform-wallet-auto-select-inputs) — fix(platform-wallet): auto_select_inputs honors Σ inputs == Σ outputs #3554Upstream pins (rust-dashcore — RED-by-design)
top_up_indexfield toCreditOutputFunding::IdentityTopUp(DIP-9 conformance gap) — OPEN — Found-006 /found_006pin — Addtop_up_indexfield toCreditOutputFunding::IdentityTopUp(DIP-9 conformance gap) rust-dashcore#762TransactionRecord::update_contextsilently dropsInstantLockonInBlock/InChainLockedBlockpromotion — OPEN —found_021pin — Found-021:TransactionRecord::update_contextsilently dropsInstantLockonInBlock/InChainLockedBlockpromotion rust-dashcore#763TransactionBuilder::set_fundingmutates funds account beforebuild_signedcan fail — OPEN —found_022pin — Found-022:TransactionBuilder::set_fundingmutates funds account beforebuild_signedcan fail — phantommonitor_revisionbumps on failed builds rust-dashcore#764Tracked platform issues
LockNotifyHandler::notify_waiters()drops lock events arriving inwait_for_proof's check/await gap (concurrent asset-lock builds stall on FinalityTimeout) #3641 — Found-008:LockNotifyHandler::notify_waiters()drops lock events arriving inwait_for_proof's check/await gap — OPEN —al_001pin — Found-008:LockNotifyHandler::notify_waiters()drops lock events arriving inwait_for_proof's check/await gap (concurrent asset-lock builds stall on FinalityTimeout) #3641pa_3040pin — AddressFundsTransferTransition::calculate_min_required_fee is too low #3040wait_for_proofandrecover_asset_lock_blockinghard-code BIP-44 — asset-lock proof flow misses CoinJoin / legacy BIP-32 funding #3642 — Found-012:wait_for_proofandrecover_asset_lock_blockinghard-code BIP-44 — asset-lock proof flow misses CoinJoin / legacy BIP-32 funding — OPEN — Found-012:wait_for_proofandrecover_asset_lock_blockinghard-code BIP-44 — asset-lock proof flow misses CoinJoin / legacy BIP-32 funding #3642Superseded / closed
pending_addressessnapshot — CLOSED (former Found-025 companion issue, closed under the PR-is-the-unit convention; fix tracked in fix(sdk): address-sync no longer silently discards balance changes for post-snapshot addresses (Found-025) #3650) — rs-sdk address-sync silently discards platform-returned balance updates for addresses not in the pre-RPC pending_addresses snapshot #3649Checklist:
For repository code-owners and collaborators only
🤖 Co-authored by Claudius the Magnificent AI Agent