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

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

open import Jolteon ⋯
open import Jolteon.Decidability ⋯
open import Jolteon.Properties.State.Invariants ⋯
open import Jolteon.Properties.State.Messages ⋯

-- ** Characterizing subset of local steps

StepVotes : Pid → Block → LocalStepProperty
StepVotes p b ((_p , _) ⊢ st) = case st of λ where
  (VoteBlock {b = _b} _ _ _) → p ≡ _p × b ≡ _b
  _ → ⊥

StepVotes′ : Pid → QC → LocalStepProperty
StepVotes′ p qc ((_p , _) ⊢ st) = case st of λ where
  (VoteBlock{b = b} _ _ _) → p ≡ _p × qc ∙blockId ≡ b ∙blockId × qc ∙round ≡ b ∙round
  _ → ⊥


StepCommits : Block → LocalStepProperty
StepCommits b (_ ⊢ st) = case st of λ where
  (Commit _ (final∈ {b = _b} _ _ _ _ , _)) → b ≡ _b
  _ → ⊥

StepCommits∈ : Block → LocalStepProperty
StepCommits∈ b (_ ⊢ st) = case st of λ where
  (Commit {ch = ch} _ _) → b ∈ ch
  _ → ⊥

StepCommitsRound> : Pid → Round → LocalStepProperty
StepCommitsRound> p r ((_p , _) ⊢ st) = case st of λ where
  (Commit _ (final∈ {b = _b} _ _ _ _ , _)) → p ≡ _p × r < _b ∙round
  _ → ⊥

StepProposes : Block → LocalStepProperty
StepProposes b ((_ , _ , ls , _) ⊢ st) = case st of λ where
  (ProposeBlock {txn = txn} _ _) → b ≡ mkBlockForState ls txn
  _ → ⊥

StepLocks : Pid → QC → LocalStepProperty
StepLocks p qc ((_p , _) ⊢ st) = case st of λ where
  (Lock {qc = _qc} _ _) → p ≡ _p × qc ≡ _qc
  _ → ⊥

StepAdvancesQC : Pid → QC → LocalStepProperty
StepAdvancesQC p qc ((_p , _) ⊢ st) = case st of λ where
  (AdvanceRoundQC {qc = _qc} _ _ _) → p ≡ _p × qc ≡ _qc
  _ → ⊥

StepInitsTC : TC → LocalStepProperty
StepInitsTC tc ((_ , _ , _ , _) ⊢ st) = case st of λ where
  (InitTC {tc = _tc} _ _) → tc ≡ _tc
  _ → ⊥

StepTimeout : Pid → TimeoutEvidence → LocalStepProperty
StepTimeout p te ((_p , _ , ls , _) ⊢ st) =
  let P = p ≡ _p × te ≡ signData p (ls .r-cur , ls .qc-high) in
  case st of λ where
  (TimerExpired _ _) → P
  (EnoughTimeouts _ _ _ _) → P
  _ → ⊥

StepRegisterProposal : Pid → Proposal → LocalStepProperty
StepRegisterProposal p sb ((_p , _ , _ , _) ⊢ st) =  case st of λ where
  (RegisterProposal {sb = _sb} _ _ _ _ _) → p ≡ _p × sb ≡ _sb
  _ → ⊥

StepInits StepReceiving StepRegisters StepAdvancesLoop StepAdvances StepAdvances* StepLocks∗ StepCommits∗ StepVotes∗
  : LocalStepProperty
StepInits (_ ⊢ st) = case st of λ where
  (InitTC _ _) → ⊤
  (InitNoTC _ _) → ⊤
  _ → ⊥
StepReceiving (_ ⊢ st) = case st of λ where
  (ProposeBlock _ _) → ⊤
  (ProposeBlockNoOp _ _) → ⊤
  (EnoughTimeouts _ _ _ _) → ⊤
  (TimerExpired _ _) → ⊤
  _ → ⊥
StepRegisters (_ ⊢ st) = case st of λ where
  (RegisterTC _ _ _ _) → ⊤
  (RegisterProposal _ _ _ _ _) → ⊤
  (RegisterTimeout _ _ _ _) → ⊤
  (RegisterVote _ _ _ _ _ _) → ⊤
  _ → ⊥

