Skip to content

Epoch and NewEpoch transition systems for Dijkstra

Modelled on the Conway.Conformance.Epoch module, adapted for Dijkstra:

  • Deposits live in CertState (not UTxOState)
  • SNAP and POOLREAP operate on CertState and Acnt rather than UTxOState and CertState.
  • govAction deposit returns are taken from GState.deposits.
{-# OPTIONS --safe #-}

open import Ledger.Dijkstra.Specification.Abstract
open import Ledger.Dijkstra.Specification.Transaction

module Ledger.Dijkstra.Specification.Epoch
  (txs : TransactionStructure) (open TransactionStructure txs)
  (abs : AbstractFunctions txs) (open AbstractFunctions abs)
  where

import Data.Integer as 
open import Data.Integer using () renaming (+_ to pos)
open import Data.Integer.Properties         using (module ≤-Reasoning; +-mono-≤; neg-mono-≤; +-identityˡ)
                                            renaming (nonNegative⁻¹ to nonNegative⁻¹ℤ)
open import Data.Integer.Tactic.RingSolver  using (solve-∀)
open import Data.Rational                   using (; floor; _*_; _÷_; _/_; _⊓_; _≟_; ≢-nonZero)
open import Data.Rational.Literals          using (number; fromℤ)
open import Data.Rational.Properties        using (nonNegative⁻¹; pos⇒nonNeg; ⊓-glb)

open import stdlib.Data.Rational.Properties using (0≤⇒0≤floor; ÷-0≤⇒0≤; fromℕ-0≤; *-0≤⇒0≤; fromℤ-0≤)


open import Ledger.Prelude hiding (iterate; _/_; _*_; _⊓_; _≟_; ≢-nonZero)
open import Ledger.Prelude.Numeric.UnitInterval using (fromUnitInterval; UnitInterval-*-0≤)

open import Data.Nat.Properties using (+-0-monoid; +-0-commutativeMonoid)
open import Data.List using (filter)

open import Agda.Builtin.FromNat
open import Data.Nat.GeneralisedArithmetic using (iterate)

open import Data.Maybe                      using (fromMaybe)

open import Ledger.Dijkstra.Specification.Certs govStructure
open import Ledger.Dijkstra.Specification.Enact govStructure
open import Ledger.Dijkstra.Specification.Gov govStructure
open import Ledger.Dijkstra.Specification.Ledger txs abs
open import Ledger.Dijkstra.Specification.PoolReap txs abs
open import Ledger.Dijkstra.Specification.Ratify govStructure
open import Ledger.Dijkstra.Specification.Rewards txs abs
open import Ledger.Dijkstra.Specification.Utxo txs abs

open Number number renaming (fromNat to fromℕ)
getOrphans : EnactState  GovState  GovState
getOrphans es govSt = proj₁ $ iterate step ([] , govSt) (length govSt)
  where
    step : GovState × GovState  GovState × GovState
    step (orps , govSt) =
      let
        isOrphan? a prev = ¬? (hasParent? es govSt a prev)
        (orps' , govSt') = partition
           (_ , record {action = a ; prevAction = prev})  isOrphan? (a .gaType) prev)
          govSt
      in
        (orps ++ orps' , govSt')

getStakeCred : TxOut  Maybe Credential
getStakeCred (a , _ , _ , _) = stakeCred a

open GovActionState using (returnAddr)
-- open RewardAddress using (stake)

PoolDelegatedStake : Type
PoolDelegatedStake = KeyHash  Coin

record EpochState : Type where
  constructor ⟦_,_,_,_,_⟧ᵉ'
  field
    acnt       : Acnt
    ss         : Snapshots
    ls         : LedgerState
    es         : EnactState
    fut        : RatifyState
record HasEpochState {a} (A : Type a) : Type a where
  field EpochStateOf : A  EpochState
open HasEpochState ⦃...⦄ public

instance
  HasAccount-EpochState : HasAccount EpochState
  HasAccount-EpochState .AccountOf = EpochState.acnt

  HasSnapshots-EpochState : HasSnapshots EpochState
  HasSnapshots-EpochState .SnapshotsOf = EpochState.ss

  HasLedgerState-EpochState : HasLedgerState EpochState
  HasLedgerState-EpochState .LedgerStateOf = EpochState.ls

  HasGovState-EpochState : HasGovState EpochState
  HasGovState-EpochState .GovStateOf = GovStateOf  LedgerStateOf

  HasEnactState-EpochState : HasEnactState EpochState
  HasEnactState-EpochState .EnactStateOf = EpochState.es

  HasDReps-EpochState : HasDReps EpochState
  HasDReps-EpochState .DRepsOf = DRepsOf  CertStateOf  LedgerStateOf

  HasTreasury-EpochState : HasTreasury EpochState
  HasTreasury-EpochState .TreasuryOf = Acnt.treasury  EpochState.acnt

  HasReserves-EpochState : HasReserves EpochState
  HasReserves-EpochState .ReservesOf = Acnt.reserves  EpochState.acnt

  HasPParams-EpochState : HasPParams EpochState
  HasPParams-EpochState .PParamsOf = PParamsOf  EnactStateOf

  HasRatifyState-EpochState : HasRatifyState EpochState
  HasRatifyState-EpochState .RatifyStateOf = EpochState.fut

  HasPState-EpochState : HasPState EpochState
  HasPState-EpochState .PStateOf = PStateOf  CertStateOf  LedgerStateOf

  HasRetiring-EpochState : HasRetiring EpochState
  HasRetiring-EpochState .RetiringOf = RetiringOf  PStateOf
