blockVoted : (p ▷ e ⊢ ls —[ mm ]→ ls′) → Maybe (Block × Chain)
blockVoted {e = e} = λ where
  (VoteBlock {ch = ch} {txs = txs} _ _ _ _ _ _) → just (⟨ ch ♯ , e , txs ⟩ , ch)
  (ProposeBlock {ch = ch} {txs = txs} _ _ _ _) → just (⟨ ch ♯ , e , txs ⟩ , ch)
  _ → nothing

≡[_▷_] : Pid → Block × Chain → LocalStepProperty
≡[ p ▷ b , ch ] ((p′ , e′ , _) ⊢ st)
  = (p ≡ p′)
  × (b .epoch ≡ e′)
  × Any ((b , ch) ≡_) (blockVoted st)

HasVoted˘ : TraceProperty
HasVoted˘ tr@(s , _) = ∀ {p b ch} →
  tr ∋⋯ ≡[ p ▷ b , ch ]
  ──────────────────────────
  p ∈ voteIds (s .history) b

hasVoted˘ : TraceInvariant HasVoted˘
hasVoted˘ (_ , refl , (_ ∎)) ()
hasVoted˘ {s′} (_ , init , (_ ⟨ st ∣ s ⟩←— tr))
  {p}{b}{ch} st∈
  with IH ← hasVoted˘ (_ , init , tr)
  with st
... | Deliver _ = IH st∈
... | AdvanceEpoch = IH st∈
... | Drop _ = IH st∈
... | LocalStep {p = p′} ls→
  = QED
  where
  QED : p ∈ voteIds (s′ .history) b
  QED with ⟫ ls→ | ⟫ st∈
  QED | ⟫ FinalizeBlock _ _ _ _ | ⟫ there st∈ = IH st∈
  QED | ⟫ RegisterVote _ _ | ⟫ there st∈ = IH st∈
  QED | ⟫ ProposeBlock {ch = ch↓} {txs = txs} _ refl _ (_ ∷ _ ⊣ B↝)
      | ⟫ here (refl , refl , M.Any.just refl)
      = voteIds-here {m = M} refl refl
      where open ∣ProposeBlock∣ p′ s ch↓ txs
  QED | ⟫ ProposeBlock {ch = ch↓} {txs = txs} _ refl _ _
      | ⟫ there st∈
      = voteIds-there b $ IH st∈
  QED | ⟫ VoteBlock {ch = ch↓} {txs = txs} _ _ _ _ _ _
      | ⟫ there st∈
      = ≪QED
    where
    open ∣VoteBlock∣ p′ s ch↓ txs

    ≪QED : p ∈ voteIds (M ∷ s .history) b
    ≪QED with b ≟ B
    ... | no  _ = IH st∈
    ... | yes _ = there $ IH st∈
  QED | ⟫ VoteBlock {ch = ch} {txs = txs} _ _ _ _ _ _
      | ⟫ here (refl , refl , M.Any.just refl)
      = voteIds-here {m = M} refl refl
      where open ∣VoteBlock∣ p′ s ch txs
... | DishonestLocalStep _ _
  = voteIds-there b $ IH st∈

HasVoted : TraceProperty
HasVoted tr@(s , _) = ∀ {p b ch} ⦃ _ : Honest p ⦄ →
  ∙ b -connects-to- ch
  ∙ p ∈ voteIds (s .history) b
    ──────────────────────────
    tr ∋⋯ ≡[ p ▷ b , ch ]

hasVoted : TraceInvariant HasVoted
hasVoted (_ , refl , (_ ∎)) _ ()
hasVoted {s′} (_ , init , (_ ⟨ st ∣ s ⟩←— tr))
  {p}{b}{ch} b↝ p∈
  with IH ← hasVoted (_ , init , tr) {p}{b}{ch} b↝
  with st
... | Deliver _ = IH p∈
... | AdvanceEpoch = IH p∈
... | Drop _ = IH p∈
... | LocalStep (FinalizeBlock _ _ _ _)
  = there $ IH p∈