StepAdvancesLoop (_ ⊢ st) = case st of λ where
  (AdvanceRoundQC _ _ _) → ⊤
  (AdvanceRoundTC _ _ _) → ⊤
  _ → ⊥

StepAdvances* (_ ⊢ st) = case st of λ where
  (RegisterTC _ _ _ _) → ⊤
  (RegisterProposal _ _ _ _ _) → ⊤
  (RegisterTimeout _ _ _ _) → ⊤
  (RegisterVote _ _ _ _ _ _) → ⊤
  (AdvanceRoundQC _ _ _) → ⊤
  (AdvanceRoundTC _ _ _) → ⊤
  _ → ⊥


StepAdvances (_ ⊢ st) = case st of λ where
  (AdvanceRoundNoOp _ _ _) → ⊤
  _ → ⊥
StepLocks∗ (_ ⊢ st) = case st of λ where
  (Lock _ _) → ⊤
  _ → ⊥
StepCommits∗ (_ ⊢ st) = case st of λ where
  (Commit _ _) → ⊤
  (CommitNoOp _ _) → ⊤
  _ → ⊥
StepVotes∗ (_ ⊢ st) = case st of λ where
  (VoteBlock _ _ _) → ⊤
  (VoteBlockNoOp _ _) → ⊤
  _ → ⊥

-- ** Decidability of step properties

StepVotes? : ∀ p b st → Dec (StepVotes p b st)
StepVotes? p b ((_p , _) ⊢ st) with st
... | InitTC _ _ = no λ ()
... | InitNoTC _ _ = no λ ()
... | ProposeBlock _ _ = no λ ()
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = no λ ()
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = no λ ()
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC _ _ _ = no λ ()
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock _ _ = no λ ()
... | Commit _ _ = no λ ()
... | CommitNoOp _ _ = no λ ()
... | VoteBlock {b = _b} _ _ _ = ¿ p ≡ _p × b ≡ _b ¿
... | VoteBlockNoOp _ _ = no λ ()

StepVotes′? : ∀ p qc st → Dec (StepVotes′ p qc st)
StepVotes′? p qc ((_p , _) ⊢ st) with st
... | InitTC _ _ = no λ ()
... | InitNoTC _ _ = no λ ()
... | ProposeBlock _ _ = no λ ()
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = no λ ()
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = no λ ()
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC _ _ _ = no λ ()
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock _ _ = no λ ()
... | Commit _ _ = no λ ()
... | CommitNoOp _ _ = no λ ()
... | VoteBlock {b = b} _ _ _ = ¿ p ≡ _p × qc ∙blockId ≡ b ∙blockId × qc ∙round ≡ b ∙round ¿
... | VoteBlockNoOp _ _ = no λ ()

StepCommits? : Decidable² StepCommits
StepCommits? b (_ ⊢ st) with st
... | InitTC _ _ = no λ ()
... | InitNoTC _ _ = no λ ()
... | ProposeBlock _ _ = no λ ()
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = no λ ()
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = no λ ()
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC _ _ _ = no λ ()
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock _ _ = no λ ()
... | Commit _ (final∈ {b = _b} _ _ _ _ , _) = b ≟ _b
... | CommitNoOp _ _ = no λ ()
... | VoteBlock _ _ _ = no λ ()
... | VoteBlockNoOp _ _ = no λ ()

StepCommitsRound? : ∀ p r st → Dec (StepCommitsRound> p r st)
StepCommitsRound? p r ((_p , _ ) ⊢ st) with st
... | InitTC _ _ = no λ ()
... | InitNoTC _ _ = no λ ()
... | ProposeBlock _ _ = no λ ()
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = no λ ()
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = no λ ()
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC _ _ _ = no λ ()
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock _ _ = no λ ()
... | Commit _ (final∈ {b = _b} _ _ _ _ , _) = ¿ p ≡ _p × r < _b ∙round ¿
... | CommitNoOp _ _ = no λ ()
... | VoteBlock _ _ _ = no λ ()
... | VoteBlockNoOp _ _ = no λ ()

