Base

{-# OPTIONS --safe #-}

open import Ledger.Conway.Specification.Transaction
open import Ledger.Conway.Specification.Abstract
import Ledger.Conway.Specification.Certs

module Ledger.Conway.Specification.Ledger.Properties.Base
  (txs : _) (open TransactionStructure txs) (open Ledger.Conway.Specification.Certs govStructure)
  (abs : AbstractFunctions txs) (open AbstractFunctions abs)
  where

open import Ledger.Prelude
open import Ledger.Conway.Specification.Gov txs
open import Ledger.Conway.Specification.Ledger txs abs
open import Ledger.Conway.Specification.Utxo txs abs
open import Ledger.Conway.Specification.Utxow txs abs

-- open import Data.List using (map)
open import Data.List.Properties using (++-identityʳ; map-++)

open import Axiom.Set.Properties th

open import Data.Nat.Properties using (+-0-monoid; +-identityʳ; +-suc)
open import Relation.Binary using (IsEquivalence)
import Relation.Binary.Reasoning.Setoid as SetoidReasoning

-- ** Proof that the set equality `govDepsMatch` (below) is a LEDGER invariant.

-- Mapping a list of `GovActionID × GovActionState`s to a list of
-- `DepositPurpose`s is so common, we give it a name `dpMap`;
-- it's equivalent to `map (λ (id , _) → GovActionDeposit id)`.
dpMap : GovState  List DepositPurpose
dpMap = map (GovActionDeposit  proj₁)

isGADeposit : DepositPurpose  Type
isGADeposit dp = isGADepositᵇ dp  true
  where
  isGADepositᵇ : DepositPurpose  Bool
  isGADepositᵇ (GovActionDeposit _) = true
  isGADepositᵇ _                    = false

govDepsMatch : LState  Type
govDepsMatch ls =
  filterˢ isGADeposit (dom (DepositsOf ls)) ≡ᵉ fromList (dpMap (GovStateOf ls))

module  = IsEquivalence (≡ᵉ-isEquivalence {DepositPurpose})
pattern UTXOW-UTXOS x = UTXOW⇒UTXO (UTXO-inductive⋯ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ x)
open Equivalence

filterGA :  txId n  filterˢ isGADeposit  GovActionDeposit (txId , n)  ≡ᵉ  GovActionDeposit (txId , n) ❵
proj₁ (filterGA txId n) {a} x = (proj₂ (from ∈-filter x)) where open Equivalence
proj₂ (filterGA txId n) {a} x = to ∈-filter (ξ (from ∈-singleton x) , x)
  where
  ξ : a  GovActionDeposit (txId , n)  isGADeposit a
  ξ refl = refl

module LEDGER-PROPS (tx : Tx) (Γ : LEnv) (s : LState) where
  open Tx tx renaming (body to txb); open TxBody txb
  open LEnv Γ renaming (pparams to pp)
  open PParams pp using (govActionDeposit; govActionLifetime)
  open LState s
  open CertState certState
  open DState dState

  -- initial utxo deposits
  utxoDeps : Deposits
  utxoDeps = UTxOState.deposits (LState.utxoSt s)

  -- GovState definitions and lemmas --
  mkAction : GovProposal    GovActionID × GovActionState
  mkAction p n = let open GovProposal p in
    mkGovStatePair
      (govActionLifetime +ᵉ epoch slot)
      (txId , n) returnAddr action prevAction

  -- update GovState with a proposal
  propUpdate : GovState  GovProposal    GovState
  propUpdate s p n = insertGovAction s (mkAction p n)

  -- update GovState with a vote
  voteUpdate : GovState  GovVote  GovState
  voteUpdate s v = addVote s gid voter vote
    where open GovVote v

  -- update GovState with a list of votes and proposals
  updateGovStates : List (GovVote  GovProposal)    GovState  GovState
  updateGovStates [] _ s = s
  updateGovStates (inj₁ v  vps) k s = updateGovStates vps (suc k) (voteUpdate s v)
  updateGovStates (inj₂ p  vps) k s = updateGovStates vps (suc k) (propUpdate s p k)

  -- updateGovStates faithfully represents a step of the LEDGER sts
  STS→GovSt≡ :  {s' : LState}  Γ  s ⇀⦇ tx ,LEDGER⦈ s'
                isValid  true  GovStateOf s'  updateGovStates (txgov txb) 0 (rmOrphanDRepVotes (CertStateOf s') (GovStateOf s))
  STS→GovSt≡ (LEDGER-V x) refl = STS→updateGovSt≡ (txgov txb) 0 (proj₂ (proj₂ (proj₂ x)))
    where
    STS→updateGovSt≡ : (vps : List (GovVote  GovProposal)) (k : ) {certSt : CertState} {govSt govSt' : GovState}
       (_⊢_⇀⟦_⟧ᵢ*'_ {_⊢_⇀⟦_⟧ᵇ_ = IdSTS}{_⊢_⇀⦇_,GOV⦈_} ( txId , epoch slot , pp , ppolicy , enactState , certSt , dom rewards  , k) govSt vps govSt')
       govSt'  updateGovStates vps k govSt
    STS→updateGovSt≡ [] _ (BS-base Id-nop) = refl
    STS→updateGovSt≡ (inj₁ v  vps) k (BS-ind (GOV-Vote x) h)
      = STS→updateGovSt≡ vps (suc k) h
    STS→updateGovSt≡ (inj₂ p  vps) k (BS-ind (GOV-Propose x) h) = STS→updateGovSt≡ vps (suc k) h

  opaque
    unfolding addVote

    dpMap-rmOrphanDRepVotes :  certState govSt  dpMap (rmOrphanDRepVotes certState govSt)  dpMap govSt
    dpMap-rmOrphanDRepVotes certState govSt = sym (fmap-∘ govSt) -- map proj₁ ∘ map (map₂ _) ≡ map (proj₁ ∘ map₂ _) ≡ map proj₁

module SetoidProperties (tx : Tx) (Γ : LEnv) (s : LState) where
  open Tx tx renaming (body to txb); open TxBody txb
  open LEnv Γ renaming (pparams to pp)
  open LEDGER-PROPS tx Γ s using (utxoDeps; propUpdate; mkAction; updateGovStates; STS→GovSt≡; voteUpdate; dpMap-rmOrphanDRepVotes)
  open SetoidReasoning (≡ᵉ-Setoid{DepositPurpose})

  CredDepIsNotGADep :  {a c}  a  CredentialDeposit c  ¬ isGADeposit a
  CredDepIsNotGADep refl ()

  PoolDepIsNotGADep :  {a c}  a  PoolDeposit c  ¬ isGADeposit a
  PoolDepIsNotGADep refl ()

  DRepDepIsNotGADep :  {a c}  a  DRepDeposit c  ¬ isGADeposit a
  DRepDepIsNotGADep refl ()

  filterCR : (c : DCert) (deps : Deposits)
              filterˢ isGADeposit (dom ( deps  certRefund c  ˢ )) ≡ᵉ filterˢ isGADeposit (dom (deps ˢ))
  filterCR (dereg c _) deps = ≡ᵉ.sym $ begin
    filterˢ isGADeposit (dom (deps ˢ)) ≈˘⟨ filter-cong $ dom-cong (res-ex-∪ Dec-∈-singleton)     filterˢ isGADeposit (dom ((deps  cr)ˢ  (deps  cr )ˢ)) ≈⟨ filter-cong dom∪     filterˢ isGADeposit (dom ((deps  cr) ˢ)  dom ((deps  cr ) ˢ )) ≈⟨ filter-hom-∪     filterˢ isGADeposit (dom ((deps  cr) ˢ))  filterˢ isGADeposit (dom ((deps  cr ) ˢ )) ≈⟨ ∪-cong filter0 ≡ᵉ.refl       filterˢ isGADeposit (dom ((deps  cr ) ˢ )) ≈⟨ ∪-identityˡ $ filterˢ isGADeposit (dom ((deps  cr ) ˢ ))     filterˢ isGADeposit (dom ((deps  cr ) ˢ))     where
    cr =  CredentialDeposit c     filter0 = filter-∅ (λ _  CredDepIsNotGADep  (from ∈-singleton)  res-dom)
  filterCR (deregdrep c _) deps = ≡ᵉ.sym $ begin
    filterˢ isGADeposit (dom (deps ˢ)) ≈˘⟨ filter-cong $ dom-cong (res-ex-∪ Dec-∈-singleton)     filterˢ isGADeposit (dom ((deps  cr)ˢ  (deps  cr )ˢ)) ≈⟨ filter-cong dom∪     filterˢ isGADeposit (dom ((deps  cr) ˢ)  dom ((deps  cr ) ˢ )) ≈⟨ filter-hom-∪     filterˢ isGADeposit (dom ((deps  cr) ˢ))  filterˢ isGADeposit (dom ((deps  cr ) ˢ )) ≈⟨ ∪-cong filter0 ≡ᵉ.refl       filterˢ isGADeposit (dom ((deps  cr ) ˢ )) ≈⟨ ∪-identityˡ $ filterˢ isGADeposit (dom ((deps  cr ) ˢ ))     filterˢ isGADeposit (dom ((deps  cr ) ˢ))     where
    cr =  DRepDeposit c     filter0 = filter-∅ (λ _  DRepDepIsNotGADep  (from ∈-singleton)  res-dom)
  filterCR (delegate _ _ _ _)  deps = filter-cong (dom-cong (resᵐ-∅ᶜ {M = deps}))
  filterCR (regpool _ _)       deps = filter-cong (dom-cong (resᵐ-∅ᶜ {M = deps}))
  filterCR (regdrep _ _ _)     deps = filter-cong (dom-cong (resᵐ-∅ᶜ {M = deps}))
  filterCR (retirepool _ _)    deps = filter-cong (dom-cong (resᵐ-∅ᶜ {M = deps}))
  filterCR (ccreghot _ _)      deps = filter-cong (dom-cong (resᵐ-∅ᶜ {M = deps}))
  filterCR (reg _ _)           deps = filter-cong (dom-cong (resᵐ-∅ᶜ {M = deps}))

  filterCD : (c : DCert) (deps : Deposits)  filterˢ isGADeposit (dom (certDeposit c pp ˢ)) ≡ᵉ   filterCD (delegate _ _ _ _)  deps = filter-∅ λ _  CredDepIsNotGADep  from ∈-singleton  dom-single→single
  filterCD (reg _ _)           deps = filter-∅ λ _  CredDepIsNotGADep  from ∈-singleton  dom-single→single
  filterCD (regpool _ _)       deps = filter-∅ λ _  PoolDepIsNotGADep  from ∈-singleton  dom-single→single
  filterCD (regdrep _ _ _)     deps = filter-∅ λ _  DRepDepIsNotGADep  from ∈-singleton  dom-single→single
  filterCD (dereg _ _)         deps = ≡ᵉ.trans (filter-cong dom∅) $ filter-∅ λ _ a∈ _  ∉-∅ a∈
  filterCD (retirepool _ _)    deps = ≡ᵉ.trans (filter-cong dom∅) $ filter-∅ λ _ a∈ _  ∉-∅ a∈
  filterCD (deregdrep _ _)     deps = ≡ᵉ.trans (filter-cong dom∅) $ filter-∅ λ _ a∈ _  ∉-∅ a∈
  filterCD (ccreghot _ _)      deps = ≡ᵉ.trans (filter-cong dom∅) $ filter-∅ λ _ a∈ _  ∉-∅ a∈

  noGACerts : (cs : List DCert) (deps : Deposits)
     filterˢ isGADeposit (dom (updateCertDeposits pp cs deps)) ≡ᵉ filterˢ isGADeposit (dom deps)
  noGACerts [] _ = filter-cong ≡ᵉ.refl
  noGACerts (dcert@(delegate _ _ _ _)  cs) deps = begin
    filterˢ isGADeposit (dom (updateCertDeposits pp cs (deps ∪⁺ cd))) ≈⟨ noGACerts cs _     filterˢ isGADeposit (dom (deps ∪⁺ cd)) ≈⟨ filter-cong dom∪⁺≡∪dom     filterˢ isGADeposit (dom deps  dom (cd ˢ )) ≈⟨ filter-hom-∪     filterˢ isGADeposit (dom deps)  filterˢ isGADeposit (dom (cd ˢ)) ≈⟨ ∪-cong ≡ᵉ.refl $ filterCD dcert deps     filterˢ isGADeposit (dom deps)   ≈⟨ ∪-identityʳ $ filterˢ isGADeposit (dom deps)     filterˢ isGADeposit (dom deps)     where
      cd = certDeposit dcert pp
      filter0 = filterCD dcert deps
  noGACerts (dcert@(reg _ _)  cs) deps = begin
    filterˢ isGADeposit (dom (updateCertDeposits pp cs (deps ∪⁺ cd))) ≈⟨ noGACerts cs _     filterˢ isGADeposit (dom (deps ∪⁺ cd)) ≈⟨ filter-cong dom∪⁺≡∪dom     filterˢ isGADeposit (dom deps  dom (cd ˢ )) ≈⟨ filter-hom-∪     filterˢ isGADeposit (dom deps)  filterˢ isGADeposit (dom (cd ˢ)) ≈⟨ ∪-cong ≡ᵉ.refl $ filterCD dcert deps     filterˢ isGADeposit (dom deps)   ≈⟨ ∪-identityʳ $ filterˢ isGADeposit (dom deps)     filterˢ isGADeposit (dom deps)     where
      cd = certDeposit dcert pp
      filter0 = filterCD dcert deps
  noGACerts (dcert@(regpool _ _)  cs) deps = begin
    filterˢ isGADeposit (dom (updateCertDeposits pp cs (deps ∪⁺ cd))) ≈⟨ noGACerts cs _     filterˢ isGADeposit (dom (deps ∪⁺ cd)) ≈⟨ filter-cong dom∪⁺≡∪dom     filterˢ isGADeposit (dom deps  dom (cd ˢ )) ≈⟨ filter-hom-∪     filterˢ isGADeposit (dom deps)  filterˢ isGADeposit (dom (cd ˢ)) ≈⟨ ∪-cong ≡ᵉ.refl filter0     filterˢ isGADeposit (dom deps)   ≈⟨ ∪-identityʳ $ filterˢ isGADeposit (dom deps)     filterˢ isGADeposit (dom deps)     where
      cd = certDeposit dcert pp
      filter0 = filterCD dcert deps
  noGACerts (dcert@(regdrep _ _ _)  cs) deps = begin
    filterˢ isGADeposit (dom (updateCertDeposits pp cs (deps ∪⁺ certDeposit dcert pp))) ≈⟨ noGACerts cs _     filterˢ isGADeposit (dom (deps ∪⁺ cd)) ≈⟨ filter-cong dom∪⁺≡∪dom     filterˢ isGADeposit (dom deps  dom (cd ˢ )) ≈⟨ filter-hom-∪     filterˢ isGADeposit (dom deps)  filterˢ isGADeposit (dom (cd ˢ)) ≈⟨ ∪-cong ≡ᵉ.refl filter0     filterˢ isGADeposit (dom deps)   ≈⟨ ∪-identityʳ $ filterˢ isGADeposit (dom deps)     filterˢ isGADeposit (dom deps)     where
      cd = certDeposit dcert pp
      filter0 = filterCD dcert deps
  noGACerts (dcert@(dereg c v)  cs) deps = begin
    filterˢ isGADeposit (dom (updateCertDeposits pp cs (deps  certRefund (dereg c v)))) ≈⟨ noGACerts cs _     filterˢ isGADeposit (dom (deps  certRefund (dereg c v))) ≈⟨ filterCR dcert deps     filterˢ isGADeposit (dom deps)   noGACerts (dcert@(deregdrep c v)  cs) deps = begin
    filterˢ isGADeposit (dom (updateCertDeposits pp cs (deps  certRefund (deregdrep c v)))) ≈⟨ noGACerts cs _     filterˢ isGADeposit (dom (deps  certRefund (deregdrep c v))) ≈⟨ filterCR dcert deps     filterˢ isGADeposit (dom deps)   noGACerts (retirepool _ _  cs) deps = noGACerts cs deps
  noGACerts (ccreghot _ _  cs) deps = noGACerts cs deps

  opaque
    unfolding addVote

    dpMap∘voteUpdate≡dpMap : (v : GovVote) {govSt : GovState}
       dpMap (voteUpdate govSt v)  dpMap govSt
    dpMap∘voteUpdate≡dpMap v {[]} = refl
    dpMap∘voteUpdate≡dpMap v {(aid , ast)  govSt} =
      cong (λ x  (GovActionDeposit  proj₁) (aid , ast)  x) (dpMap∘voteUpdate≡dpMap v)

  props-dpMap-votes-invar : (vs : List GovVote) (ps : List GovProposal) {k : } {govSt : GovState}
     fromList (dpMap (updateGovStates (map inj₂ ps ++ map inj₁ vs) k govSt ))
      ≡ᵉ fromList (dpMap (updateGovStates (map inj₂ ps) k govSt))
  props-dpMap-votes-invar [] ps {k} {govSt} = ≡ᵉ.reflexive
    (cong (λ x  fromList (dpMap (updateGovStates x k govSt))) (++-identityʳ (map inj₂ ps)))
  props-dpMap-votes-invar (v  vs) [] {k} {govSt} = begin
    fromList (dpMap (updateGovStates (map inj₁ (v  vs)) k govSt))
      ≈⟨ props-dpMap-votes-invar vs []     fromList (dpMap (updateGovStates (map inj₂ []) (suc k) (voteUpdate govSt v)))
      ≡⟨ cong fromList (dpMap∘voteUpdate≡dpMap v)     fromList (dpMap govSt)
        props-dpMap-votes-invar (v  vs) (p  ps) {k} {govSt} = props-dpMap-votes-invar (v  vs) ps

  dpMap-update-∪ :  gSt p k
     fromList (dpMap gSt)   GovActionDeposit (txId , k)         ≡ᵉ fromList (dpMap (propUpdate gSt p k))
  dpMap-update-∪ [] p k = ∪-identityˡ (fromList (dpMap [ mkAction p k ]))
  dpMap-update-∪ (g@(gaID₀ , gaSt₀)  gSt) p k
    with (govActionPriority (GovActionTypeOf gaSt₀))
         ≤? (govActionPriority (GovActionTypeOf (proj₂ (mkAction p k))))
  ... | yes _  = begin
      fromList (dpMap (g  gSt))   GovActionDeposit (txId , k)         ≈⟨ ∪-cong fromList-∪-singleton ≡ᵉ.refl       ( GovActionDeposit gaID₀   fromList (dpMap gSt))   GovActionDeposit (txId , k)         ≈⟨ ∪-assoc  GovActionDeposit gaID₀  (fromList (dpMap gSt))  GovActionDeposit (txId , k)         GovActionDeposit gaID₀   (fromList (dpMap gSt)   GovActionDeposit (txId , k) )
        ≈⟨ ∪-cong ≡ᵉ.refl (dpMap-update-∪ gSt p k)        GovActionDeposit gaID₀   fromList (dpMap (propUpdate gSt p k))
        ≈˘⟨ fromList-∪-singleton       fromList (dpMap (g  insertGovAction gSt (mkAction p k)))
          ... | no _   = begin
      fromList (dpMap (g  gSt))   GovActionDeposit (txId , k)         ≈⟨ ∪-comm (fromList (dpMap (g  gSt)))  GovActionDeposit (txId , k)         GovActionDeposit (txId , k)   fromList (dpMap (g  gSt))
        ≈˘⟨ fromList-∪-singleton       fromList (dpMap ((mkAction p k)  g  gSt))
          connex-lemma :  gSt p ps {k}
     fromList (dpMap (updateGovStates (map inj₂ ps) k gSt))   GovActionDeposit (txId , k + length ps)         ≡ᵉ fromList (dpMap (updateGovStates (map inj₂ ps) (suc k) (propUpdate gSt p k)))
  connex-lemma gSt p [] {k} = begin
      fromList (dpMap gSt)   GovActionDeposit (txId , k + 0)         ≡⟨ cong (λ x  fromList (dpMap gSt)   GovActionDeposit (txId , x) ) (+-identityʳ k)       fromList (dpMap gSt)   GovActionDeposit (txId , k)         ≈⟨ dpMap-update-∪ gSt p k       fromList (dpMap (propUpdate gSt p k))
          connex-lemma gSt p (p'  ps) {k} = begin
    fromList (dpMap (updateGovStates (map inj₂ (p'  ps)) k gSt))
        GovActionDeposit (txId , k + length (p'  ps))         ≡⟨ cong (λ x  fromList (dpMap (updateGovStates (map inj₂ (p'  ps)) k gSt))
              GovActionDeposit (txId , x) ) (+-suc k (length ps))     fromList (dpMap (updateGovStates (map inj₂ ps) (suc k) (propUpdate gSt p' k)))
        GovActionDeposit (txId , (suc k) + length ps)         ≈˘⟨ ∪-cong (connex-lemma gSt p' ps) ≡ᵉ.refl     (fromList (dpMap (updateGovStates (map inj₂ ps) k gSt))
        GovActionDeposit (txId , k + length ps) )
        GovActionDeposit (txId , (suc k) + length ps)         ≈⟨ ∪-cong (connex-lemma gSt p ps) ≡ᵉ.refl     fromList (dpMap (updateGovStates (map inj₂ ps) (suc k) (propUpdate gSt p k)))
        GovActionDeposit (txId , (suc k) + length ps)         ≈⟨ connex-lemma (propUpdate gSt p k) p' ps     fromList (dpMap (updateGovStates (map inj₂ (p'  ps)) (suc k) (propUpdate gSt p k)))
          utxo-govst-connex :  txp {utxoDs gSt gad}
     filterˢ isGADeposit (dom (utxoDs)) ≡ᵉ fromList (dpMap gSt)
     filterˢ isGADeposit (dom (updateProposalDeposits txp txId gad utxoDs))
      ≡ᵉ fromList (dpMap (updateGovStates (map inj₂ txp) 0 gSt))
  utxo-govst-connex [] x = x
  utxo-govst-connex (p  ps) {utxoDs} {gSt} {gad} x = begin
    filterˢ isGADeposit (dom (updateProposalDeposits (p  ps) txId gad utxoDs))
      ≈⟨ filter-cong dom∪⁺≡∪dom     filterˢ isGADeposit ((dom (updateProposalDeposits ps txId gad utxoDs))
       (dom{X = Deposits}  GovActionDeposit (txId , length ps) , gad ))
      ≈⟨ filter-hom-∪     filterˢ isGADeposit (dom (updateProposalDeposits ps txId gad utxoDs))  filterˢ isGADeposit
        (dom{X = Deposits}  GovActionDeposit (txId , length ps) , gad )
      ≈⟨ ∪-cong (utxo-govst-connex ps x) (filter-cong dom-single≡single)     fromList (dpMap (updateGovStates (map inj₂ ps) 0 gSt))
       filterˢ isGADeposit  GovActionDeposit (txId , length ps)       ≈⟨ ∪-cong  ≡ᵉ.refl (filterGA txId _)     fromList (dpMap (updateGovStates (map inj₂ ps) 0 gSt))   GovActionDeposit (txId , length ps)       ≈⟨ connex-lemma gSt p ps     fromList (dpMap (updateGovStates (map inj₂ (p  ps)) 0 gSt))   -- The list of natural numbers from 0 up to `n` - 1.
  ⟦0:<_⟧ :   List   ⟦0:< 0      = []
  ⟦0:< suc n  = ⟦0:< n  ++ [ n ]

  connex-lemma-rep :  k govSt ps 
    fromList (dpMap (updateGovStates (map inj₂ ps) k govSt))
    ≡ᵉ
    fromList (dpMap govSt)  fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length ps )
  connex-lemma-rep k govSt [] = begin
    fromList (dpMap govSt)
      ≈˘⟨ ∪-identityʳ (fromList (dpMap govSt))     fromList (dpMap govSt)  fromList []
      ≡⟨⟩
    fromList (dpMap govSt)  fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< 0 )   connex-lemma-rep k govSt (p  ps) = begin
    fromList (dpMap (updateGovStates (map inj₂ (p  ps)) k govSt))
      ≡⟨⟩
    fromList (dpMap (updateGovStates (inj₂ p  map inj₂ ps) k govSt))
      ≡⟨⟩
    fromList (dpMap (updateGovStates (map inj₂ ps) (suc k) (propUpdate govSt p k)))
      ≈˘⟨ connex-lemma govSt p ps {k}     fromList (dpMap (updateGovStates (map inj₂ ps) k govSt))   GovActionDeposit (txId , k + length ps)       ≈⟨ ∪-cong (connex-lemma-rep k govSt ps) ≡ᵉ.refl     (fromList (dpMap govSt)  fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length ps ))   GovActionDeposit (txId , k + length ps)       ≈⟨ ∪-assoc (fromList (dpMap govSt)) (fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length ps ))  GovActionDeposit (txId , k + length ps)      fromList (dpMap govSt)  (fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length ps )   GovActionDeposit (txId , k + length ps) )
      ≡⟨⟩
    fromList (dpMap govSt)  (fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length ps )  fromList [ GovActionDeposit (txId , k + length ps) ])
      ≈⟨ ∪-cong ≡ᵉ.refl (∪-fromList-++ (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length ps ) [ GovActionDeposit (txId , k + length ps) ])     fromList (dpMap govSt)  fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length ps  ++ [ GovActionDeposit (txId , k + length ps) ])
      ≡˘⟨ cong (λ x  fromList (dpMap govSt)  fromList x) (map-++ _ ⟦0:< length ps  [ length ps ])     fromList (dpMap govSt)  fromList (map (λ i  GovActionDeposit (txId , k + i)) (⟦0:< length ps  ++ [ length ps ]))
      ≡⟨⟩
    fromList (dpMap govSt)  fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length (p  ps) )   -- Removing orphan DRep votes does not modify the set of GAs in GovState
  |ᵒ-GAs-pres :  k govSt certState 
    fromList (dpMap (updateGovStates (txgov txb) k (rmOrphanDRepVotes certState govSt)))
    ≡ᵉ
    fromList (dpMap (updateGovStates (txgov txb) k govSt))
  |ᵒ-GAs-pres k govSt certState = begin
    fromList (dpMap (updateGovStates (txgov txb) k (rmOrphanDRepVotes certState govSt)))
      ≈⟨ props-dpMap-votes-invar txGovVotes txGovProposals {k} {rmOrphanDRepVotes certState govSt}     fromList (dpMap (updateGovStates (map inj₂ txGovProposals) k (rmOrphanDRepVotes certState govSt)))
      ≈⟨ connex-lemma-rep k (rmOrphanDRepVotes certState govSt) txGovProposals     fromList (dpMap (rmOrphanDRepVotes certState govSt))  fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length txGovProposals )
      ≡⟨ cong (λ x  fromList x  fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length txGovProposals )) (dpMap-rmOrphanDRepVotes certState govSt)     fromList (dpMap govSt)  fromList (map (λ i  GovActionDeposit (txId , k + i)) ⟦0:< length txGovProposals )
      ≈˘⟨ connex-lemma-rep k govSt txGovProposals     fromList (dpMap (updateGovStates (map inj₂ txGovProposals) k govSt))
      ≈˘⟨ props-dpMap-votes-invar txGovVotes txGovProposals {k} {govSt}     fromList (dpMap (updateGovStates (txgov txb) k govSt))