fix: don't fail settlement on empty reward_distribution_detailed - #86
Merged
Merged
Conversation
A fully overserviced claim settles to zero (settled_upokt == 0upokt) and the chain emits reward_distribution_detailed as an empty array. Since [] is truthy, _resolveSettlementParts still routes these claims through _buildSettlementFromDetailedDistribution, where both global-mint sums stay at zero and the invariant added in #78 throws. The throw propagates out of handleEventClaimSettled and kills the subql worker, halting the indexer: Error: Missing TLM_GLOBAL_MINT_DAO_REWARD_DISTRIBUTION in reward_distribution_detailed for event 852613-finalize_block-4249 Verified against mainnet block_results for height 852613: of 3033 EventClaimSettled, 43 carry an empty reward_distribution_detailed, and those are exactly the 43 with settled_upokt == 0upokt (no mismatch in either direction). Global inflation is enabled on that block, so the assertion was not detecting a misconfigured chain. The invariant is also wrong independently of overservicing: both global mint TLMs early-return when global_inflation_per_claim is zero, and tlm_global_mint skips the DAO append when its share truncates to zero. Record the global-mint inflation and reimbursement mints only when their amounts are non-zero instead of throwing. The base burn-equals-mint entry is unchanged, and effectiveBurn already resolves to "0" for these claims (it prefers settled_upokt), so a zero-settlement claim now yields zero burn and zero mint rows. Downstream is unaffected: get_mint_breakdown_between_dates SUMs over jsonb_array_elements(mints), where an absent zero row contributes the same as a present one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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
The indexer halts on mainnet block 852613 with an uncaught worker exception:
A fully overserviced claim settles to zero and the chain emits
reward_distribution_detailedas an empty array. Because[]is truthy,_resolveSettlementPartsstill routes the claim into_buildSettlementFromDetailedDistribution, both global-mint sums stay at zero, and the invariant added in #78 throws. The throw escapeshandleEventClaimSettledand kills the subql worker, so indexing stops.Root cause, verified against chain data
The offending event, from
block_resultsat height 852613:Across all 3033
EventClaimSettledin that block:reward_distribution_detailedsettled_upokt == "0upokt"Exactly 1:1 — an empty detailed distribution means a zero-settlement claim, nothing else. Global inflation is enabled on this block (the other 2990 claims all carry
TLM_GLOBAL_MINT_DAO_REWARD_DISTRIBUTIONandTLM_GLOBAL_MINT_REIMBURSEMENT_REQUEST_ESCROW_DAO_TRANSFER), so the assertion was not detecting a misconfigured chain.The invariant is unsound for a second reason as well: in poktroll,
tlm_global_mint.goearly-returns whenglobalInflationPerClaim == 0and skips the DAO append whendaoAmount.IsZero();tlm_reimbursement_requests.gohas the same zero-inflation early return. Absence of these entries is a valid chain state.Change
Drop both throws. Keep the base
TLM_RELAY_BURN_EQUALS_MINT_TOKENOMICS_CLAIM_DISTRIBUTION_MINTentry unconditionally, and append the global-mint inflation and reimbursement mints only when their amounts are non-zero.effectiveBurnalready resolves to"0"for these claims (_handleEventClaimSettledpreferssettled_upokt), so a zero-settlement claim now produces zero burn and zero mint rows rather than a dead worker.Downstream impact
None.
get_mint_breakdown_between_datesSUMs overjsonb_array_elements(t.mints), so an absent zero-amount row contributes exactly what a present one did.Recovery
Restart the indexer — nothing was written for 852613 before the throw, so it re-indexes the block cleanly. The pattern recurs on any block containing a fully overserviced claim.
Follow-up (not in this PR)
inflationAmountsums onlyTLM_GLOBAL_MINT_DAO_REWARD_DISTRIBUTION, but global mint also pays other recipients — block 852613 contains 606TLM_GLOBAL_MINT_SUPPLIER_SHAREHOLDER_REWARD_DISTRIBUTIONand 69TLM_GLOBAL_MINT_SOURCE_OWNER_REWARD_DISTRIBUTIONentries. Sinceget_mint_breakdown_between_datestreats opReason 5 as total inflation, reported inflation undercounts by that share. Pre-existing and separate from this crash.Test plan
get_mint_breakdown_between_datesover a range covering 852613 matches pre-incident values🤖 Generated with Claude Code