StepCommits∈? : Decidable² StepCommits∈
StepCommits∈? b (_ ⊢ st) with st
... | InitTC _ _ = no λ ()
... | InitNoTC _ _ = no λ ()
... | ProposeBlock _ _ = no λ ()
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = no λ ()
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = no λ ()
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC _ _ _ = no λ ()
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock _ _ = no λ ()
... | Commit {ch = ch} _ _ = b ∈? ch
... | CommitNoOp _ _ = no λ ()
... | VoteBlock _ _ _ = no λ ()
... | VoteBlockNoOp _ _ = no λ ()

StepProposes? : Decidable² StepProposes
StepProposes? b ((_ , _ , ls , _ ) ⊢ st) with st
... | InitTC _ _ = no λ ()
... | InitNoTC _ _ = no λ ()
... | ProposeBlock {txn = txn} _ _ = b ≟ mkBlockForState ls txn
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = no λ ()
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = no λ ()
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC _ _ _ = no λ ()
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock _ _ = no λ ()
... | Commit _ _ = no λ ()
... | CommitNoOp _ _ = no λ ()
... | VoteBlock _ _ _ = no λ ()
... | VoteBlockNoOp _ _ = no λ ()

StepLocks? : ∀ x y z → Dec (StepLocks x y z)
StepLocks? p qc ((_p , _ , ls , _ ) ⊢ st) with st
... | InitTC _ _ = no λ ()
... | InitNoTC _ _ = no λ ()
... | ProposeBlock _ _ = no λ ()
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = no λ ()
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = no λ ()
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC _ _ _ = no λ ()
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock {qc = _qc} _ _ = ¿ p ≡ _p × qc ≡ _qc ¿
... | Commit _ _ = no λ ()
... | CommitNoOp _ _ = no λ ()
... | VoteBlock _ _ _ = no λ ()
... | VoteBlockNoOp _ _ = no λ ()

StepAdvancesQC? : ∀ x y z → Dec (StepAdvancesQC x y z)
StepAdvancesQC? p qc ((_p , _ , ls , _ ) ⊢ st) with st
... | InitTC _ _ = no λ ()
... | InitNoTC _ _ = no λ ()
... | ProposeBlock _ _ = no λ ()
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = no λ ()
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = no λ ()
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC {qc = _qc} _ _ _ = ¿ p ≡ _p × qc ≡ _qc ¿
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock _ _ = no λ ()
... | Commit _ _ = no λ ()
... | CommitNoOp _ _ = no λ ()
... | VoteBlock _ _ _ = no λ ()
... | VoteBlockNoOp _ _ = no λ ()


StepInitsTC? : Decidable² StepInitsTC
StepInitsTC? tc ((_ , _ , ls , _ ) ⊢ st) with st
... | InitTC {tc = _tc} _ _ = tc ≟ _tc
... | InitNoTC _ _ = no λ ()
... | ProposeBlock _ _ = no λ ()
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = no λ ()
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = no λ ()
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC _ _ _ = no λ ()
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock _ _ = no λ ()
... | Commit _ _ = no λ ()
... | CommitNoOp _ _ = no λ ()
... | VoteBlock _ _ _ = no λ ()
... | VoteBlockNoOp _ _ = no λ ()

StepInits? : Decidable¹ StepInits
StepInits? (_ ⊢ st) with st
... | InitTC _ _ = yes tt
... | InitNoTC _ _ = yes tt
... | ProposeBlock _ _ = no λ ()
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = no λ ()
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = no λ ()
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC _ _ _ = no λ ()
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock _ _ = no λ ()
... | Commit _ _ = no λ ()
... | CommitNoOp _ _ = no λ ()
... | VoteBlock _ _ _ = no λ ()
... | VoteBlockNoOp _ _ = no λ ()

StepTimeout? : ∀ p te st → Dec (StepTimeout p te st)
StepTimeout? p te ((_p , _ , ls , _) ⊢ st)
  with P? ← ¿ p ≡ _p × te ≡ signData p (ls .r-cur , ls .qc-high) ¿
  with st
