module Peras.Chain where
open import Haskell.Prelude
open import Haskell.Extra.Dec
open import Haskell.Extra.Refinement
open import Haskell.Law.Equality
open import Data.Nat using (NonZero; _/_)
open import Relation.Binary.PropositionalEquality using (_≢_)
open import Peras.Crypto
open import Peras.Block
open import Peras.Numbering
open import Peras.Params
open import Peras.Util
{-# FOREIGN AGDA2HS
{-# LANGUAGE DeriveGeneric #-}
{-# OPTIONS_GHC -fno-warn-missing-pattern-synonym-signatures #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
{-# OPTIONS_GHC -fno-warn-unused-matches #-}
import GHC.Generics (Generic)
#-}
{-# FOREIGN GHC
import qualified Peras.Chain as G
#-}
VotingWeight = Nat
record Vote : Set where
constructor MkVote
field votingRound : RoundNumber
creatorId : PartyId
proofM : MembershipProof
blockHash : Hash Block
signature : Signature
votingRound' : Nat
votingRound' = getRoundNumber votingRound
open Vote public
instance
iVoteEq : Eq Vote
iVoteEq ._==_ x y = votingRound x == votingRound y
&& creatorId x == creatorId y
&& proofM x == proofM y
&& blockHash x == blockHash y
&& signature x == signature y
{-# COMPILE AGDA2HS VotingWeight #-}
{-# COMPILE AGDA2HS Vote deriving (Generic) #-}
{-# COMPILE GHC Vote = data G.Vote (G.MkVote) #-}
{-# COMPILE AGDA2HS iVoteEq #-}
record Postulates : Set₁ where
field
IsSlotLeader : PartyId → SlotNumber → LeadershipProof → Set
IsCommitteeMember : PartyId → RoundNumber → MembershipProof → Set
IsBlockSignature : Block → Signature → Set
IsVoteSignature : Vote → Signature → Set
record Network : Set₁ where
field
Δ : Nat
module _ ⦃ _ : Postulates ⦄
where
open Postulates ⦃...⦄
ValidVote : Vote → Set
ValidVote v =
IsCommitteeMember
(creatorId v)
(votingRound v)
(proofM v)
× IsVoteSignature v (signature v)
Equivocal votes are multiple votes by the same party for the same round.
data _∻_ : Vote → Vote → Set where
Equivocation : ∀ {v₁ v₂}
→ creatorId v₁ ≡ creatorId v₂
→ votingRound v₁ ≡ votingRound v₂
→ v₁ ≢ v₂
→ v₁ ∻ v₂
Chain = List Block
{-# COMPILE AGDA2HS Chain #-}
certsFromChain : Chain → List Certificate
certsFromChain = mapMaybe certificate
{-# COMPILE AGDA2HS certsFromChain #-}
insertCert : Certificate → List Certificate → List Certificate
insertCert cert [] = cert ∷ []
insertCert cert (cert' ∷ certs) =
if cert == cert'
then cert' ∷ certs
else cert' ∷ insertCert cert certs
{-# COMPILE AGDA2HS insertCert #-}
lastSlot : ∀ (c : Chain) → SlotNumber
lastSlot = foldr max (MkSlotNumber 0) ∘ map slotNumber
{-# COMPILE AGDA2HS lastSlot #-}
open Params ⦃...⦄
module _ ⦃ _ : Hashable Block ⦄
where
open Hashable ⦃...⦄
cert₀ : Certificate
cert₀ = MkCertificate (MkRoundNumber 0) (MkHash emptyBS)
ChainExtends : Hash Block → Certificate → Chain → Set
ChainExtends h c ch =
Any (λ block → (hash block ≡ blockRef c))
(dropWhile (λ block' → (hash block' /= h)) ch)
Extends : Hash Block → Certificate → List Chain → Set
Extends h c ch = if (c == cert₀) then ⊤ else Any (ChainExtends h c) ch
The weight of a chain is computed wrt to a set of dangling votes
module _ ⦃ _ : Hashable Block ⦄
⦃ _ : Params ⦄
where
open Hashable ⦃...⦄
StartOfRound : SlotNumber → RoundNumber → Set StartOfRound (MkSlotNumber sl) (MkRoundNumber r) = sl ≡ r * U
rnd : Nat → ⦃ _ : NonZero U ⦄ → Nat rnd s = s / U
v-round : SlotNumber → RoundNumber v-round (MkSlotNumber s) = MkRoundNumber (rnd s)
weight : Chain → List Certificate → Nat
weight ch cts = chainWeight' 0 ch
where
isCertified : Block → Bool
isCertified block = any (λ cert → hash block == blockRef cert) cts
chainWeight' : Nat → Chain → Nat
chainWeight' accum [] = accum
chainWeight' accum (block ∷ blocks) =
if isCertified block
then chainWeight' (accum + 1 + B) blocks
else chainWeight' (accum + 1) blocks
module _ ⦃ _ : Hashable Block ⦄
⦃ _ : Postulates ⦄
⦃ _ : Network ⦄
where
open Hashable ⦃...⦄
open Postulates ⦃...⦄
open Network ⦃...⦄
data ValidChain : Chain → Set where
Genesis : ValidChain []
Cons : ∀ {c : Chain} {b : Block}
→ IsBlockSignature b (signature b)
→ IsSlotLeader (creatorId b) (slotNumber b) (leadershipProof b)
→ compare (lastSlot c) (slotNumber b) ≡ LT
→ parentBlock b ≡ tipHash c
→ ValidChain c
→ ValidChain (b ∷ c)
<!–
-- | `foldl` does not exist in `Haskell.Prelude` so let's roll our own
-- but let's make it total.
foldl1Maybe : ∀ {a : Set} -> (a -> a -> a) -> List a -> Maybe a
foldl1Maybe f xs =
foldl (λ m y -> Just (case m of λ where
Nothing -> y
(Just x) -> f x y))
Nothing xs
{-# COMPILE AGDA2HS foldl1Maybe #-}
prefix : List Block -> List Block -> List Block -> List Block
prefix acc (x ∷ xs) (y ∷ ys) =
if x == y
then prefix (x ∷ acc) xs ys
else reverse acc
prefix acc _ _ = reverse acc
{-# COMPILE AGDA2HS prefix #-}
commonPrefix : List Chain -> List Block
commonPrefix chains =
case listPrefix of λ where
Nothing -> []
(Just bs) -> reverse bs
where
listPrefix : Maybe (List Block)
listPrefix = foldl1Maybe (prefix []) (map (λ l -> reverse l) chains)
{-# COMPILE AGDA2HS commonPrefix #-}
-->