fix(dot init): bulletin allowance resilience + QrLogin setState warning#189
Merged
UtkarshBhardwaj007 merged 2 commits intoMay 19, 2026
Merged
Conversation
The mobile app (Polkadot Android NIGHTLY) submits the RFC-0010 `Resources::claim_long_term_storage` extrinsic on the People parachain and then waits 30 s for the authorization to propagate to Bulletin Chain. That wait is .logFailure()-wrapped — failures are swallowed and the slot key is returned regardless. The CLI then polls Bulletin via `checkAuthorization` from @parity/product-sdk-bulletin for 75 s; if propagation lags, the poll throws "Mobile returned Bulletin allowance key X, but it is not authorized on Bulletin yet" and `dot init` aborts before even running funding/mapping. Verified end-to-end against the polkadot-app-android-v2 source (`RealTransactionStorageSlotAllocator.kt:53-114`, AWAIT_BULLETIN_TIMEOUT = 30s, `.logFailure(...)` at the `awaitAllocationVisibleOnBulletIn` call site) and RFC-0010's "Bulletin submission — implicit allocation" flow. The host has no on-chain step to add here — RFC-0010 puts all the chain-side work on the mobile. The CLI's only correct move is to be resilient to the propagation lag. Four fixes in this PR, plus a React warning from #188: 1. `BULLETIN_AUTHORIZATION_URL` + `bulletinAuthorizationHelp(slot)` in `src/config.ts` and `src/utils/allowances/bulletin.ts`. Both `waitForBulletinSlotAuthorization`'s timeout error and the cached-key-not-authorized error now print the slot SS58 + the manual-faucet URL (`https://paritytech.github.io/polkadot-bulletin-chain/authorizations`). Pattern lifted from PR #186. 2. `requestAndStoreBulletinAllowanceSigner` now persists the slot key + marker BEFORE the propagation wait. A 75 s timeout no longer throws away a perfectly valid key the mobile derived from `mnemonic + //allowance//bulletin//<productId>` — the key will still be valid the moment the chain catches up. 3. `AccountSetup` makes a Bulletin propagation timeout a SOFT failure rather than aborting `dot init`. The row shows the help string + slot SS58; funding + Revive auto-map mapping still run because they depend on the product account on Asset Hub, not on Bulletin authorization. The final `setup complete some account setup steps failed` warning surfaces correctly. 4. `storeSlotAccountKeysFromOutcomes` is now a single read-modify-write so two slot keys returned in one `requestResourceAllocation` call (e.g. `BulletInAllowance` + `StatementStoreAllowance`) can't race-clobber each other. The previous `Promise.all(...storeSlotAccountKey)` had each call load the JSON, mutate one resource, save the JSON; interleaved writes would drop the second sibling's key. Also fixes a React "Cannot update a component while rendering a different component" warning introduced in #188 (the account- derivation PR). `QrLogin` was calling `onDone(...)` from inside a `setStatus(updater)` callback — which runs during React's render phase, so the parent's `setAddresses` / `setAuthResolved` triggered mid-render of QrLogin. Now snapshots the resolved `SessionAddresses` in a `useRef` inside the `onStatus` callback and calls `onDone` after the promise resolves, outside any updater. Why this slipped past CI: `vitest.config.ts` only picks up `*.test.ts`, not `*.tsx`, so React-strict-mode warnings never fire in the test suite. Tests: 538 pass + 1 skipped (was 536). Two new regression tests: the help helper formats SS58 + URL correctly, and `storeSlotAccountKeysFromOutcomes` preserves sibling keys.
Contributor
|
Dev build ready — try this branch: |
Contributor
E2E Test Pass · ✅ PASSTag:
Sentry traces: view spans for this run |
- Move `bulletinAuthorizationUrl` into `ChainConfig` so the Summit devnet / mainnet swap is a single-config-row change (was a top-level constant that violated the "all chain URLs live in CONFIGS" CLAUDE.md invariant). Populated for paseo-next-v2; `null` on envs without a public faucet. - `bulletinAuthorizationHelp(slot, url?)` reads the active env's `bulletinAuthorizationUrl` by default; renders a generic "propagation pending" message when no faucet is configured. - Fix misleading `dot init` soft-failure row copy: it was "approve on your Polkadot mobile app…" — but the user has just successfully approved, the failure is People→Bulletin propagation, not a pending mobile prompt. Now reads "Bulletin authorization pending" and the error line carries the full diagnostic via `describe(waitErr)`. - Drop the dead-code `waitErr instanceof Error ? msg : help(...)` branch — `waitForBulletinSlotAuthorization` always throws Error. - Single timestamp per `storeSlotAccountKeysFromOutcomes` batch instead of one per slot (these come from the same `requestResourceAllocation` round-trip, semantically one cohort). - Add the persist-before-wait invariant to CLAUDE.md under "Allowances / session" with the upstream root cause callout (XCM-relayed Bulletin allocation can fail silently as `LongTermStorageAllocationFailed`, same class as Mobile PR #582's PGAS fix not applied to storage). - Bulletin help tests cover both explicit-URL and no-URL branches and pin the literal faucet path so a future config rename can't silently produce a wrong user-facing URL. CLAUDE.md is 39,990 chars (back under the 40k Claude Code warning). 540 tests pass, format + license clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two issues observed in
dot init v0.22.3:Bulletin allowance key returned but not authorizedfailure followed bysetup complete (some account setup steps failed).Cannot update a component (InitScreen) while rendering a different component (QrLogin).This PR fixes both, plus a related slot-key-clobber race surfaced during the investigation.
Root cause for (1) — verified across mobile + RFC
Cross-checked against
polkadot-app-android-v2,triangle-js-sdks/host-papp,polkadot-desktop,w3s-conference-app, RFC-0010, and PR #186.Resources::claim_long_term_storage(period, counter, account_id)on the People parachain (not Bulletin) —polkadot-app-android-v2/feature/transaction-storage/impl/.../RealTransactionStorageSlotAllocator.kt:53-114. Signer isTransactionSignerSource.Noneplus a Bandersnatch ring-VRF People-membership proof transaction extension. The Bulletin-side authorization propagates from People via on-chain runtime mechanics.knownChains.bulletIn. That wait is wrapped in.logFailure(...)— failures are swallowed, and the slot key is returned to the host regardless.checkAuthorizationfor 75 s. If People→Bulletin propagation lags, the poll times out and the previous code aborted the whole init flow.There is no host-side on-chain step the CLI is missing — RFC-0010 places all chain work on the mobile. The only correct host behaviour is to be resilient to the propagation lag.
What this PR changes
a.
BULLETIN_AUTHORIZATION_URL+bulletinAuthorizationHelp(slotSS58)(config.ts, bulletin.ts). The timeout error now readsMobile returned Bulletin allowance key <slotSS58>, but it is not authorized on Bulletin yet. Open <faucet URL> and authorize that address, then re-run \dot init`.` Same hint on the cached-key-not-authorized branch. Pattern lifted from PR #186.b. Persist the slot key BEFORE the propagation wait (
requestAndStoreBulletinAllowanceSigner). A 75 s timeout no longer throws away a valid mobile-derived key — next run /dot deploywill see the cached key and only re-poll Bulletin.c. Non-fatal Bulletin timeout in
AccountSetup. The slot key + marker get persisted regardless; the Bulletin row shows the help string; funding +Revive::map_accountcontinue to run because they depend on Asset Hub, not Bulletin. Thesetup complete some account setup steps failedsummary surfaces correctly.d. Batched
storeSlotAccountKeysFromOutcomes. WasPromise.all([...storeSlotAccountKey])where each call did its own read-modify-write ofallowance-keys.json— interleaved writes would drop sibling slot keys (BulletInAllowance+StatementStoreAllowancereturned in the same call). Now a single load → mutate → save.QrLogin setState warning
Introduced in #188. The code did:
```tsx
waitForLogin(login, setStatus).then(() => {
setStatus((current) => {
onDone(current.step === "success" ? current.addresses : null);
return current;
});
});
```
The
setStatusupdater runs during React's render phase, soonDone(...)calling the parent'ssetAddresses/setAuthResolvedtriggered a "Cannot update a component while rendering a different component" warning.Fix: snapshot the resolved addresses in a
useRefinside theonStatuscallback, then callonDoneoutside any updater.Why CI didn't catch it.
vitest.config.tsonly picks up*.test.ts, not*.tsx, so React-strict-mode warnings never fire in the suite.What this PR does NOT do
LongTermStorageAllocationFailedis a mobile + chain issue. A separate root-cause investigation is running.//Alicefunding, no host-sideBulletin::authorizeextrinsic — RFC-0010 doesn't allow that.Test plan
pnpm format:check(145 files)pnpm lint:license(172/172 files)pnpm test— 538 passed, 1 skipped (was 536). Added:bulletinAuthorizationHelpreturns SS58 + URL + "re-run dot init";storeSlotAccountKeysFromOutcomespreserves siblings.dot initpost-merge: confirm Bulletin row shows warning + faucet URL, funding/mapping still completes, and no React warning at top of output.