Uh oh!
There was an error while loading. Please reload this page.
feat(sdk-ffi): expose the current epoch; fix getCurrentEpoch and the proposed-blocks range proof - #4453
Conversation
`dash_sdk_system_get_current_epoch` returns the newest started epoch via `ExtendedEpochInfo::fetch_current` (the proved two-query probe), as one JSON object with the same keys `dash_sdk_system_get_epochs_info` emits per epoch. The Swift `SDK.getCurrentEpoch()` used `getEpochsInfo(start: nil, count: 1, ascending: true)`, which is epoch 0 — not the current epoch — and an unbounded descending proved query is rejected by the proof verifier, so no existing bridge could answer the question. It now calls the new FFI. Consumer: dashwallet-ios home-screen "blocks proposed this epoch" card. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Warning Review limit reached
Next review available in:37 minutes Limit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
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 |
ℹ️ Review skipped (commit 0eaceda) |
Uh oh!
There was an error while loading. Please reload this page.
…ange with it Proved proposer queries must name an explicit epoch — the proof verifier rejects "current" (`proved proposer queries require an explicit epoch`), so every range scan failed silently and the card/rows never populated. The service now resolves the current epoch via `getCurrentEpoch()` first (a hard dependency on dashpay/platform#4453) and passes its index to every page. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…his epoch (#1036) * feat(wallet): home card with the blocks your evonodes proposed this epoch Adds a home-feed card (shown only when the wallet has active evonodes) with the number of Platform blocks they have proposed in the current epoch, "Epoch N · started <relative>", tapping into the masternode list, which now shows the per-evonode count on each row. Privacy: the wallet never names its own evonodes to DAPI. Instead of the by-ids query (whose request would list exactly our nodes), `EvonodeEpochBlocksService` pages the whole epoch's proposer tallies with `getEvonodesProposedEpochBlocksByRange` — a request with no node ids, identical for every wallet — and joins against the owned set on-device. A wallet without evonodes issues no query at all. Refresh: sync done, app foreground, wallet/network switch, and screen appear (throttled to 5 min). The epoch label uses the SDK's new `getCurrentEpoch()` (dashpay/platform#4453 — the old one returned epoch 0). Also factors the Masternodes hosting wrapper into `MasternodesScreen.hostingController(popFrom:)`, shared by the Governance menu and the home card. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(wallet): evonode epoch-blocks review follow-ups - Empty owned set returns without touching the SDK (no query at all). - A scan still paging at the page guard throws `pageLimitReached` instead of reporting a truncated tally; callers keep their last value. - Generation token owns the in-flight fetch (home + masternode list): a superseded fetch unwinding late can no longer clear or publish over its replacement. - Masternode list refreshes its tallies on the same events as the home card (sync done, foreground, wallet/network switch). - Locale-formatted per-row counts; log line wrapped under 180 chars. - Failed fetches retry after 30 s on routine triggers (not the 5-min success throttle) and log why the card is hidden. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(wallet): resolve the current epoch first and query the proposer range with it Proved proposer queries must name an explicit epoch — the proof verifier rejects "current" (`proved proposer queries require an explicit epoch`), so every range scan failed silently and the card/rows never populated. The service now resolves the current epoch via `getCurrentEpoch()` first (a hard dependency on dashpay/platform#4453) and passes its index to every page. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(wallet): shared EvonodeEpochBlocksMonitor owns the epoch-blocks refresh policy CodeRabbit follow-ups, resolved by centralising the policy instead of duplicating it in two view models: - `EvonodeEpochBlocksMonitor` (shared; one scan serves every screen, seam via `EvonodeEpochBlocksProviding` + injectable owned-evonode source) serialises scans: at most one in flight, a forced refresh requested while one runs is queued behind it (never dropped), routine triggers are throttled (5 min after success, 30 s after failure), and a wallet/network reset cancels the running scan, drops the stale value and queues a forced one. Failure state is only recorded by the live generation. - The service forwards the caller's cancellation into its detached scan (`withTaskCancellationHandler` + stop flag checked per page) and parses counts through their decimal text so negatives are rejected. - Home and Masternodes view models mirror the monitor and only call `refresh()` on appear; the list therefore gets the same throttle and lifecycle triggers as the card. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(wallet): Nodes shortcut with epoch day and blocks proposed, instead of the home card Replaces the home-feed card with a "Nodes" shortcut in the customizable shortcut bar (long-press to switch), per the owner's direction: - `ShortcutActionType.nodes`, offered in the customization picker — and swapped into the default bar's last slot — only while the wallet has active evonodes (same runtime gating as CrowdNode / Switch Wallet). - `NodesShortcutIcon`: a live 46 pt disc — the epoch day (0–9, recomputed every minute from the epoch start) large on top, a divider, and the blocks proposed this epoch ("99+" cap) on the bottom strip; "–" until the first tally; accessibility label carries both numbers. Reads the shared `EvonodeEpochBlocksMonitor`. - Tap opens the Masternodes list (per-row counts unchanged). - Home no longer mirrors the tallies; it only nudges the monitor on appear. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(wallet): Nodes shortcut is opt-in only; gate saved Nodes; reload list on context changes - Defaults unchanged: Nodes is offered in the long-press picker for evonode owners and never placed automatically (owner's direction). - A persisted Nodes shortcut degrades to Spend / the faucet while the active wallet runs no evonodes (e.g. after a wallet switch); the saved config is untouched and it returns with an evonode wallet. - `EvonodeEpochBlocksMonitor.contextVersion` bumps on sync-done and wallet/network changes; the Masternodes list reloads itself (and its ownership indexes) on it while visible. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(wallet): Nodes icon as epoch ring + badge, coloured by evonode health - Icon redesign (design B): the rim is an epoch-progress ring, the epoch day sits large in the centre, and a white badge on the bottom edge carries the blocks proposed this epoch. - Health colouring: blue when every evonode is proposing; yellow when any evonode hasn't proposed a block in the last 2 days; red when we're on epoch day 4+ and an evonode still has no block this epoch. - Platform only reports per-epoch totals, so recency is tracked locally: `EvonodeProposalActivity` folds every successful tally (per node: last observed increase, first observation, epoch-aware) and is persisted per network; the monitor publishes it and the icon evaluates `EvonodeHealth` every minute. Accessibility label names the condition. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Brings the branch up to date with upstream after #4451 (masternode credit withdrawals), #4452, #4453, #4456, and #4461 landed on v4.2-dev. One conflict, in packages/rs-platform-wallet/src/wallet/core/mod.rs: a module-registration collision where this branch adds 'pub mod spend_observer;' and upstream adds 'pub(crate) use sign_message::is_signable_funding_account;' at the same spot. Resolved as the union — both lines kept, no semantic overlap. Auto-merged overlaps verified by hand: both error.rs files and DashSdkError.kt gained disjoint additions (upstream's MasternodeWithdrawalUnconfirmed / FFI code 42 alongside this branch's StaleReservation reusing code 34 — codes distinct, both mapping arms present). generation.rs (the broadcast-fence redesign) was touched by this branch only. Verified: cargo check -p platform-wallet -p platform-wallet-ffi clean; cargo test -p platform-wallet wallet::core::generation — 15/15 passed, including the settle-boundary and handoff tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Brings the shielded-invite branch up to date with upstream v4.2-dev (#4451 masternode credit withdrawals, #4452, #4453, #4456, #4461). One conflict, in rs-platform-wallet/src/wallet/shielded/operations.rs: upstream #4451 moved carries_consensus_rejection() and broadcast_definitely_failed() out of operations.rs into the new shared crate::broadcast_outcome module (so masternode withdrawals can reuse them), while this branch had inserted its one-time-key claim machinery (NullifierSpentStatus, claim-evidence resolution) directly after those functions. Resolved by dropping the now-local duplicate of broadcast_definitely_failed() — its body is byte-identical to the moved copy, and the file already imports both helpers from crate::broadcast_outcome via upstream's auto-merged use line — and keeping this branch's one-time-key claim block in place. No semantic changes to either side. Verified: cargo check -p platform-wallet -p platform-wallet-ffi -p rs-unified-sdk-jni clean; cargo test -p platform-wallet --features shielded wallet::shielded = 205 passed, 0 failed (includes the one_time_claim_evidence and note_selection suites). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
New
dash_sdk_system_get_current_epoch(sdk)in rs-sdk-ffi: the newest started epoch viaExtendedEpochInfo::fetch_current(the proved two-query probe), returned as one JSON object with the same keysdash_sdk_system_get_epochs_infoemits per epoch (index,first_block_time,first_block_height,first_core_block_height,fee_multiplier_permille,protocol_version).NoDatawhen Platform has no epoch yet.Swift
SDK.getCurrentEpoch()now calls it. The previous implementation usedgetEpochsInfo(start: nil, count: 1, ascending: true), which perEpochQuerysemantics is epoch 0, not the current epoch — and an unbounded descending proved query is rejected by the proof verifier, so no existing bridge could answer "which epoch is it now".dash_sdk_evonode_get_proposed_epoch_blocks_by_rangenow carries itslimitin the request. It used to sendlimit: None, so Drive built the proof for its default page while the verifier re-derived a no-limit query from the request — every proved call failed withProof is missing data for query range … KVHash(seen on mainnet from the iOS wallet).0⇒ Drive's default page.Consumer: dashwallet-ios home-screen "blocks proposed this epoch" card (dashpay/dashwallet-ios#1036).
Test plan
cargo test -p rs-sdk-ffi --lib -- current_epoch proposed_epoch_blocks,cargo clippy -p rs-sdk-ffi --all-targets -- -D warnings,cargo fmt./build_ios.sh --target sim(xcframework + SwiftExampleApp, warnings-as-errors)🤖 Generated with Claude Code