... | InitTC _ _ = no λ ()
... | InitNoTC _ _ = no λ ()
... | ProposeBlock _ _ = no λ ()
... | ProposeBlockNoOp _ _ = no λ ()
... | RegisterProposal _ _ _ _ _ = no λ ()
... | EnoughTimeouts _ _ _ _ = P?
... | RegisterTimeout _ _ _ _ = no λ ()
... | RegisterTC _ _ _ _ = no λ ()
... | TimerExpired _ _ = P?
... | RegisterVote _ _ _ _ _ _ = no λ ()
... | AdvanceRoundQC _ _ _ = no λ ()
... | AdvanceRoundTC _ _ _ = no λ ()
... | AdvanceRoundNoOp _ _ _ = no λ ()
... | Lock _ _ = no λ ()
... | Commit _ _ = no λ ()
... | CommitNoOp _ _ = no λ ()
... | VoteBlock _ _ _ = no λ ()
... | VoteBlockNoOp _ _ = no λ ()

-- ** Simple proofs about step properties.

StepVotes⇒ShouldVote : ∀ {s} (Rs : Reachable s) →
  Rs ∋⋯ StepVotes p b
  ────────────────────────
  ∃ λ ls → ShouldVote ls b
StepVotes⇒ShouldVote (s , s-init , (_ ⟨ WaitUntil _ _ _ ⟩←— tr)) st∈
  = StepVotes⇒ShouldVote (s , s-init , tr) st∈
StepVotes⇒ShouldVote (s , s-init , (_ ⟨ Deliver _ ⟩←— tr)) st∈
  = StepVotes⇒ShouldVote (s , s-init , tr) st∈
StepVotes⇒ShouldVote (s , s-init , (_ ⟨ DishonestLocalStep _ _ ⟩←— tr)) st∈
  = StepVotes⇒ShouldVote (s , s-init , tr) st∈
StepVotes⇒ShouldVote (s , s-init , (_ ⟨ LocalStep p ⟩←— tr))
  (there st∈)
  = StepVotes⇒ShouldVote (s , s-init , tr) st∈
StepVotes⇒ShouldVote (_ , _ , (_ ⟨ LocalStep {p = p} (VoteBlock _ _ sv) ∣ s ⟩←— tr))
  (here (refl , refl))
  = s @ p , sv

StepVotes⇒ShouldVote′ : ⦃ _ : Honest p ⦄ →
  s ▷ StepVotes p b
  ────────────────────
  ShouldVote (s @ p) b
StepVotes⇒ShouldVote′ (_ ⊢ VoteBlock _ _ sv , refl , refl , refl , refl) = sv

StepVotes⇒r≡ : ⦃ _ : Honest p ⦄ →
  StepVotes p b ◃ s
  ──────────────────────────
  b ∙round ≡ (s @ p) .r-vote
StepVotes⇒r≡ {p} ⦃ hp ⦄
  ((_ , _ , _ , _ , ls′) ⊢ VoteBlock _ _ (refl , _) , s , refl , refl , refl , refl , refl)
  rewrite pLookup∘updateAt p ⦃ hp ⦄ {const ls′} (s .stateMap)
  = refl

StepVotes⇒Voting : ⦃ _ : Honest p ⦄ →
  s ▷ StepVotes p b
  ───────────────────────
  (s @ p) .phase ≡ Voting
StepVotes⇒Voting (_ ⊢ VoteBlock ph _ _ , _ , refl , refl , _) = ph

StepVotes⇒b∈db : ⦃ _ : Honest p ⦄ →
  s ▷ StepVotes p b
  ─────────────────
  b ∙∈ (s @ p) .db
StepVotes⇒b∈db (_ ⊢ VoteBlock _ b∈ _ , refl , refl , refl , refl) = b∈

StepProposes⇒b∈ : ∀ {s} (Rs : Reachable s) →
  Rs ∋⋯ StepProposes b
  ─────────────────────────
  b ∙∈ s .history
StepProposes⇒b∈ (s , s-init , (_ ⟨ WaitUntil _ _ _ ⟩←— tr)) st∈
  = StepProposes⇒b∈ (s , s-init , tr) st∈
