{-# 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⦈_} ($\begin{pmatrix} \,\href{Ledger.Conway.Specification.Transaction.html#3180}{\htmlId{3940}{\htmlClass{Function}{\text{txId}}}}\, \\ \,\href{Ledger.Core.Specification.Epoch.html#810}{\htmlId{3947}{\htmlClass{Function}{\text{epoch}}}}\, \,\href{Ledger.Conway.Specification.Ledger.html#743}{\htmlId{3953}{\htmlClass{Function}{\text{slot}}}}\, \\ \,\href{Ledger.Conway.Specification.Ledger.Properties.Base.html#2306}{\htmlId{3960}{\htmlClass{Function}{\text{pp}}}}\, \\ \,\href{Ledger.Conway.Specification.Ledger.html#766}{\htmlId{3965}{\htmlClass{Function}{\text{ppolicy}}}}\, \\ \,\href{Ledger.Conway.Specification.Ledger.html#827}{\htmlId{3975}{\htmlClass{Function}{\text{enactState}}}}\, \\ \,\href{Ledger.Conway.Specification.Ledger.Properties.Base.html#3836}{\htmlId{3988}{\htmlClass{Bound}{\text{certSt}}}}\, \\ \,\href{Class.IsSet.html#916}{\htmlId{3997}{\htmlClass{Function}{\text{dom}}}}\, \,\href{Ledger.Conway.Specification.Certs.html#4017}{\htmlId{4001}{\htmlClass{Function}{\text{rewards}}}}\, \end{pmatrix}$ , 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))