fix: bulletin storage slot-account signer — eliminate mobile signing size errors#238
Open
EnderOfWorlds007 wants to merge 3 commits into
Open
fix: bulletin storage slot-account signer — eliminate mobile signing size errors#238EnderOfWorlds007 wants to merge 3 commits into
EnderOfWorlds007 wants to merge 3 commits into
Conversation
… PAPI-native signRaw(Payload) Removes the signPayload path (which sent 2 MB chunk calldata to mobile wallets, triggering "message too big" rejections). PAPI's getPolkadotSigner hashes payloads >256 bytes before calling the raw sign function, so mobile receives ≤32 bytes. The Payload tag tells Android to sign without the anti-phishing envelope. Removes RELAXED_SIGNED_EXTENSIONS wrapper, asHexString, coerceAssetId helpers, and the getPolkadotSignerFromPjs import (pjs-signer). Adds 3 anti-regression tests: signPayload-never-called, Bytes-tag routing, rejection error prefix.
…torageSigner to runStorageDeploy In phone mode, both `runDeploy` and `runDecentralize` now attempt to resolve the user's BulletIn slot-account signer via `getBulletinAllowanceSigner` before passing auth to `runStorageDeploy`. When the slot key is found, `storageSigner` + `storageSignerAddress` are injected into `bulletinDeployAuthOptions`; any resolution failure falls through silently so bulletin-deploy's pool path remains the fallback. `bulletinDeployAuthOptions` in `DeploySignerSetup` and `StorageDeployOptions.auth` are widened with an intersection type to carry the two new optional fields. bulletin-deploy 0.7.x ignores them at runtime; the routing becomes effective once the Task-3 version (feat/411-signin-impl) is published to npm. 3 new tests cover: slot signer injected in phone mode, skipped in dev mode, and failure swallowed with pool fallback intact.
Emit { kind: "signing", event: { label: "Approve Bulletin storage allowance" } }
before calling getBulletinAllowanceSigner in both deploy and decentralize runners,
so the TUI shows "check your phone" while the allocator is pending. Test updated.
Contributor
|
Dev build ready — try this branch: |
Contributor
E2E Test Pass · ❌ FAILTag:
Sentry traces: view spans for this run |
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
getPolkadotSignerFromPjs+session.signPayloadinsrc/utils/sessionSigner.tswith PAPI-nativegetPolkadotSigner+session.signRaw({ tag: "Payload" }).getBulletinAllowanceSignerinto phone-mode deploy and decentralize runners. Emits"Approve Bulletin storage allowance"signing event before allocation.StorageDeployOptions.authandbulletinDeployAuthOptionsto carrystorageSigner/storageSignerAddress.Depends on: paritytech/bulletin-deploy#806 (must merge first).
Bulletin Storage Slot-Account Signer
Date: 2026-06-02
Repos:
paritytech/bulletin-deploy(PR #791 branch) +paritytech/playground-cliStatus: Design — awaiting implementation
Problem
src/auth/vendor/sessionSigner.ts(bulletin-deploy) andsrc/utils/sessionSigner.ts(playground-cli) both use
getPolkadotSignerFromPjs+session.signPayload. The PJSadapter puts the full call data (~2 MB for a storage chunk) in the
methodfield andsends it to the mobile wallet. Android rejects it:
"Mobile signing failed: message too big".Confirmed in Sentry (7-day window): 2 live events from
paritytech/dApp-factory, domainpaseo-tip-jar01,chunk(nonce:0) subscription error: Mobile signing failed: message too big.Even with a patched signer, routing 30+ storage chunks through an interactive mobile
session is architecturally wrong. The slot-account model — one wallet dialog at login
(or lazily at first deploy), then local sr25519 signing for all uploads — is the correct
design for bulk Bulletin submissions. playground-cli already implements this in
src/utils/allowances/bulletin.tsfor its metadata-upload path; this design extends itto the main
runStorageDeploypath and mirrors the pattern in bulletin-deploy.Scope
Two repos change in lock-step because
DeployOptionsin bulletin-deploy is a breakinginterface for playground-cli.
bulletin-deploy
src/auth/vendor/sessionSigner.tsstorageSignerparametersrc/deploy.ts(DeployOptions,selectStorageReconnect)src/storage-signer.ts(new)src/commands/deploy.tssrc/telemetry.ts(PR #803 follow-up)playground-cli
src/utils/sessionSigner.tssrc/utils/deploy/run.ts,src/utils/decentralize/run.tsStorageDeployOptionswideningsrc/utils/deploy/storage.tsArchitecture
A — Session signer vendor update (both repos)
The upstream product-sdk
signer.tshas been rewritten. The old path:New path (mirrors current product-sdk
signer.tsexactly):The
Payloadtag tells Android to sign the bytes as-is (no<Bytes>…</Bytes>anti-phishing envelope), which avoids the
BadProoffailure that broke the previoussignRawattempt on old Android builds.The error string changes:
"Mobile signing failed:"→"Mobile signing rejected:".The
signer.message_too_largeclassifier insrc/telemetry.ts(PR #803) must bewidened:
B —
DeployOptions.storageSigner(bulletin-deploy)Add to
DeployOptions:Update
selectStorageReconnect— new priority:storageSigner > mnemonic > pool.The
signerfield is removed from storage routing entirely; it routes to DotNS only.This restores the architectural invariant documented at
deploy.ts:2309that the sign-inlift inadvertently broke.
The slot signer is Bulletin-only — it has nothing to do with the
ensureAuthorized/DotNS authorization machinery in
getSignerProvider. A newgetSlotSignerProvidercreates a Bulletin WS connection and returns
{ client, unsafeApi, signer, ss58 }withno authorization checks. Pool is always the final fallback; no deploy should fail because
of the Bulletin allowance path.
The reconnect thunk uses a committed
useSlotflag: once the slot signer fails on thefirst connection attempt, every subsequent reconnect uses pool. This prevents signer
drift across chunk uploads (nonce attribution would break if storage switched signers
mid-upload).
C — Slot signer reader + writer (bulletin-deploy
src/storage-signer.ts)Reads the product-sdk terminal allowance cache at
~/.polkadot-apps/{sanitize(DOT_DAPP_ID)}_AllowanceKeys.json(same format as
@parity/product-sdk-terminal'shost-signer.ts).All imports (
@polkadot-labs/hdkd,@polkadot-labs/hdkd-helpers,@polkadot-api/utils,polkadot-api/signer) are already direct dependencies on thefeat/411-signin-implbranch. No new deps.
src/storage-signer.tsalso needs a writer, because the vendoredallocations.tsintentionally does not persist slot keys ("the host stores them and uses them
transparently on subsequent calls" — its
AllocationOutcome.valueis typedunknownand never read). The CLI path must extract the key from the outcome and write it to the
product-sdk terminal cache format itself.
Add to
src/storage-signer.ts:(
dirnamecomes fromnode:path, already imported.)D — CLI wiring (bulletin-deploy
src/commands/deploy.ts)After
resolveSigner, if a session exists:Imports added to the deploy command:
requestResourceAllocationfromsrc/auth/index.ts(already exported, signature is(session: UserSession, productId: string, resources, onExisting) => Promise<AllocationOutcome[]>)extractBulletinSlotKey,writeBulletinSlotKeyfromsrc/storage-signer.ts(new)DOT_PRODUCT_IDfromsrc/auth-config.ts(already exported)Pool is always the final fallback. Any failure — declined, timeout, key not in outcome,
write error — is caught and swallowed; deploy continues with pool storage.
E — Slot signer resolution in playground-cli runners
resolveSignerSetupstays synchronous — no signature change. The slot signer resolutionhappens in the async deploy runners, which already have
env,ownerAddress(
userSigner.address), anduserSignerin scope.src/utils/deploy/run.tsandsrc/utils/decentralize/run.ts(phone mode):getBulletinAllowanceSignerhandles: cache miss →requestResourceAllocation(phonedialog) →
storeSlotAccountKeysFromOutcomes→ authorization check → re-allocate withIgnoreif not authorized. TheonEventsigning emission before the call drives theTUI's "check your phone" callout; it fires only when allocation is needed (the function
returns immediately from cache when the key exists).
Note: the
Increasere-allocation branch insidegetBulletinAllowanceSignerfires whenauthorized && remainingTransactions == 0. In practice Bulletin grants a largetransactions_allowance, so remaining stays positive for any authorized account — theIncreasepath is dead in practice. Leave the function unchanged; aligning the checkto
status.authorizedonly is a separate cleanup.src/utils/deploy/storage.ts—StorageDeployOptions.authwidened:DeploySignerSetup.bulletinDeployAuthOptionsinsignerMode.tssimilarly widens itsPickto include the two new fields.Data flow summary
bulletin-deploy CLI
playground-cli phone mode
Fallback chain (both paths):
storageSigner→mnemonic→ pool.signernever enters storage routing.Error handling
Pool is always the final fallback. No deploy should fail because of the Bulletin
allowance path.
readBulletinSlotSignerreturns null → poolgetSlotSignerProviderthrows (connection, not authorized, anything)selectStorageReconnect→ poolgetBulletinAllowanceSignerre-allocates withIgnore; if still fails → propagates to runner, which should catch and fall back to poolTesting
bulletin-deploy
src/storage-signer.ts: unit tests — (1) cache absent → null, (2) valid 32-bytekey → correct SS58, (3) valid 64-byte key → correct SS58, (4) corrupt JSON → null,
(5) missing
BulletInAllowanceentry → null.src/deploy.ts__selectStorageProviderModeForTest: update existing tests; addcases for
storageSignerpresent →"storageSigner", absent → existing"direct"/"pool"behaviour unchanged.src/auth/vendor/sessionSigner.ts: mirror the product-sdkhost-signer.tstests —(1)
signTxroutes throughsignRawwithPayloadtag, neversignPayload; (2)signBytesroutes throughsignRawwithBytestag; (3) error →"Mobile signing rejected:"prefix.playground-cli
src/utils/sessionSigner.ts: same three tests as bulletin-deploy vendor above.src/utils/deploy/signerMode.ts: existing snapshot tests unchanged (function stayssync, output shape unchanged for DotNS fields).
src/utils/deploy/run.ts: new test — phone mode with a pre-cached slot key callsgetBulletinAllowanceSignerand passesstorageSignertorunStorageDeploy; dev modedoes not call
getBulletinAllowanceSigner.Open items
product-sdk
signer.tsversion pin: confirm@parity/product-sdk-terminalonboth branches is at or above the version containing the
Payload-tag rewrite beforemerging. The old
signPayloadpath is removed in that version.storageSignerAddressderivation in playground-cli runner:getBulletinAllowanceSignerreturns aPolkadotSignerbut not the SS58. UsegetSlotAccountAddress(key)fromslotKeys.tsimmediately after reading the key.To avoid a double read, add a thin wrapper that returns both
{ signer, ss58 }, orcall
readSlotAccountKeyagain (cheap, no WS).AuthClient.getSessionSignercreates its own adapter: thegetSessionSigner()call in the CLI wiring tears down and recreates a terminal adapter. If
resolveSigneralready called it (to produce the DotNS signer), confirm whether a second call is
safe or whether the session handle from the first call can be threaded through instead.