record NewEpochState : Type where
  field
    lastEpoch   : Epoch
    bprev       : BlocksMade
    bcur        : BlocksMade
    epochState  : EpochState
    ru          : Maybe RewardUpdate
    pd          : PoolDelegatedStake
record HasNewEpochState {a} (A : Type a) : Type a where
  field NewEpochStateOf : A  NewEpochState
open HasNewEpochState ⦃...⦄ public

record HasLastEpoch {a} (A : Type a) : Type a where
  field LastEpochOf : A  Epoch
open HasLastEpoch ⦃...⦄ public


instance
  HasLastEpoch-NewEpochState : HasLastEpoch NewEpochState
  HasLastEpoch-NewEpochState .LastEpochOf = NewEpochState.lastEpoch

  HasEpochState-NewEpochState : HasEpochState NewEpochState
  HasEpochState-NewEpochState .EpochStateOf = NewEpochState.epochState

  HasEnactState-NewEpochState : HasEnactState NewEpochState
  HasEnactState-NewEpochState .EnactStateOf = EnactStateOf  EpochStateOf

  Hastreasury-NewEpochState : HasTreasury NewEpochState
  Hastreasury-NewEpochState .TreasuryOf = TreasuryOf  EpochStateOf

  HasLedgerState-NewEpochState : HasLedgerState NewEpochState
  HasLedgerState-NewEpochState .LedgerStateOf = LedgerStateOf  EpochStateOf

  HasGovState-NewEpochState : HasGovState NewEpochState
  HasGovState-NewEpochState .GovStateOf = GovStateOf  LedgerStateOf

  HasCertState-NewEpochState : HasCertState NewEpochState
  HasCertState-NewEpochState .CertStateOf = CertStateOf  LedgerStateOf

  HasDReps-NewEpochState : HasDReps NewEpochState
  HasDReps-NewEpochState .DRepsOf = DRepsOf  CertStateOf

  HasRewards-NewEpochState : HasRewards NewEpochState
  HasRewards-NewEpochState .RewardsOf = RewardsOf  CertStateOf

  HasPParams-NewEpochState : HasPParams NewEpochState
  HasPParams-NewEpochState .PParamsOf = PParamsOf  EpochStateOf

  unquoteDecl HasCast-EpochState HasCast-NewEpochState = derive-HasCast
    ( (quote EpochState     , HasCast-EpochState)
     [ (quote NewEpochState  , HasCast-NewEpochState)])

