updateLocal : ∀ p ⦃ _ : Honest p ⦄ → LocalState → Op₁ GlobalState
updateLocal p ls s = record s
{ stateMap = s .stateMap [ p ,· it ]≔ ls }
module _
(s : GlobalState) {env : Envelope}
(let [ p ∣ m ⟩ = env)
(env∈ : env ∈ s .networkBuffer) (let envⁱ = L.Any.index env∈) where
deliverMsg dropMsg : GlobalState
deliverMsg = record s
{ stateMap = s .stateMap [ p ]%= receiveMessage m
; networkBuffer = L.removeAt (s .networkBuffer) envⁱ
}
dropMsg = record s
{ networkBuffer = L.removeAt (s .networkBuffer) envⁱ }
broadcast : Pid → Maybe Message → Op₁ GlobalState
broadcast _ nothing s = s
broadcast pid (just m) s = record s
{ networkBuffer = s .networkBuffer ++ msgs
; history = m ∷ s .history
}
where msgs = L.map [_∣ m ⟩ (filter (pid ≢?_) allPids)
advanceEpoch : Op₁ GlobalState
advanceEpoch s = record s
{ e-now = suc (s .e-now)
; stateMap = V.map epochChange (s .stateMap)
}
data _—→_ (s : GlobalState) : GlobalState → Type where
-- An *honest* node performs a local step.
LocalStep : ⦃ _ : Honest p ⦄ →
(p ▷ s .e-now ⊢ s @ p —[ mm ]→ ls′)
─────────────────────────────────────────
s —→ broadcast p mm (updateLocal p ls′ s)
-- A *dishonest* node can:
-- - Replay a message sent previously by an honest participant.
-- - Broadcast any message signed by a dishonest participant.
-- - Update their local database arbitrarily.
DishonestLocalStep :
∙ Dishonest p
∙ (Honest (m ∙pid) → m ∈ s .history)
───────────────────────────────────────────────
s —→ broadcast p (just m) s
-- * Deliver a message in the network.
-- Since we may deliver any message on the network, this models
-- non-determinism in the order that messages may arrive.
Deliver :
(env∈ : env ∈ s .networkBuffer) →
─────────────────────────────────
s —→ deliverMsg s env∈
-- * Advancing to the next epoch.
AdvanceEpoch :
───────────────────
s —→ advanceEpoch s
-- * A message is lost in the network.
Drop :
(env∈ : env ∈ s .networkBuffer) →
─────────────────────────────────
s —→ dropMsg s env∈
Note : We have system epoch but not local epochs. In a synchronous network (like the one assumed in Streamlet) only the system epoch is needed. If we were to assume a partially-synchronous network then we need the epoch in each local state.