StepProposes⇒b∈ (s , s-init , (_ ⟨ Deliver _ ⟩←— tr)) st∈
  = StepProposes⇒b∈ (s , s-init , tr) st∈
StepProposes⇒b∈ (_ , s-init , (_ ⟨ DishonestLocalStep {env} _ _ ∣ s ⟩←— tr)) st∈
  = ∈-allBlocks-there {ms = s .history} {m = env .content}
  $ StepProposes⇒b∈ (_ , s-init , tr) st∈
StepProposes⇒b∈ (s , s-init , (_ ⟨ LocalStep {menv = me} p ⟩←— tr)) (there st∈)
  = ∈-allBlocks⁺ʳ {ms = L.fromMaybe (M.map _∙message me)}
  $ StepProposes⇒b∈ (s , s-init , tr) st∈
StepProposes⇒b∈ (_ , _ , (_ ⟨ LocalStep (ProposeBlock _ _) ⟩←— _)) (here px)
  = here px

{- NOT TRUE with Adversarial behaviour
b∈⇒StepProposes : ∀ {s} (Rs : Reachable s) →
  b ∙∈ s .history
  ────────────────────
  Rs ∋⋯ StepProposes b
b∈⇒StepProposes (_ , refl , (_ ∎)) b∈
  = contradict b∈
b∈⇒StepProposes (s , s-init , (_ ⟨ Deliver _ _ _ ⟩←— tr)) b∈
  = b∈⇒StepProposes (s , s-init , tr) b∈
b∈⇒StepProposes (s , s-init , (_ ⟨ DishonestLocalStep {env} _ _ ⟩←— tr)) b∈
  = {!!}
-- b∈⇒StepProposes (s , s-init , (_ ⟨ DishonestLocalStep {env} _ _ ⟩←— tr)) (here px)
--   = ?
-- b∈⇒StepProposes (s , s-init , (_ ⟨ DishonestLocalStep {env} _ _ ⟩←— tr)) (there b∈)
--   = b∈⇒StepProposes (s , s-init , tr) b∈
b∈⇒StepProposes {b} (_ , s-init , (_ ⟨ LocalStep st ⟩←— tr)) b∈
  with IH ← b∈⇒StepProposes {b} (_ , s-init , tr)
  with st
... | InitNoTC _ _
  = there $ IH b∈
... | ProposeBlockNoOp _ _
  = there $ IH b∈
... | RegisterProposal _ _ _ _ _
  = there $ IH b∈
... | RegisterVote _ _ _ _ _ _
  = there $ IH b∈
... | RegisterTimeout _ _ _ _
  = there $ IH b∈
... | RegisterTC _ _ _ _
  = there $ IH b∈
... | AdvanceRoundQC _ _ _
  = there $ IH b∈
... | AdvanceRoundTC _ _ _
  = there $ IH b∈
... | AdvanceRoundNoOp _ _ _
  = there $ IH b∈
... | Lock _ _
  = there $ IH b∈
... | Commit _ _
  = there $ IH b∈
... | CommitNoOp _ _
  = there $ IH b∈
... | VoteBlockNoOp _ _
  = there $ IH b∈
... | InitTC {tc = tc} _ _
  = there $ IH b∈
... | EnoughTimeouts _ _ _ _
  = there $ IH b∈
... | TimerExpired _ _
  = there $ IH b∈
... | VoteBlock _ _ _
  = there $ IH b∈
... | ProposeBlock {txn = txn} _ _
  with b∈
... | here  b≡ = here b≡
... | there b∈ = there $ IH b∈
-}

sb∈⇒StepRegisterProposal : ∀ {s} ⦃ _ : Honest p ⦄ → (Rs : Reachable s) →
  Propose sb ∈ (s @ p) .db
  ───────────────────────────────
  Rs ∋⋯ StepRegisterProposal p sb
sb∈⇒StepRegisterProposal {p = p} (_ , refl , (_ ∎)) pr∈
  rewrite pLookup-replicate p initLocalState
  = contradict pr∈