opaque
  createRUpd :   BlocksMade  EpochState  Coin  RewardUpdate
  createRUpd slotsPerEpoch b es total =
    record  { Δt = Δt₁
            ; Δr = 0 - Δr₁ + Δr₂
            ; Δf = 0 - pos feeSS
            ; rs = rs
            ; flowConservation = flowConservation
            ; Δt-nonnegative = Δt-nonneg
            ; Δf-nonpositive = Δf-nonpos
            }
    where
      prevPp : PParams
      prevPp = PParamsOf es

      reserves : Reserves
      reserves = ReservesOf es

      pstakego : Snapshot
      pstakego = (SnapshotsOf es) .Snapshots.go

      feeSS : Fees
      feeSS = FeesOf (SnapshotsOf es)

      stake : Stake
      stake = StakeOf pstakego

      delegs : StakeDelegs
      delegs = StakeDelegsOf pstakego

      poolParams : Pools
      poolParams = PoolsOf pstakego

      blocksMade : 
      blocksMade = ∑[ m  b ] m

      ρ η τ : 
      ρ = fromUnitInterval (prevPp .PParams.monetaryExpansion)
      η = fromℕ blocksMade ÷₀ (fromℕ slotsPerEpoch * ActiveSlotCoeff)
      τ = fromUnitInterval (prevPp .PParams.treasuryCut)

      Δr₁ rewardPot Δt₁ R : 
      Δr₁ = floor (1  η * ρ * fromℕ reserves)
      rewardPot = pos feeSS + Δr₁
      Δt₁ = floor (fromℤ rewardPot * τ)
      R = rewardPot - Δt₁

      circulation : Coin
      circulation = total - reserves

      rs : Rewards
      rs = reward prevPp b (posPart R) poolParams stake delegs circulation

      Δr₂ : 
      Δr₂ = R - pos (∑[ c  rs ] c)

      -- Proofs
      -- Note: Overloading of + and - seems to interfere with the ring solver.
      lemmaFlow :  (t₁ r₁ f z : )
         (t₁ ℤ.+ (0 ℤ.- r₁ ℤ.+ ((f ℤ.+ r₁ ℤ.- t₁) ℤ.- z)) ℤ.+ (0 ℤ.- f) ℤ.+ z)  0
      lemmaFlow = solve-∀
      flowConservation :
        let t₁ = Δt₁
            r₁ = Δr₁
            f  = pos feeSS
            z  = pos (∑[ c  rs ] c)
         in
            (t₁ ℤ.+ (0 ℤ.- r₁ ℤ.+ ((f ℤ.+ r₁ ℤ.- t₁) ℤ.- z)) ℤ.+ (0 ℤ.- f) ℤ.+ z)  0
      flowConservation = lemmaFlow Δt₁ Δr₁ (pos feeSS) (pos (∑[ c  rs ] c))

      ÷₀-0≤⇒0≤ :  (x y : )  0  x  0  y  0  (x ÷₀ y)
      ÷₀-0≤⇒0≤ x y 0≤x 0≤y with y  0
      ... | (yes y≡0) = nonNegative⁻¹ 0
      ... | (no y≢0)  = ÷-0≤⇒0≤ x y {{≢-nonZero y≢0}} 0≤x 0≤y

      η-nonneg : 0  η
      η-nonneg = ÷₀-0≤⇒0≤ _ _ (fromℕ-0≤ blocksMade)
        (*-0≤⇒0≤ _ _
          (fromℕ-0≤ slotsPerEpoch)
          (nonNegative⁻¹ ActiveSlotCoeff {{pos⇒nonNeg ActiveSlotCoeff}}))

      min1η-nonneg : 0  1  η
      min1η-nonneg = ⊓-glb (nonNegative⁻¹ 1) η-nonneg

      Δr₁-nonneg : 0  Δr₁
      Δr₁-nonneg = 0≤⇒0≤floor _
        (*-0≤⇒0≤ (1  η * ρ) (fromℕ reserves)
          (UnitInterval-*-0≤ (1  η) (prevPp .PParams.monetaryExpansion) min1η-nonneg)
          (fromℕ-0≤ reserves))

      rewardPot-nonneg : 0  rewardPot
      rewardPot-nonneg = +-mono-≤ (nonNegative⁻¹ℤ (pos feeSS)) Δr₁-nonneg

      Δt-nonneg : 0  Δt₁
      Δt-nonneg = 0≤⇒0≤floor _
        (UnitInterval-*-0≤ (fromℤ rewardPot) (prevPp .PParams.treasuryCut)
          (fromℤ-0≤ rewardPot rewardPot-nonneg))

      Δf-nonpos : (0 - pos feeSS)  0
      Δf-nonpos = begin
          0 - pos feeSS ≡⟨ +-identityˡ _ 
          ℤ.- pos feeSS ≤⟨ neg-mono-≤ (ℤ.+≤+ z≤n) 
          0             
        where open ≤-Reasoning

