Skip to content

IIP-59: era-based distribution amendment (v2)#75

Draft
envestcc wants to merge 1 commit into
masterfrom
iip-59-era-distribution
Draft

IIP-59: era-based distribution amendment (v2)#75
envestcc wants to merge 1 commit into
masterfrom
iip-59-era-distribution

Conversation

@envestcc

Copy link
Copy Markdown
Member

Summary

Adds §8 amendment to IIP-59 superseding the per-epoch voter reward distribution cadence with a per-day (24-epoch) era model. Motivated by mainnet-scale measurement.

  • v1 assumption: ~40k voter credits per epoch, ~10-50 ms per epoch-close block
  • Measured mainnet reality (2026-07, via gRPC ReadStakingDataMethod_BUCKETS enumeration): 27,020 distinct voter addresses across 39,950 live buckets
  • Trie-backed per-voter cost: ~130 μs (2.5 μs SlotBucketReader + ~40 μs AddDepositForCompound + trie overhead)
  • Projected epoch-close block wall clock: ~3.4 s trie-backed — exceeds the 2.5 s post-Dardanelles block interval

The v1 spec is mechanism-correct but its per-epoch fan-out concentrates too much work into the epoch-close block. Chunking the drain (prototyped in iotex-core PR #4936) spreads the cost but does not reduce it and introduces snapshot-drift questions across the chunk window. This amendment adopts a per-era model instead:

  • Phase 1 — Accrue (every block, unchanged): block/epoch rewards accumulate to the per-delegate pending pool from §3.1
  • Phase 2 — Credit (once per era, chunked): drain pool → voter unclaimedBalance across ⌈voters / VoterBudgetPerBlock⌉ blocks
  • Phase 3 — Compound (background sweep + lazy on Claim): deferred compound of unclaimedBalance, no time constraint

Every other §3 mechanism — opt-in gate (§3.7), DelegateProfile rate source (§3.5), AutoDeposit compound routing (§3.6), pending pool (§3.1), orphan drain (§3.3) — is preserved. Only the firing cadence and log format change.

What's in the diff

Single-file amendment to iip-59.md, +223 / −2 lines:

  • Forward-pointer note at the top of §3 flagging the amendment
  • New §8 (Amendment v2 — Era-Based Distribution):
    • 8.1 motivation + measured cost
    • 8.2 three-phase decomposition
    • 8.3 per-era distribution cadence + EpochsPerRewardEra genesis param
    • 8.4 per-era SnapshotForEpochReward cadence
    • 8.5 state model additions (VoterRewardEraCursor + sentinel)
    • 8.6 chunked Phase 2 credit path (VoterBudgetPerBlock cap)
    • 8.7 EraVoterCredited log replacing DelegateDistributed
    • 8.8 Phase 3 hybrid compound (background sweep + lazy on Claim)
    • 8.9 first-era boundary handling
    • 8.10 genesis parameters table
    • 8.11 explicit list of superseded items in §3
    • 8.12 new test cases 17-22
    • 8.13 amended migration steps 2a / 2b
  • New Rationale block "Why Per-Era (Not Per-Epoch) Distribution" comparing three alternatives (per-voter optimization, chunking, cadence change)
  • Backwards Compatibility notes for the new state schema (VoterRewardEraCursor) and the new genesis fields (EpochsPerRewardEra / VoterBudgetPerBlock / CompoundBatchSize)

Key design invariants preserved

  1. No new fork gate. Reuses the existing !fCtx.NoVoterRewardDistribution gate from PR IIP-59: contract-backed rates, native compound, batched log, opt-in migration #74. EpochsPerRewardEra = 1 reproduces v1 per-epoch behavior for testnet debug.
  2. Snapshot determinism. The era voter-weight snapshot is written once at the era boundary and stable through all Phase 2 chunks — no drift window, no versioning.
  3. Phase 3 pause safety. unclaimedBalance is monotonic between Phase 2 credit and Phase 3 compound (or user Claim), so Phase 3 can pause arbitrarily without correctness impact.
  4. Log verifiability. EraVoterCredited carries chunk_seq + is_final + snapshotHash so off-chain aggregators can sum by (era_start_epoch, delegate) and independently verify against the frozen snapshot.

Trade-offs (called out in §8 + Rationale)

  • Reward accrual visibility drops from hourly to daily. Compound APY differs by <0.001% between per-hour and per-day compounding at 5%; UX-visible but economically neutral.
  • Voter staking mid-era earns from the following era, not the current one (Polkadot per-era semantics).
  • Off-chain Hermes filter must observe VoterRewardOnchainOptIn at era boundaries, not epoch boundaries — otherwise a voter is double-paid for up to 24 epochs. Guaranteed if the filter runs at every epoch (superset).

References

Test plan

  • Reviewer confirms §8 supersedes §3.2 / §3.4 / §3.7 correctly and that nothing in §3.5 / §3.6 / §3.7 (rate source / compound routing / opt-in) is unintentionally reworded
  • Reviewer confirms the new genesis parameters (§8.10) fit IoTeX's existing genesis schema shape
  • Reviewer confirms the EraVoterCredited log payload (§8.7) is reconstructible by the off-chain verifier tool tracked in iotex-core task #45 once implemented
  • Implementation PRs land in iotexproject/iotex-core per the sequence in the design doc (PRs A–F)

Adds §8 amendment superseding per-epoch distribution cadence with a
per-day (24-epoch) era model. Motivated by mainnet-scale measurement
(27,020 distinct voter addresses vs. the v1 assumption of ~40k credits
spread across delegates) — the v1 per-epoch drain projects to ~3.4s
trie-backed wall clock at the epoch-close block, exceeding the 2.5s
post-Dardanelles block interval.

§8 covers:
  8.1  motivation with measured cost
  8.2  three-phase decomposition (accrue / credit / compound)
  8.3  per-era distribution cadence + EpochsPerRewardEra genesis param
  8.4  per-era VoterWeightSnapshot cadence (no drift window)
  8.5  state model additions (VoterRewardEraCursor + sentinel)
  8.6  chunked Phase 2 credit path (VoterBudgetPerBlock cap)
  8.7  EraVoterCredited log replacing DelegateDistributed
  8.8  Phase 3 hybrid compound (background sweep + lazy on Claim)
  8.9  first-era boundary handling
  8.10 genesis parameters table
  8.11 explicit list of superseded items in §3
  8.12 new test cases 17-22
  8.13 amended migration steps

Also adds a Rationale block "Why Per-Era (Not Per-Epoch) Distribution"
comparing three alternatives and a Backwards Compatibility note on the
new state and genesis fields.

Mechanism-preserving amendment: opt-in gate (§3.7), rate source (§3.5),
compound routing (§3.6), pending pool (§3.1), and orphan drain (§3.3)
are unchanged. Only the firing cadence and log format change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant