{-# OPTIONS --safe #-}
open import Prelude
open import Hash
open import Jolteon.Assumptions

module Jolteon.Properties.Safety.Lemma2 ( : _) (open Assumptions ) where

open import Jolteon 
  hiding (begin_; _∎)
open import Jolteon.Properties.Core 
open import Jolteon.Properties.State 
open import Jolteon.Properties.Votes 
open import Jolteon.Properties.QuorumIntersection 
open import Jolteon.Properties.Steps 

open import Jolteon.Properties.Safety.Core 
open import Jolteon.Properties.Safety.Lemma1 

-- Lemma 2
GDB⇒qcHighRound :  {s}  Reachable s 
  -- If a block B is globally direct-committed...
   GloballyDirectCommitted s b
  -- ...then any higher-round TC...
   tc ∙∈ s .history
   b ∙round < tc ∙round
    ──────────────────────────────
  -- ...contains qc-high of round at least B.r.
    b ∙round  highestQC tc ∙round
{- Proof:
  The TC has a majority of timeout messages.

  Because b is GDC, MoreThanF-Honest voted for b' (s.t. b ←— b′),
  and therefore executed the lock step in B'.r = B.r+1,
  and set qc_high to the QC certifying b.

  By quorum intersection, one of timeout messages in tc was sent by
  one of the honest replicas (say p) that executed the lock step in B.r+1

  Hence p set qc_high to a QC of round (b ∙round) *and* voted for the TC.

  Since qc_high never decreases, highestQC tc ∙round is at least b ∙round.
-}
GDB⇒qcHighRound {b = b} {tc = tc} {s = s} Rs dcb tc∈ br<
  with bᵣ₊₁ , refl , b←bᵣ₊₁@(refl , refl) , hon-bᵣ₊₁dcb
  with p , hp , p∈ , p∈'quorumIntersection (getUniqueTC tc)
                         (Unique-nub {xs = honestVotes' bᵣ₊₁ (s. history)})
                         (majority-map⁺ (tc .tes) node (getQuorumTC tc))
                         hon-bᵣ₊₁
                         (Honest-honestVotes  bᵣ₊₁ (s. history))
  with  sᵣ₊₁ , Rsᵣ₊₁ , s←sᵣ₊₁ , eqᵣ₊  , stᵣ₊₁ , refl , refl , stVotestraceRs▷ Rs (honestVote⇒StepVotes Rs p∈')
  with te , te∈ , reflL.Mem.find (L.Any.map⁻ p∈)
  with  sₜₑ  , Rsₜₑ  , s←sₜₑ  , eqₜₑ  , stₜₑ , ⟪sₜₑ , refl , refl , refl , stTimeouttraceRs◃ Rs (te∈tc⇒Timeout Rs  hp  tc∈ refl te∈)
  = QED
  where
  trEᵣ₊₁ trEₜₑ : TraceExtension Rs
  trEᵣ₊₁ =  sᵣ₊₁ , Rsᵣ₊₁ , s←sᵣ₊₁ , eqᵣ₊ 
  trEₜₑ  =  sₜₑ  , Rsₜₑ  , s←sₜₑ  , eqₜₑ 

  qcb : QC
  qcb = bᵣ₊₁ .blockQC

  qctc : QC
  qctc = te ∙qcTE

  qctc≤ : qctc ≤qc highestQC tc
  qctc≤ = highestQC-correct tc (qcTE-lemma {tc = tc} te∈)

  lsᵣ₊₁ : LocalState
  lsᵣ₊₁ = sᵣ₊₁ @ʰ hp

  sᵣ₊₁▷Voting : sᵣ₊₁  StepVotes p bᵣ₊₁
  sᵣ₊₁▷Voting = stᵣ₊₁ , refl , refl , stVotes

  -- * voting for bᵣ₊₁ ⇒ qc-high set to qcb
  qcb≡qc-high : qcb ∙round  (lsᵣ₊₁ .qc-high) ∙round
  qcb≡qc-high = vote-qc-high {b = bᵣ₊₁}  hp  Rsᵣ₊₁ sᵣ₊₁▷Voting refl

  lsₜₑ : LocalState
  lsₜₑ = sₜₑ @ʰ hp

  Timeout◃sₜₑ : StepTimeout p te  sₜₑ
  Timeout◃sₜₑ = stₜₑ , ⟪sₜₑ , refl , refl , refl , stTimeout

  qctc≡qc-high : qctc  lsₜₑ .qc-high
  qctc≡qc-high = timeout-qc-high {s = sₜₑ} {te = te}  hp  Timeout◃sₜₑ

  shouldVote : ShouldVote lsᵣ₊₁ bᵣ₊₁
  shouldVote = StepVotes⇒ShouldVote′ {s = sᵣ₊₁}  hp  sᵣ₊₁▷Voting

  rcur>rvote : lsᵣ₊₁ .r-cur > lsᵣ₊₁ .r-vote
  rcur>rvote = let eq , r> , _ = shouldVote in
    subst (suc (lsᵣ₊₁ .r-vote) ≤_) eq r>

  rvote>rcur : sᵣ₊₁ ↞— sₜₑ  lsᵣ₊₁ .r-cur < lsᵣ₊₁ .r-vote
  rvote>rcur sᵣ₊₁←sₜₑ =
    Nat.≤-reflexive $ timedOut?⇒r-cur-vote  hp  Rsₜₑ Timeout◃sₜₑ sᵣ₊₁←sₜₑ ter≡r-cur
    where
    r-cur≤ : lsₜₑ .r-cur  lsᵣ₊₁ .r-cur
    r-cur≤ = r-cur-mono  hp  sᵣ₊₁←sₜₑ

    ter≡tcr : te ∙round  tc ∙round
    ter≡tcr = L.All.lookup (getAllRound tc) te∈

    tc≡ : tc ∙round  lsₜₑ .r-cur
    tc≡ = let open ≡-Reasoning in
      begin
        tc ∙round
      ≡˘⟨ ter≡tcr 
        te ∙round
      ≡⟨ timeout-r-cur {s = sₜₑ}  hp  Timeout◃sₜₑ 
        lsₜₑ .r-cur
      

    r-curᵣ₊₁≡r : bᵣ₊₁ ∙round  lsᵣ₊₁ .r-cur
    r-curᵣ₊₁≡r = shouldVote .proj₁

    tc< : tc ∙round  1 + b ∙round
    tc< = let open Nat.≤-Reasoning in
      begin
        tc ∙round
      ≡⟨ tc≡ 
        lsₜₑ .r-cur
      ≤⟨ r-cur≤ 
        lsᵣ₊₁ .r-cur
      ≡˘⟨ r-curᵣ₊₁≡r 
        1 + b ∙round
      

    ter≡r-cur : te ∙round  lsᵣ₊₁ .r-cur
    ter≡r-cur = let open ≡-Reasoning in
      begin
        te ∙round
      ≡⟨ ter≡tcr 
        tc ∙round
      ≡⟨ Nat.≤-antisym tc< br< 
        1 + b ∙round
      ≡⟨ r-curᵣ₊₁≡r 
        lsᵣ₊₁ .r-cur
      

  sₜₑ←sᵣ₊₁ : sₜₑ ↞— sᵣ₊₁
  sₜₑ←sᵣ₊₁ = case (factorRs Rs trEᵣ₊₁ trEₜₑ) of λ where
    (inj₁ sᵣ₊₁←sₜₑ)  ⊥-elim (Nat.<-asym rcur>rvote (rvote>rcur sᵣ₊₁←sₜₑ))
    (inj₂ sₜₑ←sᵣ₊₁)  sₜₑ←sᵣ₊₁

  qc-high≤ : lsᵣ₊₁ .qc-high ≤qc lsₜₑ .qc-high
  qc-high≤ = qc-high-mono  hp  Rsᵣ₊₁ sₜₑ←sᵣ₊₁

  open Nat.≤-Reasoning

  qcb≤ : qcb ≤qc qctc
  qcb≤ = let open Nat.≤-Reasoning in
    begin
      qcb ∙round
    ≡⟨ qcb≡qc-high 
      lsᵣ₊₁ .qc-high ∙round
    ≤⟨ qc-high≤ 
      lsₜₑ .qc-high ∙round
    ≡˘⟨ cong _∙round qctc≡qc-high 
      qctc ∙round
    

  QED : b ∙round  highestQC tc ∙round
  QED = let open Nat.≤-Reasoning in
    begin
      b ∙round
    ≡⟨⟩
      qcb ∙round
    ≤⟨ qcb≤ 
      qctc ∙round
    ≤⟨ qctc≤ 
      highestQC tc ∙round