open RewardAddress using (stake)
applyRUpd : RewardUpdate  EpochState  EpochState
applyRUpd rewardUpdate
  $\begin{pmatrix} \begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#10282}{\htmlId{10282}{\htmlClass{Bound}{\text{treasury}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10293}{\htmlId{10293}{\htmlClass{Bound}{\text{reserves}}}}\, \end{pmatrix} \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10307}{\htmlId{10307}{\htmlClass{Bound}{\text{ss}}}}\, \\ \begin{pmatrix} \begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#10316}{\htmlId{10316}{\htmlClass{Bound}{\text{utxo}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10323}{\htmlId{10323}{\htmlClass{Bound}{\text{fees}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10330}{\htmlId{10330}{\htmlClass{Bound}{\text{donations}}}}\, \end{pmatrix} \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10345}{\htmlId{10345}{\htmlClass{Bound}{\text{govSt}}}}\, \\ \begin{pmatrix} \begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#10357}{\htmlId{10357}{\htmlClass{Bound}{\text{voteDelegs}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10370}{\htmlId{10370}{\htmlClass{Bound}{\text{stakeDelegs}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10384}{\htmlId{10384}{\htmlClass{Bound}{\text{rewards}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10394}{\htmlId{10394}{\htmlClass{Bound}{\text{deposits}}}}\, \end{pmatrix} \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10408}{\htmlId{10408}{\htmlClass{Bound}{\text{pState}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10417}{\htmlId{10417}{\htmlClass{Bound}{\text{gState}}}}\, \end{pmatrix} \end{pmatrix} \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10433}{\htmlId{10433}{\htmlClass{Bound}{\text{es}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10438}{\htmlId{10438}{\htmlClass{Bound}{\text{fut}}}}\, \end{pmatrix}$ = $\begin{pmatrix}  \begin{pmatrix} \,\href{Prelude.html#3404}{\htmlId{10453}{\htmlClass{Function}{\text{posPart}}}}\, \,\htmlId{10461}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Dijkstra.Specification.Epoch.html#966}{\htmlId{10462}{\htmlClass{InductiveConstructor}{\text{pos}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#10282}{\htmlId{10466}{\htmlClass{Bound}{\text{treasury}}}}\, \,\href{Class.HasAdd.Core.html#162}{\htmlId{10475}{\htmlClass{Field Operator}{\text{+}}}}\, \,\href{Ledger.Dijkstra.Specification.Rewards.html#6508}{\htmlId{10477}{\htmlClass{Function}{\text{Δt}}}}\, \,\href{Class.HasAdd.Core.html#162}{\htmlId{10480}{\htmlClass{Field Operator}{\text{+}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#966}{\htmlId{10482}{\htmlClass{InductiveConstructor}{\text{pos}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#10827}{\htmlId{10486}{\htmlClass{Function}{\text{unregRU'}}}}\,\,\htmlId{10494}{\htmlClass{Symbol}{\text{)}}}\, \\ \,\href{Prelude.html#3404}{\htmlId{10498}{\htmlClass{Function}{\text{posPart}}}}\, \,\htmlId{10506}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Dijkstra.Specification.Epoch.html#966}{\htmlId{10507}{\htmlClass{InductiveConstructor}{\text{pos}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#10293}{\htmlId{10511}{\htmlClass{Bound}{\text{reserves}}}}\, \,\href{Class.HasAdd.Core.html#162}{\htmlId{10520}{\htmlClass{Field Operator}{\text{+}}}}\, \,\href{Ledger.Dijkstra.Specification.Rewards.html#6511}{\htmlId{10522}{\htmlClass{Function}{\text{Δr}}}}\,\,\htmlId{10524}{\htmlClass{Symbol}{\text{)}}}\, \end{pmatrix} \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10307}{\htmlId{10530}{\htmlClass{Bound}{\text{ss}}}}\, \\ \begin{pmatrix} \begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#10316}{\htmlId{10539}{\htmlClass{Bound}{\text{utxo}}}}\, \\ \,\href{Prelude.html#3404}{\htmlId{10546}{\htmlClass{Function}{\text{posPart}}}}\, \,\htmlId{10554}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Dijkstra.Specification.Epoch.html#966}{\htmlId{10555}{\htmlClass{InductiveConstructor}{\text{pos}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#10323}{\htmlId{10559}{\htmlClass{Bound}{\text{fees}}}}\, \,\href{Class.HasAdd.Core.html#162}{\htmlId{10564}{\htmlClass{Field Operator}{\text{+}}}}\, \,\href{Ledger.Dijkstra.Specification.Rewards.html#6514}{\htmlId{10566}{\htmlClass{Function}{\text{Δf}}}}\,\,\htmlId{10568}{\htmlClass{Symbol}{\text{)}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10330}{\htmlId{10572}{\htmlClass{Bound}{\text{donations}}}}\, \end{pmatrix} \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10345}{\htmlId{10586}{\htmlClass{Bound}{\text{govSt}}}}\, \\ \begin{pmatrix} \begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#10357}{\htmlId{10598}{\htmlClass{Bound}{\text{voteDelegs}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10370}{\htmlId{10611}{\htmlClass{Bound}{\text{stakeDelegs}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10384}{\htmlId{10625}{\htmlClass{Bound}{\text{rewards}}}}\, \,\href{Axiom.Set.Map.Dec.html#2149}{\htmlId{10633}{\htmlClass{Function Operator}{\text{∪⁺}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#10763}{\htmlId{10636}{\htmlClass{Function}{\text{regRU}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10394}{\htmlId{10644}{\htmlClass{Bound}{\text{deposits}}}}\, \end{pmatrix} \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10408}{\htmlId{10658}{\htmlClass{Bound}{\text{pState}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10417}{\htmlId{10667}{\htmlClass{Bound}{\text{gState}}}}\, \end{pmatrix}  \end{pmatrix} \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10433}{\htmlId{10684}{\htmlClass{Bound}{\text{es}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#10438}{\htmlId{10689}{\htmlClass{Bound}{\text{fut}}}}\, \end{pmatrix}$
  where
  open RewardUpdate rewardUpdate using (Δt; Δr; Δf; rs)
  regRU     = rs  dom rewards
  unregRU   = rs  dom rewards 
  unregRU'  = ∑[ x  unregRU ] x
opaque
  calculatePoolDelegatedStake : Snapshot  PoolDelegatedStake
  calculatePoolDelegatedStake ss = sd  dom (ss .pools)
    -- Shelley spec: the output map must contain keys appearing in both
    -- sd and the pool parameters.
    where
      open Snapshot
      -- stake credentials delegating to each pool
      stakeCredentialsPerPool : Rel KeyHash Credential
      stakeCredentialsPerPool = (StakeDelegsOf ss ˢ) ⁻¹ʳ
      -- delegated stake per pool
      sd : KeyHash  Coin
      sd = aggregate₊ ((stakeCredentialsPerPool ∘ʳ (StakeOf ss ˢ)) ᶠˢ)

  -- In Dijkstra, look up each gov action's deposit from GState.deposits
  -- using the stake credential of the proposal's returnAddr.
  stakeFromGADeposits : GovState  GState  Stake
  stakeFromGADeposits govSt gState =
    aggregateBy
      (mapˢ  (gaid , addr)  (gaid , addr) , stake addr) govSt')
      (mapFromPartialFun  (_ , addr)  lookupᵐ? (DepositsOf gState) (stake addr)) govSt')
    where
      govSt' :  (GovActionID × RewardAddress)
      govSt' = mapˢ (map₂ returnAddr) (fromList govSt)

