Repository navigation
Conversation
Both are development instrumentation in the production schema, marked for removal in the redesign (docs/implementation/09-infrastructure.md §9.7). FoundType cost a write per argument of every event: the serializer saved the same id again for each one. A testnet genesis resync left 1.4M row versions for 403 type names, and closing each version scanned the whole table, 166 ms a time. Nothing has written Debug for some time. BREAKING CHANGE: the FoundType and Debug entities and their queries are removed. Neither the SDK nor the portal reads them.
Before v6, asset.Transfer names no instruction, and handleAssetTransfer took the block's first InstructionExecuted. In a block executing several instructions every transfer was filed under the first: testnet block 5,091,763 executed 27 and all 270 transfers went to one. asset.Transfer is emitted by unsafe_transfer, which only three paths reach (checked at v3.0.0, v4.1.0 and v5.4.0): settlement, which transfers an instruction's legs and then emits InstructionExecuted in the same dispatch, with only further transfers and CheckpointCreated between; asset.controller_transfer, followed by ControllerTransfer; and a capital distribution claim, followed by BenefitClaimed. A transfer's instruction is now the next InstructionExecuted in its phase, a controller transfer or claim has none, and anything else is recorded as an UnreadableValue anomaly. All 16,488 pre-v6 testnet transfers classify, none unexplained, and every settlement transfer is filed under its own instruction. Adding an affirmation's signer to an instruction's legs searched for the legs with getByFields, quadratic in a block of affirmations (testnet block 5,091,762 has 498). Instruction now records legCount, and the legs are read by id, instructionId/0 to legCount - 1, all at once. Fewer legs than that, or an affirmed instruction the index does not hold, is recorded as a MissingReferencedEntity anomaly.
AssetAgentHistory is append-only: every handler creates a row and none reads one back to change it, so updatedEvent always equalled createdEvent. It was missed when updatedEvent was dropped from the other append-only entities, and it still cost a non-null foreign key and its index on every row. BREAKING CHANGE: AssetAgentHistory.updatedEvent is removed. Select createdEvent instead.
For a portfolio holding the pair is the row's id, assetId/portfolioId, so a filter on both is already a point lookup, and portfolio alone has the index every relation gets. Under historical state each index is a GiST index maintained on every insert, on a table written for every asset movement. The same reasoning removed Nft's (asset, nftId) composite. The (asset, identity) composite stays: it serves one identity's holdings of one asset across its portfolios and accounts, the total the AssetHolder rollup has to agree with. Its docstring now says so, and that it has not been measured.
The transfer-manager helpers went when the pre-v5 transfer-manager path was removed. What is left parses compliance requirements and transfer compliance exemptions, so the file is named for that.
CorporateBallot.corporateAction was non-null and set from the ballot's own id without checking the action exists. attach_ballot names a corporate action created by an earlier extrinsic, so when that action is outside the index (an index started after it, or a missed CAInitiated) the ballot pointed at a row that is not there, which a non-null relation only fails on at query time. The relation is now nullable and set only when the action is found; otherwise it is left null and a MissingReferencedEntity anomaly is recorded, as Distribution.corporateAction already does.
propose schedules a PIP's expiry before it emits ProposalCreated, in every runtime from v3.0.0 to v8.1.2, so ExpiryScheduled arrives first, before the PIP exists. Its handler found no proposal, recorded a MissingReferencedEntity anomaly and dropped the expiry: on mainnet, every PIP proposed with an expiry, from PIP 0 at block 68,657. ProposalCreated now takes the expiry from the ExpiryScheduled earlier in its own extrinsic, and the separate handler is gone. A PIP whose expiry the scheduler refused emits ExpirySchedulingFailed instead, and still records none.
An instruction-less Transferred balance update is labelled with the name of the event that follows it. The name was cast to EventIdEnum unchecked, so an event the enum lacks reached the asset_transactions.event_id insert, failed the enum check, and halted indexing on that block. Map it through toEnum, as extractArgs does, so unknown names become Unknown. The same fix as alpha's 5c36f8b, whose test here expects the redesign's zero-padded instruction id.
The genesis config gives genesis and system identities CDD claims, issued by the governance committee and the CDD system identity, and no ClaimAdded announces them. The genesis seed created those identities but no claims, so the index lacked all ten on mainnet. When PIP 149 revoked one at block 20,842,777, the revocation found no claim and recorded an anomaly; the other nine are still on chain. The genesis handler now reads identity.claims at the genesis block and writes each claim through the same path as ClaimAdded, after the identities they are about. The full double-map scan helper moves to utils so the holdings seed and this one share it.
Plan 09 §9.10 proposes replacing the harvester-era event encoding, the positional eventArg columns and Extrinsic.paramsTxt with arguments built on toPrimitive() and an EventReference lookup. It is breaking for the SDK and the portal, so it is recorded as pending a decision, with the consumer changes listed in reference/consumer-queries.md §5.
…ent actions AssetAgentAction is the per-asset record of what an agent did, but five agent-permissioned asset calls were missing from it, so "who froze this holder, and when" had no answer there: - SetAccountFreeze and FrozenBalanceSet (8.1.1), which freeze a holder outright or partly; - ControllerTransferTo (8.1.1), a forced transfer to a named holder; - TickerLinkedToAsset, listed but commented out, and TickerUnlinkedFromAsset, never listed. Both require the agent's permission in every runtime from v7.0. Each is now recorded with its caller and asset. The holder and amount stay on the action's event.
|
This was referenced Oct 7, 2026
F-OBrien
added this pull request to stack #358
October 7, 2026 17:25
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.