sb∈⇒StepRegisterProposal {p}{sb} ⦃ hp ⦄ (_ , s-init , _ ⟨ st ∣ s ⟩←— tr) pr∈
  -- with Rs ← _ , s-init , tr
  with IH ← sb∈⇒StepRegisterProposal {p}{sb} ⦃ hp ⦄ (_ , s-init , tr)
  with st
... | WaitUntil _ _ _
  = IH pr∈
... | Deliver {tpm} _
  rewrite receiveMsg-ls≡ {p = p}{s .stateMap} (honestTPMessage tpm)
  = IH pr∈
... | DishonestLocalStep _ _
  = IH pr∈
... | LocalStep {p = p′}{ls′ = ls′} st
  with lookup✓ ← pLookup∘updateAt p {const ls′} (s .stateMap)
  with lookup✖ ← (λ p≢ → pLookup∘updateAt′ p p′ {const ls′} p≢ (s .stateMap))
  with p ≟ p′
... | no p≢ rewrite lookup✖ (p≢ ∘ ↑-injective) = there $ IH pr∈
... | yes refl
  rewrite lookup✓
  with st
... | InitNoTC _ _
  = there $ IH pr∈
... | ProposeBlockNoOp _ _
  = there $ IH pr∈
... | RegisterVote _ _ _ _ _ _
  with there pr∈ ← pr∈
  = there $ IH pr∈
... | RegisterTimeout _ _ _ _
  with there pr∈ ← pr∈
  = there $ IH pr∈
... | RegisterTC _ _ _ _
  with there pr∈ ← pr∈
  = there $ IH pr∈
... | AdvanceRoundQC _ _ _
  = there $ IH pr∈
... | AdvanceRoundTC _ _ _
  = there $ IH pr∈
... | AdvanceRoundNoOp _ _ _
  = there $ IH pr∈
... | Lock _ _
  = there $ IH pr∈
... | Commit _ _
  = there $ IH pr∈
... | CommitNoOp _ _
  = there $ IH pr∈
... | VoteBlockNoOp _ _
  = there $ IH pr∈
... | InitTC {tc = tc} _ _
  = there $ IH pr∈
... | EnoughTimeouts _ _ _ _
  = there $ IH pr∈
... | TimerExpired _ _
  = there $ IH pr∈
... | VoteBlock _ _ _
  = there $ IH pr∈
... | ProposeBlock {txn = txn} _ _
  = there $ IH pr∈
... | RegisterProposal _ _ _ _ _
  with pr∈
... | here refl = here (refl , refl)
... | there pr∈ = there $ IH pr∈


StepRegisterProposal⇒sbValid : ∀ {s} (Rs : Reachable s) →
  Rs ∋⋯ StepRegisterProposal p sb
  ─────────────────────────────────────────
  sb .node ≡ roundLeader (sb .datum ∙round)
StepRegisterProposal⇒sbValid (s , s-init , (_ ⟨ WaitUntil _ _ _ ⟩←— tr)) st∈
  = StepRegisterProposal⇒sbValid (s , s-init , tr) st∈
StepRegisterProposal⇒sbValid (s , s-init , (_ ⟨ Deliver _ ⟩←— tr)) st∈
  = StepRegisterProposal⇒sbValid (s , s-init , tr) st∈
StepRegisterProposal⇒sbValid (s , s-init , (_ ⟨ DishonestLocalStep _ _ ⟩←— tr)) st∈
  = StepRegisterProposal⇒sbValid (s , s-init , tr) st∈
StepRegisterProposal⇒sbValid (s , s-init , (_ ⟨ LocalStep p ⟩←— tr))
  (there st∈)
  = StepRegisterProposal⇒sbValid (s , s-init , tr) st∈
StepRegisterProposal⇒sbValid (_ , _ , (_ ⟨ LocalStep {p = p} (RegisterProposal _ _ _ L≡ _) ∣ s ⟩←— tr))
  (here (refl , refl))
  = L≡

StepRegisterProposal⇒ValidProposal : ∀ {s} → ⦃ _ : Honest p ⦄ → Reachable s →
  s ▷ StepRegisterProposal p sb
  ───────────────────────────────────────
  ValidProposal ((s @ p) .db) (sb .datum)