... | LocalStep (RegisterVote _ _)
  = there $ IH p∈
... | LocalStep s→@(ProposeBlock {ch = ch↓} {txs = txs} _ _ _ (_ ∷ _ ⊣ B↝))
  = QED
  where
  open ∣ProposeBlock∣ p s ch↓ txs

  QED : Any ≡[ p ▷ b , ch ] ((_ ⊢ s→) ∷ allLocalSteps tr)
  QED
    with b ≟ B
  ... | no _ = there $ IH p∈
  ... | yes refl
    with ⟫ p∈
  ... | ⟫ there p∈
    = there $ IH p∈
  ... | ⟫ here refl
    = here $′ refl , refl , just bch≡
      where
      bch≡ : (b , ch) ≡ (B , ch↓)
      bch≡ = cong (_ ,_) $ connects-to≡ b↝ B↝
... | LocalStep s→@(VoteBlock {ch = ch↓} {txs = txs} _ _ _ _ _ (_ ∷ _ ⊣ B↝))
  = QED
  where
  open ∣VoteBlock∣ p s ch↓ txs

  QED : Any ≡[ p ▷ b , ch ] ((_ ⊢ s→) ∷ allLocalSteps tr)
  QED
    with b ≟ B
  ... | no _ = there $ IH p∈
  ... | yes refl
    with ⟫ p∈
  ... | ⟫ there p∈
    = there $ IH p∈
  ... | ⟫ here refl
    = here $′ refl , refl , just bch≡
      where
      bch≡ : (b , ch) ≡ (B , ch↓)
      bch≡ = cong (_ ,_) $ connects-to≡ b↝ B↝
... | DishonestLocalStep {p = p′}{m} ¬hp′ h⇒m∈
  = QED
  where
  open ∣DishonestLocalStep∣ p p′ ¬hp′ s m

  ≪p∈ : p ∈ voteIds (s .history) b
  ≪p∈ with m ∙block ≟ b
  ... | no ≢b = voteIds-∷˘′ ≢b p∈
  ... | yes refl
    with m ∙pid ≟ p
  ... | no  ≢p = voteIds-∷˘ {ms = s .history} ≢p p∈
  ... | yes refl = voteIds-accept∈ (h⇒m∈ it) refl refl

  QED : Any ≡[ p ▷ b , ch ] (allLocalSteps tr)
  QED = IH ≪p∈

HasVotedInbox : TraceProperty
HasVotedInbox tr@(s , _) = ∀ {p m ch} ⦃ _ : Honest p ⦄ ⦃ _ : Honest (m ∙pid) ⦄ →
  let ls = s @ p in
  ∙ m ∙block -connects-to- ch
  ∙ m ∈ ls .inbox
    ─────────────────────────────────
    tr ∋⋯ ≡[ m ∙pid ▷ m ∙block , ch ]

hasVotedInbox : TraceInvariant HasVotedInbox
hasVotedInbox {s} Rs {p}{m}{ch} b↝ m∈ = hasVoted Rs b↝ p∈
  where
  m∈′ : m ∈ s .history
  m∈′ = inboxCompleteHonest Rs m∈

  p∈ : m ∙pid ∈ voteIds (s .history) (m ∙block)
  p∈ = L.Mem.∈-map⁺ _∙pid
     $ L.Mem.∈-filter⁺ (((m ∙block ≟_) ∘ _∙block)) m∈′ refl

Notarized∈ : TraceProperty
Notarized∈ tr@(s , _) = ∀ {p b ch} ⦃ _ : Honest p ⦄ →
  tr ∋⋯ ≡[ p ▷ b , ch ]
  ────────────────────────────────
  ch notarized-chain-∈ (s @ p) .db