module VDelegDelegatedStake
  (currentEpoch : Epoch)
  (utxoSt       : UTxOState)
  (govSt        : GovState)
  (gState       : GState)
  (dState       : DState)
  where
  activeDReps :  Credential
  activeDReps = dom (activeDRepsOf gState currentEpoch)
  activeVDelegs :  VDeleg
  activeVDelegs = mapˢ vDelegCredential activeDReps   vDelegNoConfidence    vDelegAbstain 
  stakePerCredential : Credential  Coin
  stakePerCredential c =
      cbalance ((UTxOOf utxoSt) ∣^' λ txout  getStakeCred txout  just c)
    + fromMaybe 0 (lookupᵐ? (stakeFromGADeposits govSt gState) c)  -- ← gState, not utxoSt
    + fromMaybe 0 (lookupᵐ? (RewardsOf dState) c)
  calculate : VDeleg  Coin
  calculate =
    mapFromFun
       vd  ∑ˢ[ c  (VoteDelegsOf dState) ⁻¹ vd ] stakePerCredential c)
      activeVDelegs


opaque
  calculateVDelegDelegatedStake : Epoch  UTxOState  GovState  GState  DState  VDeleg  Coin
  calculateVDelegDelegatedStake = VDelegDelegatedStake.calculate

  -- Pool-delegated stake for voting:
  -- also uses gState instead of utxoSt for gov-action deposit component.
  calculatePoolDelegatedStakeForVoting : Snapshot  GovState  GState  KeyHash  Coin
  calculatePoolDelegatedStakeForVoting ss govSt gState =
    calculatePoolDelegatedStake ss ∪⁺ (stakeFromDeposits  dom (PoolsOf ss))
    where
    stakeFromDeposits : KeyHash  Coin
    stakeFromDeposits = aggregate₊ (((StakeDelegsOf ss ˢ) ⁻¹ʳ ∘ʳ (stakeFromGADeposits govSt gState ˢ)) ᶠˢ)