StepRegisterProposal⇒ValidProposal Rs
  (_ ⊢ RegisterProposal _ _ _ _ vp , refl , refl , refl , refl) = vp

StepRegisterProposal⇒ValidBlock : ∀ {s} → ⦃ _ : Honest p ⦄ → Reachable s →
  s ▷ StepRegisterProposal p sb
  ─────────────────────────────
  ValidBlock (sb .datum)
StepRegisterProposal⇒ValidBlock Rs rp
  = ValidProposal⇒ValidBlock $ StepRegisterProposal⇒ValidProposal Rs rp

timeout-r-cur : ∀ {s te} → ⦃ _ : Honest p ⦄ →
  StepTimeout p te ◃ s
  ──────────────────────────
  te ∙round ≡ (s @ p) .r-cur
timeout-r-cur ⦃ hp ⦄ ((p , _ , _ , _ , ls′) ⊢ EnoughTimeouts _ _ _ _ , s , _ , refl , refl , refl , refl)
  rewrite pLookup∘updateAt  p ⦃ hp ⦄ {const ls′} (s .stateMap)
  = refl
timeout-r-cur ⦃ hp ⦄ ((p , _ , _ , _ , ls′) ⊢ TimerExpired _ _ , s , _ , refl , refl , refl , refl )
  rewrite pLookup∘updateAt  p ⦃ hp ⦄ {const ls′} (s .stateMap)
  = refl

timeout-qc-high : ∀ {s te} → ⦃ _ : Honest p ⦄ →
  StepTimeout p te ◃ s
  ───────────────────────────
  te ∙qcTE ≡ (s @ p) .qc-high
timeout-qc-high ⦃ hp ⦄ ((p , _ , _ , _ , ls′) ⊢ EnoughTimeouts _ _ _ _ , s , _ , refl , refl , refl , refl)
  rewrite pLookup∘updateAt  p ⦃ hp ⦄ {const ls′} (s .stateMap)
  = refl
timeout-qc-high ⦃ hp ⦄ ((p , _ , _ , _ , ls′) ⊢ TimerExpired _ _ , s , _ , refl , refl , refl , refl )
  rewrite pLookup∘updateAt  p ⦃ hp ⦄ {const ls′} (s .stateMap)
  = refl

-- a p step cannot send a p′ message
ownMessage :
  (p ⦂ s .currentTime ⊢ ls — menv —→ ls′)
  ───────────────────────────────────────────
  All (All (_≡ p) ∘ _∙sender? ∘ content) menv
ownMessage (InitTC _ _) = just nothing
ownMessage (InitNoTC _ _) = nothing
ownMessage (ProposeBlock _ refl) = just (just refl)
ownMessage (ProposeBlockNoOp _ _) = nothing
ownMessage (RegisterProposal _ _ _ _ _) = nothing
ownMessage (RegisterVote _ _ _ _ _ _) = nothing
ownMessage (RegisterTimeout _ _ _ _) = nothing
ownMessage (RegisterTC _ _ _ _) = nothing
ownMessage (EnoughTimeouts _ _ _ _) = just (just refl)
ownMessage (TimerExpired _ _) = just (just refl)
ownMessage (AdvanceRoundQC _ _ _) = nothing
ownMessage (AdvanceRoundTC _ _ _) = nothing
ownMessage (AdvanceRoundNoOp _ _ _) = nothing
ownMessage (Lock _ _) = nothing
ownMessage (Commit _ _) = nothing
ownMessage (CommitNoOp _ _) = nothing
ownMessage (VoteBlock _ _ _) = just (just refl)
ownMessage (VoteBlockNoOp _ _) = nothing

{-
timeout-phase : ∀ {s te} → ⦃ _ : Honest p ⦄ →
  s ▷ StepTimeout p te
  ──────────────────────────
  (s @ p) .phase ≡ Receiving
timeout-phase (_ ⊢ EnoughTimeouts ph _ _ _ , _ , refl , refl , refl) = ph
timeout-phase (_ ⊢ TimerExpired ph _ , _ , refl , refl , refl ) = ph
-}