Stack: #361 (review fixes) → #367 (resync fixes outside the ledger) → #368 (POLYX ledger resync fixes) → #369 (ledger split by era) → #365 (consumer requests)
Description
Fixes found by running PR 361 against testnet and mainnet, outside the POLYX ledger. It sits on #361. The ledger fixes are in #368.
Each commit is self-contained and its message records the chain evidence (blocks, specs, counts), so it reads best commit by commit.
Settlement and assets
6bc6e52Before v6,asset.Transfernames no instruction, so every transfer in a block was filed under its firstInstructionExecuted(testnet block 5,091,763: 27 instructions, 270 transfers, all filed under one). Each transfer now takes the nextInstructionExecutedin its phase. Adding an affirmation's signer to the legs was quadratic in a block of affirmations;Instruction.legCountlets the legs be read by id.52cf2b4An unrecognised event name following a transfer reached theevent_idenum column and halted indexing. It now maps throughtoEnumtoUnknown.63469ddCorporateBallot.corporateActionbecomes nullable and is set only when the action is indexed, matchingDistribution.corporateAction.Identities and governance
5912165The genesis config grants ten CDD claims that noClaimAddedannounces, so the index lacked all ten on mainnet. They are now seeded fromidentity.claimsat genesis.e3fe724proposeschedules a PIP's expiry beforeProposalCreated, so the expiry was always dropped (every mainnet PIP with an expiry).ProposalCreatednow takes it from the earlierExpiryScheduled.5121075AssetAgentActionrecordsSetAccountFreeze,FrozenBalanceSet,ControllerTransferTo,TickerLinkedToAssetandTickerUnlinkedFromAsset. These were missing from the agent-permissioned calls. Moved here from PR 365.Schema clean-up
8118c72RemovesFoundTypeandDebug(plan 09 §9.7).FoundTypewas rewritten once per event argument: 1.4M row versions for 403 names on a testnet resync.9039c64DropsupdatedEventfromAssetAgentHistory, which is append-only and was missed when the other append-only entities lost it.fcd7c4bDropsHolding's(portfolio, asset)composite index, which duplicates the row's id.67c62e5Renamesutils/transferManagers.tstocompliance.ts.Docs
3c77a95Plan 09 §9.10 proposes one canonical encoding for event and call arguments. It is breaking for the SDK and the portal, so it is recorded as pending a decision.Breaking Changes
FoundTypeandDebugentities removed. Neither the SDK nor the portal reads them.AssetAgentHistory.updatedEventremoved. UsecreatedEvent.CorporateBallot.corporateActionis nullable.The redesign already needs a fresh reindex; these come with it.
Verification
typecheck,test:unit,lint,check-handlers,check-strict-nullandbuildpass on this tip.JIRA Link
None.
Checklist