-- mkStakeDistrs no longer takes utxoSt for the deposit lookup,
-- but still takes it for the UTxO-balance part of VDeleg stake.
mkStakeDistrs : Snapshot  Epoch  UTxOState  GovState  GState  DState  StakeDistrs
mkStakeDistrs ss currentEpoch utxoSt govSt gState dState =
  $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#12766}{\htmlId{13697}{\htmlClass{Function}{\text{calculateVDelegDelegatedStake}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13651}{\htmlId{13727}{\htmlClass{Bound}{\text{currentEpoch}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13664}{\htmlId{13740}{\htmlClass{Bound}{\text{utxoSt}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13671}{\htmlId{13747}{\htmlClass{Bound}{\text{govSt}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13677}{\htmlId{13753}{\htmlClass{Bound}{\text{gState}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13684}{\htmlId{13760}{\htmlClass{Bound}{\text{dState}}}}\,
  \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13041}{\htmlId{13771}{\htmlClass{Function}{\text{calculatePoolDelegatedStakeForVoting}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13648}{\htmlId{13808}{\htmlClass{Bound}{\text{ss}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13671}{\htmlId{13811}{\htmlClass{Bound}{\text{govSt}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13677}{\htmlId{13817}{\htmlClass{Bound}{\text{gState}}}}\,   \,\htmlId{13826}{\htmlClass{Comment}{\text{-- ← no utxoSt here}}}\,
  \end{pmatrix}$


private variable
  e lastEpoch : Epoch
  fut fut' : RatifyState
  eps eps' eps'' : EpochState
  ls : LedgerState
  acnt : Acnt
  es₀ : EnactState
  ss ss' : Snapshots
  ru : RewardUpdate
  mru : Maybe RewardUpdate
data _⊢_⇀⦇_,EPOCH⦈_ :   EpochState  Epoch  EpochState  Type where

  EPOCH : let
      open LedgerState ls
      open RatifyState fut renaming (es to esW)

      es : EnactState
      es = record esW { withdrawals =  }

      tmpGovSt = filter  x  ¿ proj₁ x  mapˢ proj₁ removed ¿) govSt

      orphans :  (GovActionID × GovActionState)
      orphans  = fromList (getOrphans es tmpGovSt)

      removed' :  (GovActionID × GovActionState)
      removed' = removed  orphans

      govSt' = filter  x  ¿ proj₁ x  mapˢ proj₁ removed' ¿) govSt

      removedGovActions :  (RewardAddress × Coin)
      removedGovActions =
          mapPartial
             (gaid , gaSt) 
              let ra   = GovActionState.returnAddr gaSt
                  cred = RewardAddress.stake ra
              in  (ra ,_) <$> lookupᵐ? (DepositsOf (GStateOf ls)) cred)
            removed'

      govActionReturns : RewardAddress  Coin
      govActionReturns =
        aggregate₊ (mapˢ  (a , d)  a , d) removedGovActions ᶠˢ)

      trWithdrawals   = WithdrawalsOf esW
      totWithdrawals  = ∑[ x  trWithdrawals ] x

      retired    = (RetiringOf (PStateOf ls)) ⁻¹ e
      payout     = govActionReturns ∪⁺ trWithdrawals
      refunds    = pullbackMap payout toRewardAddress (dom (RewardsOf (DStateOf ls)))
      unclaimed  = getCoin payout - getCoin refunds

      dState' : DState
      dState' = record (DStateOf ls) { rewards = (RewardsOf (DStateOf ls)) ∪⁺ refunds }

      pState' : PState
      pState' = let ps = PStateOf ls in
        $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Certs.html#3102}{\htmlId{15625}{\htmlClass{Field}{\text{PoolsOf}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#15595}{\htmlId{15633}{\htmlClass{Bound}{\text{ps}}}}\, \,\href{Axiom.Set.Map.html#13606}{\htmlId{15636}{\htmlClass{Function Operator}{\text{∣}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#15203}{\htmlId{15638}{\htmlClass{Bound}{\text{retired}}}}\, \,\href{Axiom.Set.Map.html#13606}{\htmlId{15646}{\htmlClass{Function Operator}{\text{ᶜ}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Certs.html#2296}{\htmlId{15650}{\htmlClass{Field}{\text{PState.fPools}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#15595}{\htmlId{15664}{\htmlClass{Bound}{\text{ps}}}}\, \,\href{Axiom.Set.Map.html#13606}{\htmlId{15667}{\htmlClass{Function Operator}{\text{∣}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#15203}{\htmlId{15669}{\htmlClass{Bound}{\text{retired}}}}\, \,\href{Axiom.Set.Map.html#13606}{\htmlId{15677}{\htmlClass{Function Operator}{\text{ᶜ}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Certs.html#3209}{\htmlId{15681}{\htmlClass{Field}{\text{RetiringOf}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#15595}{\htmlId{15692}{\htmlClass{Bound}{\text{ps}}}}\, \,\href{Axiom.Set.Map.html#13606}{\htmlId{15695}{\htmlClass{Function Operator}{\text{∣}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#15203}{\htmlId{15697}{\htmlClass{Bound}{\text{retired}}}}\, \,\href{Axiom.Set.Map.html#13606}{\htmlId{15705}{\htmlClass{Function Operator}{\text{ᶜ}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Certs.html#2869}{\htmlId{15709}{\htmlClass{Field}{\text{DepositsOf}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#15595}{\htmlId{15720}{\htmlClass{Bound}{\text{ps}}}}\, \,\href{Axiom.Set.Map.html#13606}{\htmlId{15723}{\htmlClass{Function Operator}{\text{∣}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#15203}{\htmlId{15725}{\htmlClass{Bound}{\text{retired}}}}\, \,\href{Axiom.Set.Map.html#13606}{\htmlId{15733}{\htmlClass{Function Operator}{\text{ᶜ}}}}\, \end{pmatrix}$

      gState' : GState
      gState' = $\begin{pmatrix} \,\htmlId{15779}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Class.ToBool.html#342}{\htmlId{15780}{\htmlClass{Function Operator}{\text{if}}}}\, \,\href{Data.List.Base.html#4681}{\htmlId{15783}{\htmlClass{Function}{\text{null}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#14574}{\htmlId{15788}{\htmlClass{Bound}{\text{govSt'}}}}\, \,\href{Class.ToBool.html#342}{\htmlId{15795}{\htmlClass{Function Operator}{\text{then}}}}\, \,\href{Axiom.Set.Map.html#7108}{\htmlId{15800}{\htmlClass{Function}{\text{mapValues}}}}\, \,\htmlId{15810}{\htmlClass{Symbol}{\text{(}}}\,\,\htmlId{15811}{\htmlClass{Number}{\text{1}}}\, \,\href{Class.HasAdd.Core.html#162}{\htmlId{15813}{\htmlClass{Field Operator}{\text{+\_}}}}\,\,\htmlId{15815}{\htmlClass{Symbol}{\text{)}}}\, \,\htmlId{15817}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Dijkstra.Specification.Gov.Actions.html#5421}{\htmlId{15818}{\htmlClass{Field}{\text{DRepsOf}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13948}{\htmlId{15826}{\htmlClass{Generalizable}{\text{ls}}}}\,\,\htmlId{15828}{\htmlClass{Symbol}{\text{)}}}\, \,\href{Class.ToBool.html#342}{\htmlId{15830}{\htmlClass{Function Operator}{\text{else}}}}\, \,\htmlId{15835}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Dijkstra.Specification.Gov.Actions.html#5421}{\htmlId{15836}{\htmlClass{Field}{\text{DRepsOf}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13948}{\htmlId{15844}{\htmlClass{Generalizable}{\text{ls}}}}\,\,\htmlId{15846}{\htmlClass{Symbol}{\text{))}}}\,
                , \,\href{Ledger.Dijkstra.Specification.Certs.html#2986}{\htmlId{15867}{\htmlClass{Field}{\text{CCHotKeysOf}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13948}{\htmlId{15879}{\htmlClass{Generalizable}{\text{ls}}}}\, \,\href{Axiom.Set.Map.html#13536}{\htmlId{15882}{\htmlClass{Function Operator}{\text{∣}}}}\, \,\href{Ledger.Dijkstra.Specification.Enact.html#1770}{\htmlId{15884}{\htmlClass{Function}{\text{ccCreds}}}}\, \,\htmlId{15892}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Dijkstra.Specification.Enact.html#857}{\htmlId{15893}{\htmlClass{Field}{\text{EnactState.cc}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#14250}{\htmlId{15907}{\htmlClass{Bound}{\text{es}}}}\,\,\htmlId{15909}{\htmlClass{Symbol}{\text{)}}}\,
                , \,\href{Ledger.Dijkstra.Specification.Certs.html#2869}{\htmlId{15929}{\htmlClass{Field}{\text{DepositsOf}}}}\, \,\htmlId{15940}{\htmlClass{Symbol}{\text{(}}}\,\,\href{Ledger.Dijkstra.Specification.Certs.html#3885}{\htmlId{15941}{\htmlClass{Field}{\text{GStateOf}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#13948}{\htmlId{15950}{\htmlClass{Generalizable}{\text{ls}}}}\,\,\htmlId{15952}{\htmlClass{Symbol}{\text{)}}}\,
                  \,\htmlId{15972}{\htmlClass{Comment}{\text{-- ∣ mapˢ (RewardAddress.stake ∘ GovActionState.returnAddr ∘ proj₂) removed' ᶜ}}}\,
                \end{pmatrix}$

      certState' : CertState
      certState' = record { dState = dState' ; pState = pState' ; gState = gState' }

      -- utxoSt' = ⟦ utxoSt .utxo , utxoSt .fees , utxoSt .deposits ∣ mapˢ (proj₁ ∘ proj₂) removedGovActions ᶜ , 0 ⟧
      utxoSt' = UTxOStateOf ls

      acnt' = record acnt
        { treasury  = TreasuryOf acnt  totWithdrawals + DonationsOf utxoSt + unclaimed }

      stakeDistrs : StakeDistrs
      stakeDistrs = mkStakeDistrs (Snapshots.mark ss') e utxoSt' govSt' (GStateOf ls) (DStateOf ls)

      ratifyΓ : RatifyEnv
      ratifyΓ = record { stakeDistrs  = stakeDistrs
                       ; currentEpoch = e
                       ; dreps        = DRepsOf ls
                       ; ccHotKeys    = CCHotKeysOf ls
                       ; treasury     = TreasuryOf acnt
                       ; pools        = PoolsOf ls
                       ; delegatees   = VoteDelegsOf ls }

    in
     ratifyΓ  $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#14250}{\htmlId{17001}{\htmlClass{Bound}{\text{es}}}}\, \\ \,\href{Class.HasEmptySet.html#287}{\htmlId{17006}{\htmlClass{Field}{\text{∅}}}}\, \\ \,\href{Agda.Builtin.Bool.html#192}{\htmlId{17010}{\htmlClass{InductiveConstructor}{\text{false}}}}\, \end{pmatrix}$ ⇀⦇ govSt' ,RATIFIES⦈ fut'
     ls  ss ⇀⦇ tt ,SNAP⦈ ss'
      ────────────────────────────────
      _  $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#13967}{\htmlId{17126}{\htmlClass{Generalizable}{\text{acnt}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#14000}{\htmlId{17133}{\htmlClass{Generalizable}{\text{ss}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13948}{\htmlId{17138}{\htmlClass{Generalizable}{\text{ls}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13981}{\htmlId{17143}{\htmlClass{Generalizable}{\text{es₀}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13893}{\htmlId{17149}{\htmlClass{Generalizable}{\text{fut}}}}\, \end{pmatrix}$ ⇀⦇ e ,EPOCH⦈ $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#16340}{\htmlId{17170}{\htmlClass{Bound}{\text{acnt'}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#14003}{\htmlId{17178}{\htmlClass{Generalizable}{\text{ss'}}}}\, \\ \begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#16308}{\htmlId{17186}{\htmlClass{Bound}{\text{utxoSt'}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#14574}{\htmlId{17196}{\htmlClass{Bound}{\text{govSt'}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#16076}{\htmlId{17205}{\htmlClass{Bound}{\text{certState'}}}}\, \end{pmatrix} \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#14250}{\htmlId{17220}{\htmlClass{Bound}{\text{es}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13897}{\htmlId{17225}{\htmlClass{Generalizable}{\text{fut'}}}}\, \end{pmatrix}$

data _⊢_⇀⦇_,NEWEPOCH⦈_ :   NewEpochState  Epoch  NewEpochState  Type where

  NEWEPOCH-New :
     {bprev bcur : BlocksMade} {pd : PoolDelegatedStake} 
    let
       eps' = applyRUpd ru eps
       ss   = EpochState.ss eps''
       pd'  = calculatePoolDelegatedStake (Snapshots.set ss)
     in
        e  lastEpoch + 1
        _  eps' ⇀⦇ e ,EPOCH⦈ eps''
       ────────────────────────────────
       _  $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#13873}{\htmlId{17650}{\htmlClass{Generalizable}{\text{lastEpoch}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17338}{\htmlId{17662}{\htmlClass{Bound}{\text{bprev}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17344}{\htmlId{17670}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13918}{\htmlId{17677}{\htmlClass{Generalizable}{\text{eps}}}}\, \\ \,\href{Agda.Builtin.Maybe.html#173}{\htmlId{17683}{\htmlClass{InductiveConstructor}{\text{just}}}}\, \,\href{Ledger.Dijkstra.Specification.Epoch.html#14021}{\htmlId{17688}{\htmlClass{Generalizable}{\text{ru}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17364}{\htmlId{17693}{\htmlClass{Bound}{\text{pd}}}}\, \end{pmatrix}$ ⇀⦇ e ,NEWEPOCH⦈ $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#13871}{\htmlId{17716}{\htmlClass{Generalizable}{\text{e}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17344}{\htmlId{17720}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Axiom.Set.Map.html#2671}{\htmlId{17727}{\htmlClass{Function}{\text{∅ᵐ}}}}\,  \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13927}{\htmlId{17733}{\htmlClass{Generalizable}{\text{eps''}}}}\, \\ \,\href{Agda.Builtin.Maybe.html#194}{\htmlId{17741}{\htmlClass{InductiveConstructor}{\text{nothing}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17471}{\htmlId{17751}{\htmlClass{Bound}{\text{pd'}}}}\, \end{pmatrix}$

  NEWEPOCH-Not-New :  {bprev bcur : BlocksMade} {pd : PoolDelegatedStake} 
     e  lastEpoch + 1
      ────────────────────────────────
      _  $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#13873}{\htmlId{17910}{\htmlClass{Generalizable}{\text{lastEpoch}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17782}{\htmlId{17922}{\htmlClass{Bound}{\text{bprev}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17788}{\htmlId{17930}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13918}{\htmlId{17937}{\htmlClass{Generalizable}{\text{eps}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#14041}{\htmlId{17943}{\htmlClass{Generalizable}{\text{mru}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17808}{\htmlId{17949}{\htmlClass{Bound}{\text{pd}}}}\, \end{pmatrix}$ ⇀⦇ e ,NEWEPOCH⦈ $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#13873}{\htmlId{17972}{\htmlClass{Generalizable}{\text{lastEpoch}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17782}{\htmlId{17984}{\htmlClass{Bound}{\text{bprev}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17788}{\htmlId{17992}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13918}{\htmlId{17999}{\htmlClass{Generalizable}{\text{eps}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#14041}{\htmlId{18005}{\htmlClass{Generalizable}{\text{mru}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#17808}{\htmlId{18011}{\htmlClass{Bound}{\text{pd}}}}\, \end{pmatrix}$

  NEWEPOCH-No-Reward-Update :
     {bprev bcur : BlocksMade} {pd : PoolDelegatedStake} 
    let
      ss  = EpochState.ss eps'
      pd' = calculatePoolDelegatedStake (Snapshots.set ss)
    in
       e  lastEpoch + 1
       _  eps ⇀⦇ e ,EPOCH⦈ eps'
      ────────────────────────────────
      _  $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#13873}{\htmlId{18323}{\htmlClass{Generalizable}{\text{lastEpoch}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#18054}{\htmlId{18335}{\htmlClass{Bound}{\text{bprev}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#18060}{\htmlId{18343}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13918}{\htmlId{18350}{\htmlClass{Generalizable}{\text{eps}}}}\, \\ \,\href{Agda.Builtin.Maybe.html#194}{\htmlId{18356}{\htmlClass{InductiveConstructor}{\text{nothing}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#18080}{\htmlId{18366}{\htmlClass{Bound}{\text{pd}}}}\, \end{pmatrix}$ ⇀⦇ e ,NEWEPOCH⦈ $\begin{pmatrix} \,\href{Ledger.Dijkstra.Specification.Epoch.html#13871}{\htmlId{18389}{\htmlClass{Generalizable}{\text{e}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#18060}{\htmlId{18393}{\htmlClass{Bound}{\text{bcur}}}}\, \\ \,\href{Axiom.Set.Map.html#2671}{\htmlId{18400}{\htmlClass{Function}{\text{∅ᵐ}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#13922}{\htmlId{18405}{\htmlClass{Generalizable}{\text{eps'}}}}\, \\ \,\href{Agda.Builtin.Maybe.html#194}{\htmlId{18412}{\htmlClass{InductiveConstructor}{\text{nothing}}}}\, \\ \,\href{Ledger.Dijkstra.Specification.Epoch.html#18152}{\htmlId{18422}{\htmlClass{Bound}{\text{pd'}}}}\, \end{pmatrix}$