notarized∈ : TraceInvariant Notarized∈
notarized∈ (_ , refl , (_ ∎)) ()
notarized∈ {s′} (_ , init , (_ ⟨ st ∣ s ⟩←— tr))
  {p}{b}{ch} st∈
  with IH ← notarized∈ (_ , init , tr) {p}{b}{ch} ⦃ it ⦄
  with st
... | Deliver {env = [ p′ ∣ m′ ⟩} env∈
  = QED
  where
  open ∣Deliver∣ p s env∈

  QED : ch notarized-chain-∈ (s′ @ p) .db
  QED
    with honest? p′
  ... | no _ = IH st∈
  ... | yes hp′
    with p ≟ p′
  ... | no p≢ rewrite lookup✖ ⦃ hp′ ⦄ p≢ = IH st∈
  ... | yes refl rewrite lookup✓ ⦃ it ⦄ = IH st∈
... | AdvanceEpoch
  rewrite let open ∣AdvanceEpoch∣ p s in lookup✓
  = IH st∈
... | Drop _ = IH st∈
... | LocalStep {p = p′}{mm}{ls′} ls→
  = QED
  where
  open ∣LocalStep∣ p p′ s mm ls′

  QED : ch notarized-chain-∈ (s′ @ p) .db
  QED with ⟫ ls→ | ⟫ st∈
  QED | ⟫ FinalizeBlock ch↓ _ _ _ | ⟫ there st∈
    with p ≟ p′
  ... | no p≢ rewrite lookup✖ p≢ = IH st∈
  ... | yes refl rewrite lookup✓ = IH st∈
  QED | ⟫ RegisterVote {sb = sb} M∈ M∉ | ⟫ there st∈
    with p ≟ p′
  ... | yes refl rewrite lookup✓ = notarized-chain-∈-∷ $ IH st∈
  ... | no p≢ rewrite lookup✖ p≢ = IH st∈
  QED | ⟫ ProposeBlock {ch = ch↓} {txs = txs} _ refl _ _ | ⟫ there st∈
    with p ≟ p′
  ... | no p≢ rewrite lookup✖ p≢ = IH st∈
  ... | yes refl rewrite lookup✓ = notarized-chain-∈-∷ $ IH st∈
  QED | ⟫ ProposeBlock {ch = ch↓} {txs = txs} _ refl (nch∈ , _) _
      | ⟫ here (refl , refl , just refl)
    with p ≟ p′
  ... | no p≢ rewrite lookup✖ p≢ = nch∈
  ... | yes refl rewrite lookup✓ = notarized-chain-∈-∷ nch∈
  QED | ⟫ VoteBlock {ch = ch↓} {txs = txs} M∈ _ _ _ _ _ | ⟫ there st∈
    with p ≟ p′
  ... | no p≢ rewrite lookup✖ p≢ = IH st∈
  ... | yes refl rewrite lookup✓ = notarized-chain-∈-∷ $ notarized-chain-∈-∷ $ IH st∈
  QED | ⟫ VoteBlock {ch = ch↓} {txs = txs} M∈ _ _ _ (nch∈ , _) _
      | ⟫ here (refl , refl , just refl)
    with p ≟ p′
  ... | no p≢ rewrite lookup✖ p≢ = nch∈
  ... | yes refl rewrite lookup✓ = notarized-chain-∈-∷ $ notarized-chain-∈-∷ nch∈
... | DishonestLocalStep {p = p′}{mm} ¬hp′ h⇒m∈
  = subst (_ notarized-chain-∈_) db≡ $ IH st∈
  where
  open ∣DishonestLocalStep∣ p p′ ¬hp′ s mm

IncreasingEpochs⋯ : TraceProperty
IncreasingEpochs⋯ tr = ∀ {p b ch b′ ch′} →
  ∙ length ch < length ch′
  ∙ tr ∋⋯ ≡[ p ▷ b  , ch  ]
  ∙ tr ∋⋯ ≡[ p ▷ b′ , ch′ ]
    ────────────────────────────
    b .epoch ≤ b′ .epoch

private pattern HERE = here (refl , refl , just refl)

increasingEpochs⋯ : TraceInvariant IncreasingEpochs⋯
increasingEpochs⋯ (_ , refl , (_ ∎)) _ ()
increasingEpochs⋯ {s′} (_ , init , (_ ⟨ st ∣ s ⟩←— tr))
  {p}{b}{ch}{b′}{ch′} len< st∈ st∈′
  with IH ← increasingEpochs⋯ (_ , init , tr) {p}{b}{ch}{b′}{ch′} len<
  with IH-noFutVot ← noFutureVotes≤ (_ , init , tr) {p}
  with IH-hasVot ← hasVoted˘ (_ , init , tr) {p}
  with IH-not∈ ← notarized∈ (_ , init , tr)
  with st
... | Deliver _ = IH st∈ st∈′
... | AdvanceEpoch = IH st∈ st∈′
... | Drop _ = IH st∈ st∈′
... | LocalStep ls→
  = QED
  where
  QED : b .epoch ≤ b′ .epoch
  QED with ⟫ ls→ | ⟫ st∈ | ⟫ st∈′
  QED | ⟫ FinalizeBlock _ _ _ _ | ⟫ there st∈ | ⟫ there st∈′ = IH st∈ st∈′
  QED | ⟫ RegisterVote _ _ | ⟫ there st∈ | ⟫ there st∈′ = IH st∈ st∈′
  QED | ⟫ ProposeBlock _ _ _ _ | ⟫ there st∈ | ⟫ there st∈′ = IH st∈ st∈′
  QED | ⟫ ProposeBlock _ _ _ _ | ⟫ HERE | ⟫ HERE
    = ⊥-elim $ Nat.<-irrefl refl len<
  QED | ⟫ ProposeBlock {ch = ch↓} {txs = txs} _ _ (_ , mkLongest∈ lch) _
      | ⟫ HERE | ⟫ there st∈′
    = ⊥-elim $ Nat.<⇒≱ len< len≥
    where
    open ∣ProposeBlock∣ p s ch↓ txs

    ch∈′ : ch′ notarized-chain-∈ ((s @ p) .db)
    ch∈′ = IH-not∈ st∈′

    len≥ : length ch↓ ≥ length ch′
    len≥ = lch ch∈′
  QED | ⟫ ProposeBlock {ch = ch↓} {txs = txs} _ refl _ _ | ⟫ there st∈ | ⟫ HERE
    = IH-noFutVot p∈
    where
    open ∣ProposeBlock∣ p s ch↓ txs

    p∈ : L ∈ voteIds (s .history) b
    p∈ = IH-hasVot st∈
  QED | ⟫ VoteBlock _ _ _ _ _ _ | ⟫ there st∈ | ⟫ there st∈′ = IH st∈ st∈′
  QED | ⟫ VoteBlock _ _ _ _ _ _ | ⟫ HERE | ⟫ HERE
    = ⊥-elim $ Nat.<-irrefl refl len<
  QED | ⟫ VoteBlock {ch = ch↓} {txs = txs} _ _ _ _ (_ , mkLongest∈ lch) _ | ⟫ HERE | ⟫ there st∈′
    = ⊥-elim $ Nat.<⇒≱ len< len≥
    where
    open ∣VoteBlock∣ p s ch↓ txs

    ch∈′ : ch′ notarized-chain-∈ ((s @ p) .db)
    ch∈′ = IH-not∈ st∈′

    len≥ : length ch↓ ≥ length ch′
    len≥ = lch ch∈′
  QED | ⟫ VoteBlock {ch = ch} {txs = txs} _ _ _ _ _ _ | ⟫ there st∈ | ⟫ HERE
    = IH-noFutVot p∈
    where
    open ∣VoteBlock∣ p s ch txs

    p∈ : p ∈ voteIds (s .history) b
    p∈ = IH-hasVot st∈
... | DishonestLocalStep _ _ = IH st∈ st∈′