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

module Jolteon.Properties.Steps.Phases ( : _) (open Assumptions ) where

open import Jolteon 
open import Jolteon.Properties.Steps.Core 
open import Jolteon.Properties.State 

-- ** Relating phases to step properties.

Proposing⇒StepInits :  (st : Step) 
  (st ∙end) .phase  Proposing
  ────────────────────────────
  StepInits st
Proposing⇒StepInits (_  InitTC _ _) _ = tt
Proposing⇒StepInits (_  InitNoTC _ _) _ = tt
Proposing⇒StepInits (_  EnoughTimeouts ph≡′ _ _ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
Proposing⇒StepInits (_  TimerExpired ph≡′ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
Proposing⇒StepInits ((_ , _ , ls , _)  VoteBlock _ _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡
Proposing⇒StepInits ((_ , _ , ls , _)  VoteBlockNoOp _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡

Receiving⇒StepReceiving :  (st : Step)  let ls = st ∙end in
  ls .phase  Receiving
  ────────────────────────────
    StepReceiving st
   ls .roundAdvanced?  false
Receiving⇒StepReceiving (_  ProposeBlock _ _) _ = inj₁ tt
Receiving⇒StepReceiving (_  ProposeBlockNoOp _ _) _ = inj₁ tt
Receiving⇒StepReceiving (_  EnoughTimeouts ph≡′ _ _ _) _ = inj₁ tt
Receiving⇒StepReceiving (_  TimerExpired ph≡′ _) _ = inj₁ tt
Receiving⇒StepReceiving ((_ , _ , ls , _)  VoteBlock _ _ _) ph≡
  with ls .roundAdvanced?
... | false = inj₂ refl
... | true  = inj₁ $ contradict ph≡
Receiving⇒StepReceiving ((_ , _ , ls , _)  VoteBlockNoOp _ _) ph≡
  with ls .roundAdvanced?
... | false = inj₂ refl
... | true  = inj₁ $ contradict ph≡

AdvancingRound⇒StepRegisters :  (st : Step)   let ls = st ∙end in
  ls .phase  AdvancingRound
  ──────────────────────────
    StepRegisters st
   ls .roundAdvanced?  true
AdvancingRound⇒StepRegisters (_  RegisterTC _ _ _ _) _ = inj₁ tt
AdvancingRound⇒StepRegisters (_  RegisterProposal _ _ _ _ _) _ = inj₁ tt
AdvancingRound⇒StepRegisters (_  RegisterTimeout _ _ _ _) _ = inj₁ tt
AdvancingRound⇒StepRegisters (_  RegisterVote _ _ _ _ _ _) _ = inj₁ tt
AdvancingRound⇒StepRegisters (_  EnoughTimeouts ph≡′ _ _ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
AdvancingRound⇒StepRegisters (_  TimerExpired ph≡′ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
AdvancingRound⇒StepRegisters ((_ , _ , ls , _)  VoteBlock _ _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡
AdvancingRound⇒StepRegisters ((_ , _ , ls , _)  VoteBlockNoOp _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡
AdvancingRound⇒StepRegisters (_  AdvanceRoundQC _ _ _) _ = inj₂ refl
AdvancingRound⇒StepRegisters (_  AdvanceRoundTC _ _ _) _ = inj₂ refl

AdvancingRound⇒StepAdvances* :  (st : Step)   let ls = st ∙end in
  ls .phase  AdvancingRound
  ──────────────────────────
    StepAdvances* st
AdvancingRound⇒StepAdvances* (_  RegisterProposal _ _ _ _ _) _ = tt
AdvancingRound⇒StepAdvances* (_  RegisterVote _ _ _ _ _ _) _ = tt
AdvancingRound⇒StepAdvances* (_  RegisterTimeout _ _ _ _) _ = tt
AdvancingRound⇒StepAdvances* (_  RegisterTC _ _ _ _) _ = tt
AdvancingRound⇒StepAdvances* (_  EnoughTimeouts ph≡′ _ _ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
AdvancingRound⇒StepAdvances* (_  TimerExpired ph≡′ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
AdvancingRound⇒StepAdvances* (_  AdvanceRoundQC _ _ _) _ = tt
AdvancingRound⇒StepAdvances* (_  AdvanceRoundTC _ _ _) _ = tt
AdvancingRound⇒StepAdvances* ((_ , _ , ls , _)  VoteBlock _ _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡
AdvancingRound⇒StepAdvances* ((_ , _ , ls , _)  VoteBlockNoOp _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡

Locking⇒StepAdvances :  (st : Step) 
  (st ∙end) .phase  Locking
  ──────────────────────────
  StepAdvances st
Locking⇒StepAdvances (_  AdvanceRoundNoOp _ _ _) _ = tt
Locking⇒StepAdvances (_  EnoughTimeouts ph≡′ _ _ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
Locking⇒StepAdvances (_  TimerExpired ph≡′ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
Locking⇒StepAdvances ((_ , _ , ls , _)  VoteBlock _ _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡
Locking⇒StepAdvances ((_ , _ , ls , _)  VoteBlockNoOp _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡

Committing⇒StepLocks∗ :  (st : Step) 
  (st ∙end) .phase  Committing
  ─────────────────────────────
  StepLocks∗ st
Committing⇒StepLocks∗ (_  Lock _ _) _ = tt
Committing⇒StepLocks∗ (_  EnoughTimeouts ph≡′ _ _ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
Committing⇒StepLocks∗ (_  TimerExpired ph≡′ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
Committing⇒StepLocks∗ ((_ , _ , ls , _)  VoteBlock _ _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡
Committing⇒StepLocks∗ ((_ , _ , ls , _)  VoteBlockNoOp _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡

Voting⇒StepCommits∗ :  (st : Step) 
  (st ∙end) .phase  Voting
  ─────────────────────────
  StepCommits∗ st
Voting⇒StepCommits∗ (_  Commit _ _) _ = tt
Voting⇒StepCommits∗ (_  CommitNoOp _ _) _ = tt
Voting⇒StepCommits∗ (_  EnoughTimeouts ph≡′ _ _ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
Voting⇒StepCommits∗ (_  TimerExpired ph≡′ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
Voting⇒StepCommits∗ ((_ , _ , ls , _)  VoteBlock _ _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡
Voting⇒StepCommits∗ ((_ , _ , ls , _)  VoteBlockNoOp _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = contradict ph≡

EnteringRound⇒StepVotes∗ :  (st : Step)  let ls = st ∙end in
  ls .phase  EnteringRound
  ──────────────────────────────────────
  StepVotes∗ st × T (ls .roundAdvanced?)
EnteringRound⇒StepVotes∗ (_  EnoughTimeouts ph≡′ _ _ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
EnteringRound⇒StepVotes∗ (_  TimerExpired ph≡′ _) ph≡ =
  contradict $ trans (sym ph≡) ph≡′
EnteringRound⇒StepVotes∗ ((_ , _ , ls , _)  VoteBlock _ _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = tt , tt
EnteringRound⇒StepVotes∗ ((_ , _ , ls , _)  VoteBlockNoOp _ _) ph≡
  with ls .roundAdvanced?
... | false = contradict ph≡
... | true  = tt , tt

-- ** Relating phases to the state's `roundAdvanced?` flag.

EnteringRound⇒roundAdvanced :  {s}   _ : Honest p   Reachable s  let ls = s  p in
  ls .phase  EnteringRound
  ─────────────────────────
  ls .roundAdvanced?  true
EnteringRound⇒roundAdvanced {p} (_ , refl , (_ )) ph≡
  rewrite pLookup-replicate p initLocalState
  = refl
EnteringRound⇒roundAdvanced {p}  hp  (_ , s-init , (s′  st  s ⟩←— tr)) ph≡
  with Rs_ , s-init , tr
  with IHEnteringRound⇒roundAdvanced {p} Rs
  with st
... | WaitUntil _ _ _
  = IH ph≡
... | Deliver {tpm} _
  = subst (_≡ true) (sym $ receiveMsg-roundA (honestTPMessage tpm))
  $ IH (subst (_≡ _) (receiveMsg-phase (honestTPMessage tpm)) ph≡)
... | DishonestLocalStep  _ _
  = IH ph≡
... | LocalStep {p = p′} {ls′ = ls′} st
  with p  p′
... | no p≢ rewrite pLookup∘updateAt′ p p′ {const ls′} (p≢  ↑-injective) (s .stateMap)
  = IH ph≡
... | yes refl rewrite pLookup∘updateAt p  hp  {const ls′} (s .stateMap)
  with st | (st ∙end) .roundAdvanced? | EnteringRound⇒StepVotes∗ ((_  st)  hp ⦄) ph≡
... | VoteBlock _ _ _   | true | tt , tt = refl
... | VoteBlockNoOp _ _ | true | tt , tt = refl

Proposing⇒¬roundAdvanced :  {s}   _ : Honest p   Reachable s  let ls = s  p in
  ls .phase  Proposing
  ──────────────────────────
  ls .roundAdvanced?  false
Proposing⇒¬roundAdvanced {p} (_ , refl , (_ )) ph≡
  rewrite pLookup-replicate p initLocalState
  = contradict ph≡
Proposing⇒¬roundAdvanced {p}  hp  (_ , s-init , (s′  st  s ⟩←— tr)) ph≡
  with Rs_ , s-init , tr
  with IHProposing⇒¬roundAdvanced {p} Rs
  with st
... | WaitUntil _ _ _
  = IH ph≡
... | Deliver {tpm} _
  = subst (_≡ false) (sym $ receiveMsg-roundA (honestTPMessage tpm))
  $ IH (subst (_≡ _) (receiveMsg-phase (honestTPMessage tpm)) ph≡)
... | DishonestLocalStep _ _
  = IH ph≡
... | LocalStep {p = p′} {ls′ = ls′} st
  with p  p′
... | no p≢ rewrite pLookup∘updateAt′ p p′ {const ls′} (p≢  ↑-injective) (s .stateMap)
  = IH ph≡
... | yes refl rewrite pLookup∘updateAt p  hp  {const ls′} (s .stateMap)
  with st | Proposing⇒StepInits ((_  st)  hp ⦄) ph≡
... | InitTC _ _   | tt = refl
... | InitNoTC _ _ | tt = refl

Receiving⇒¬roundAdvanced :  {s}   _ : Honest p   Reachable s  let ls = s  p in
  ls .phase  Receiving
  ──────────────────────────
  ls .roundAdvanced?  false
Receiving⇒¬roundAdvanced {p} (_ , refl , (_ )) ph≡
  rewrite pLookup-replicate p initLocalState
  = contradict ph≡
Receiving⇒¬roundAdvanced {p}  hp  (_ , s-init , (s′  st  s ⟩←— tr)) ph≡
  with Rs_ , s-init , tr
  with IHReceiving⇒¬roundAdvanced {p} Rs
  with st
... | WaitUntil _ _ _
  = IH ph≡
... | Deliver {tpm} _
  = subst (_≡ false) (sym $ receiveMsg-roundA (honestTPMessage tpm))
  $ IH (subst (_≡ _) (receiveMsg-phase (honestTPMessage tpm)) ph≡)
... | DishonestLocalStep _ _
  = IH ph≡
... | LocalStep {p = p′} {ls′ = ls′} st
  with p  p′
... | no p≢ rewrite pLookup∘updateAt′ p p′ {const ls′} (p≢  ↑-injective) (s .stateMap)
  = IH ph≡
... | yes refl rewrite pLookup∘updateAt p  hp  {const ls′} (s .stateMap)
  with st | Receiving⇒StepReceiving ((_  st)  hp ⦄) ph≡
... | ProposeBlock ph≡ _     | inj₁ tt = Proposing⇒¬roundAdvanced  hp  Rs ph≡
... | ProposeBlockNoOp ph≡ _ | inj₁ tt = Proposing⇒¬roundAdvanced  hp  Rs ph≡
... | EnoughTimeouts _ _ _ _ | inj₁ tt = IH ph≡
... | TimerExpired _ _       | inj₁ tt = IH ph≡
... | _                      | inj₂ r≡ = r≡

AdvancingRound⇒¬roundAdvanced :  {s}  Reachable s 
  (ssr : s  StepRegisters) 
  ──────────────────────────
  let (st , _ ) = ssr ; (_ , _ , _ , _ , ls′) = stepArgs st in
  ls′ .roundAdvanced?  false
AdvancingRound⇒¬roundAdvanced Rs ((_  st) , refl , refl , x)
  with st | x
... | RegisterProposal _ ph≡ _ _ _ | tt = Receiving⇒¬roundAdvanced Rs ph≡
... | RegisterVote _ ph≡ _ _ _ _ | tt =  Receiving⇒¬roundAdvanced Rs ph≡
... | RegisterTimeout _ ph≡ _ _ | tt =  Receiving⇒¬roundAdvanced Rs ph≡
... | RegisterTC _ ph≡ _ _ | tt =  Receiving⇒¬roundAdvanced Rs ph≡