Source code on Githubopen import Prelude.Init
open import Prelude.Lists
open import Prelude.DecEq
open import Prelude.Membership
open import Prelude.Functor
open import Prelude.Applicative
open import Prelude.Default
open import Prelude.Ord
open import UTxO.Hashing
open import UTxO.Value
open import UTxO.Types
open import StateMachine.Base
module StateMachine.Examples.MultiSig (Signatories : List HashId)(Threshold : ℕ)
where
PubKeyHash = HashId
record Payment : Set where
constructor payment
field
paymentAmount : Value
paymentRecipient : PubKeyHash
paymentDeadline : Bound
data State : Set where
Holding : _
Collecting : Payment → List PubKeyHash → _
data Input : Set where
ProposePayment : Payment → Input
AddSignature : PubKeyHash → Input
Cancel : Input
Pay : Input
map-just' : {A B : Set}(ma : Maybe A)(a : A)
→ (f : A → B)
→ (∀{a a'} → f a ≡ f a' → a ≡ a')
→ (f <$> ma) ≡ just (f a)
→ ma ≡ just a
map-just' (just _) a f p q = cong just (p (M.just-injective q))
map-nothing' : {A B : Set}(ma : Maybe A)
→ (f : A → B)
→ (f <$> ma) ≡ nothing
→ ma ≡ nothing
map-nothing' nothing f p = refl
ap-map-just : {A B C : Set}(ma : Maybe A)(a : A)(mb : Maybe B)(b : B)
→ (f : A → B → C)
→ (∀{a a'}{b b'} → f a b ≡ f a' b' → a ≡ a' × b ≡ b')
→ ⦇ f ma mb ⦈ ≡ just (f a b)
→ ma ≡ just a × mb ≡ just b
ap-map-just (just _) a (just _) b f p q =
let
r , r' = p (M.just-injective q)
in
cong just r , cong just r'
ap-ap-map-just : {A B C D : Set}
→ (ma : Maybe A)(a : A)
→ (mb : Maybe B)(b : B)
→ (mc : Maybe C)(c : C)
→ (f : A → B → C → D)
→ (∀{a a'}{b b'}{c c'} → f a b c ≡ f a' b' c' → a ≡ a' × b ≡ b' × c ≡ c')
→ (⦇ f ma mb ⦈ <*> mc) ≡ just (f a b c)
→ ma ≡ just a × mb ≡ just b × mc ≡ just c
ap-ap-map-just (just _) a (just _) b (just _) c f p q =
let
r , r' , r'' = p (M.just-injective q)
in
cong just r , cong just r' , cong just r''
,-injective : {A B : Set}{a a' : A}{b b' : B}
→ (a , b) ≡ (a' , b') → a ≡ a' × b ≡ b'
,-injective refl = refl , refl
t=-injective : ∀{n n'} → t= n ≡ t= n' → n ≡ n'
t=-injective refl = refl
payment-injective : ∀{v v' r r' d d'}
→ payment v r d ≡ payment v' r' d' → v ≡ v' × r ≡ r' × d ≡ d'
payment-injective refl = refl , refl , refl
Collecting-injective : ∀{p p' sigs sigs'}
→ Collecting p sigs ≡ Collecting p' sigs'
→ p ≡ p' × sigs ≡ sigs'
Collecting-injective refl = refl , refl
ProposePayment-injective : ∀{p p'}
→ ProposePayment p ≡ ProposePayment p' → p ≡ p'
ProposePayment-injective refl = refl
AddSignature-injective : ∀{sig sig'}
→ AddSignature sig ≡ AddSignature sig' → sig ≡ sig'
AddSignature-injective refl = refl
cong₃ : {A B C D : Set}(f : A → B → C → D){a a' : A}{b b' : B}{c c' : C}
→ a ≡ a' → b ≡ b' → c ≡ c' → f a b c ≡ f a' b' c'
cong₃ f refl refl refl = refl
instance
isData-ℕ : IsData ℕ
toData ⦃ isData-ℕ ⦄ n = I (+ n)
fromData ⦃ isData-ℕ ⦄ (I (+ n)) = just n
fromData ⦃ isData-ℕ ⦄ _ = nothing
from∘to ⦃ isData-ℕ ⦄ n = refl
from-inj ⦃ isData-ℕ ⦄ (I (+ _)) _ refl = refl
instance
isData-Bound : IsData Bound
toData ⦃ isData-Bound ⦄ -∞ = CONSTR 0 []
toData ⦃ isData-Bound ⦄ (t= n) = CONSTR 1 [ toData n ]
toData ⦃ isData-Bound ⦄ +∞ = CONSTR 2 []
fromData ⦃ isData-Bound ⦄ (CONSTR 0 []) = just -∞
fromData ⦃ isData-Bound ⦄ (CONSTR 1 (dt ∷ [])) =
t=_ <$> fromData dt
fromData ⦃ isData-Bound ⦄ (CONSTR 2 []) = just +∞
fromData ⦃ isData-Bound ⦄ _ = nothing
from∘to ⦃ isData-Bound ⦄ -∞ = refl
from∘to ⦃ isData-Bound ⦄ (t= t) = refl
from∘to ⦃ isData-Bound ⦄ +∞ = refl
from-inj ⦃ isData-Bound ⦄ (CONSTR 0 []) -∞ refl = refl
from-inj ⦃ isData-Bound ⦄ (CONSTR 0 (_ ∷ _)) b ()
from-inj ⦃ isData-Bound ⦄ (CONSTR 1 (dt ∷ [])) (t= t) p =
cong (λ dt → CONSTR 1 [ dt ]) (from-inj dt t (map-just' (fromData dt) t t=_ t=-injective p))
from-inj ⦃ isData-Bound ⦄ (CONSTR 1 (dt ∷ [])) +∞ p with fromData {ℕ} dt
from-inj ⦃ isData-Bound ⦄ _ _ () | nothing
from-inj ⦃ isData-Bound ⦄ _ _ () | just x
from-inj ⦃ isData-Bound ⦄ (CONSTR 1 (dt ∷ [])) -∞ p with fromData {ℕ} dt
from-inj ⦃ isData-Bound ⦄ _ _ () | nothing
from-inj ⦃ isData-Bound ⦄ _ _ () | just x
from-inj ⦃ isData-Bound ⦄ (CONSTR 1 []) b ()
from-inj ⦃ isData-Bound ⦄ (CONSTR 2 []) +∞ refl = refl
from-inj ⦃ isData-Bound ⦄ (CONSTR 2 (_ ∷ _)) b ()
from-inj ⦃ isData-Bound ⦄ (CONSTR (suc (suc (suc n))) xs) b ()
instance
IsData-Pair : ∀ {A B : Set} → {{_ : IsData A}} → {{_ : IsData B}}
→ IsData (A × B)
toData ⦃ IsData-Pair ⦄ (a , b) = LIST (toData a ∷ toData b ∷ [])
fromData ⦃ IsData-Pair ⦄ (LIST (a ∷ b ∷ [])) =
⦇ fromData a , fromData b ⦈
fromData ⦃ IsData-Pair ⦄ _ = nothing
from∘to ⦃ IsData-Pair ⦄ (a , b) rewrite from∘to a | from∘to b = refl
from-inj ⦃ IsData-Pair ⦄ (LIST (da ∷ db ∷ [])) (a , b) p =
let
q , q' = ap-map-just (fromData da) a (fromData db) b _,_ ,-injective p
in
cong₂ (λ a b → LIST (a ∷ b ∷ [])) (from-inj da a q) (from-inj db b q')
instance
IsData-Payment : IsData Payment
toData ⦃ IsData-Payment ⦄ (payment v r d) =
LIST (toData v ∷ toData r ∷ toData d ∷ [])
fromData ⦃ IsData-Payment ⦄ (LIST (dv ∷ dr ∷ dd ∷ [])) =
⦇ payment (fromData dv) (fromData dr) ⦈ <*> fromData dd
fromData ⦃ IsData-Payment ⦄ _ = nothing
from∘to ⦃ IsData-Payment ⦄ (payment v r d) rewrite from∘to v | from∘to r | from∘to d = refl
from-inj ⦃ IsData-Payment ⦄ (LIST (dv ∷ dr ∷ dd ∷ [])) (payment v r d) p =
let
q , q' , q'' = ap-ap-map-just (fromData dv) v (fromData dr) r (fromData dd) d payment payment-injective p
in
cong₃ (λ v r d → LIST (v ∷ r ∷ d ∷ [])) (from-inj dv v q) (from-inj dr r q') (from-inj dd d q'')
instance
IsData-MS : IsData State
toData ⦃ IsData-MS ⦄ Holding = CONSTR 0 []
toData ⦃ IsData-MS ⦄ (Collecting p sigs) = CONSTR 1
(toData p ∷ toData sigs ∷ [])
fromData ⦃ IsData-MS ⦄ (CONSTR 0 []) = just Holding
fromData ⦃ IsData-MS ⦄ (CONSTR 1 (p ∷ sigs ∷ [])) =
⦇ Collecting (fromData p) (fromData sigs) ⦈
fromData ⦃ IsData-MS ⦄ _ = nothing
from∘to ⦃ IsData-MS ⦄ Holding = refl
from∘to ⦃ IsData-MS ⦄ (Collecting p sigs)
rewrite from∘to p | from∘to sigs = refl
from-inj ⦃ IsData-MS ⦄ (CONSTR 0 []) Holding p = refl
from-inj ⦃ IsData-MS ⦄ (CONSTR 1 (dp ∷ dsigs ∷ [])) (Collecting p sigs) q =
let
x , x' = ap-map-just (fromData dp) p (fromData dsigs) sigs Collecting Collecting-injective q
in
cong₂ (λ p sigs → CONSTR 1 (p ∷ sigs ∷ [])) (from-inj dp p x) (from-inj dsigs sigs x')
from-inj ⦃ IsData-MS ⦄ (CONSTR (suc (suc n)) (_ ∷ _)) Holding ()
from-inj ⦃ IsData-MS ⦄ (CONSTR 1 (dp ∷ dsigs ∷ [])) Holding q with (fromData {Payment} dp)
from-inj IsData-MS _ _ () | nothing
... | just x with fromData {List ℕ} dsigs
from-inj IsData-MS _ _ () | just _ | just _
from-inj IsData-MS _ _ () | just _ | nothing
from-inj ⦃ IsData-MS ⦄ (CONSTR 0 (_ ∷ _)) Holding ()
from-inj ⦃ IsData-MS ⦄ (CONSTR 1 []) Holding ()
from-inj ⦃ IsData-MS ⦄ (CONSTR 1 (_ ∷ [])) Holding ()
from-inj ⦃ IsData-MS ⦄ (CONSTR (suc (suc n)) []) Holding ()
from-inj ⦃ IsData-MS ⦄ (CONSTR 0 []) (Collecting _ _) ()
from-inj ⦃ IsData-MS ⦄ (CONSTR 0 (_ ∷ _)) (Collecting _ _) ()
from-inj ⦃ IsData-MS ⦄ (CONSTR 1 []) (Collecting _ _) ()
from-inj ⦃ IsData-MS ⦄ (CONSTR 1 (_ ∷ [])) (Collecting _ _) ()
from-inj ⦃ IsData-MS ⦄ (CONSTR (suc (suc n)) _) _ ()
IsData-MI : IsData Input
toData ⦃ IsData-MI ⦄ (ProposePayment p) = CONSTR 0 [ toData p ]
toData ⦃ IsData-MI ⦄ (AddSignature sig) = CONSTR 1 [ toData sig ]
toData ⦃ IsData-MI ⦄ Pay = CONSTR 2 []
toData ⦃ IsData-MI ⦄ Cancel = CONSTR 3 []
fromData ⦃ IsData-MI ⦄ (CONSTR 0 (dp ∷ [])) = ProposePayment <$> fromData dp
fromData ⦃ IsData-MI ⦄ (CONSTR 1 (dsig ∷ [])) = AddSignature <$> fromData dsig
fromData ⦃ IsData-MI ⦄ (CONSTR 2 []) = just Pay
fromData ⦃ IsData-MI ⦄ (CONSTR 3 []) = just Cancel
fromData ⦃ IsData-MI ⦄ _ = nothing
from∘to ⦃ IsData-MI ⦄ (ProposePayment p) rewrite from∘to p = refl
from∘to ⦃ IsData-MI ⦄ (AddSignature sig) rewrite from∘to sig = refl
from∘to ⦃ IsData-MI ⦄ Pay = refl
from∘to ⦃ IsData-MI ⦄ Cancel = refl
from-inj ⦃ IsData-MI ⦄ (CONSTR 0 (dp ∷ [])) (ProposePayment p) q =
let
r = (map-just' (fromData dp) p ProposePayment ProposePayment-injective q)
in
cong (λ p → CONSTR 0 [ p ]) (from-inj dp p r)
from-inj ⦃ IsData-MI ⦄ (CONSTR 1 []) (ProposePayment p) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 1 (dp ∷ [])) (ProposePayment p) q with fromData {ℕ} dp
from-inj ⦃ IsData-MI ⦄ _ _ () | just _
from-inj ⦃ IsData-MI ⦄ _ _ () | nothing
from-inj ⦃ IsData-MI ⦄ (CONSTR 1 (_ ∷ _ ∷ _)) (ProposePayment p) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 2 []) (ProposePayment p) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 2 (_ ∷ _)) (ProposePayment p) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 3 []) (ProposePayment p) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 3 (_ ∷ _)) (ProposePayment p) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR (suc (suc (suc (suc _)))) _) (ProposePayment p) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 1 (dsig ∷ [])) (AddSignature sig) q =
let
r = (map-just' (fromData dsig) sig AddSignature AddSignature-injective q)
in
cong (λ sig → CONSTR 1 [ sig ]) (from-inj dsig sig r)
from-inj ⦃ IsData-MI ⦄ (CONSTR 0 []) (AddSignature sig) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 0 (dp ∷ [])) (AddSignature sig) q with fromData {Payment} dp
from-inj ⦃ IsData-MI ⦄ _ _ () | just _
from-inj ⦃ IsData-MI ⦄ _ _ () | nothing
from-inj ⦃ IsData-MI ⦄ (CONSTR 0 (_ ∷ _ ∷ _)) (AddSignature sig) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 2 []) (AddSignature sig) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 2 (_ ∷ _)) (AddSignature sig) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 3 []) (AddSignature sig) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 3 (_ ∷ _)) (AddSignature sig) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR (suc (suc (suc (suc _)))) _) (AddSignature sig) ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 2 []) Pay q = refl
from-inj ⦃ IsData-MI ⦄ (CONSTR 2 (_ ∷ _)) Pay ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 0 []) Pay ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 0 (dp ∷ [])) Pay q with fromData {Payment} dp
from-inj ⦃ IsData-MI ⦄ _ _ () | just _
from-inj ⦃ IsData-MI ⦄ _ _ () | nothing
from-inj ⦃ IsData-MI ⦄ (CONSTR 0 (_ ∷ _ ∷ _)) Pay ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 1 []) Pay ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 1 (dsig ∷ [])) Pay q with fromData {ℕ} dsig
from-inj ⦃ IsData-MI ⦄ _ _ () | just _
from-inj ⦃ IsData-MI ⦄ _ _ () | nothing
from-inj ⦃ IsData-MI ⦄ (CONSTR 1 (_ ∷ _ ∷ _)) Pay ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 3 []) Pay ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 3 (_ ∷ _)) Pay ()
from-inj ⦃ IsData-MI ⦄ (CONSTR (suc (suc (suc (suc _)))) _) Pay ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 3 []) Cancel q = refl
from-inj ⦃ IsData-MI ⦄ (CONSTR 3 (_ ∷ _)) Cancel ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 0 []) Cancel ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 0 (dp ∷ [])) Cancel q with fromData {Payment} dp
from-inj ⦃ IsData-MI ⦄ _ _ () | just _
from-inj ⦃ IsData-MI ⦄ _ _ () | nothing
from-inj ⦃ IsData-MI ⦄ (CONSTR 0 (_ ∷ _ ∷ _)) Cancel ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 1 []) Cancel ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 1 (dsig ∷ [])) Cancel q with fromData {ℕ} dsig
from-inj ⦃ IsData-MI ⦄ _ _ () | just _
from-inj ⦃ IsData-MI ⦄ _ _ () | nothing
from-inj ⦃ IsData-MI ⦄ (CONSTR 1 (_ ∷ _ ∷ _)) Cancel ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 2 []) Cancel ()
from-inj ⦃ IsData-MI ⦄ (CONSTR 2 (_ ∷ _)) Cancel ()
from-inj ⦃ IsData-MI ⦄ (CONSTR (suc (suc (suc (suc _)))) _) Cancel ()
MultiSigSM : StateMachine State Input
isInitial MultiSigSM Holding = true
isInitial MultiSigSM _ = false
step MultiSigSM Holding (ProposePayment p) = just ((Collecting p []) , def)
step MultiSigSM (Collecting p sigs) (AddSignature sig) with sig ∈? Signatories | sig ∈? sigs
... | no ¬q | _ = nothing
... | yes q | no ¬r =
just (Collecting p (sig ∷ sigs) , def)
... | yes q | yes r = nothing
step MultiSigSM (Collecting p sigs) Cancel =
just ( Holding
, record { forge≡ = nothing
; range≡ = just (Payment.paymentDeadline p ⋯ +∞)
; spent≥ = nothing })
step MultiSigSM (Collecting p sigs) Pay with length sigs ≥? Threshold
... | yes q =
just (Holding
, record { forge≡ = nothing
; range≡ = just (-∞ ⋯ Payment.paymentDeadline p)
; spent≥ = just (Payment.paymentAmount p) })
... | no ¬q = nothing
step MultiSigSM _ _ = nothing
origin MultiSigSM = nothing
open import StateMachine.Inductive {sm = MultiSigSM}
P : State → Input → TxConstraints → State → Set
P (Collecting p _) Cancel txc _ = range≡ txc ≡ just (Payment.paymentDeadline p ⋯ +∞)
P _ Cancel _ _ = ⊥
P _ _ _ _ = ⊤
lemma : ∀ {s s'} (xs : s ↝⋆ s') → AllI (const ⊤) P xs
lemma (root p) = root p tt
lemma (snoc {s' = Holding} xs x@(ProposePayment _ , _)) = snoc xs x tt (lemma xs)
lemma (snoc {s' = Collecting pay sigs} xs x@(AddSignature sig , _)) = snoc xs x tt (lemma xs)
lemma (snoc {s' = Collecting pay sigs} xs x@(Cancel , _ , refl)) = snoc xs x refl (lemma xs)
lemma (snoc {s' = Collecting pay sigs} xs x@(Pay , _ , _)) = snoc xs x tt (lemma xs)
temp : ∀ {sigs₀} →
(λ{ (Collecting _ sigs) → sigs ≡ sigs₀
; Holding → ⊥ })
↝⋆⟨ (λ{ (AddSignature _) → ⊤
; _ → ⊥ }) ⟩
(λ{ (Collecting _ sigs) → sigs₀ ⊆ sigs
; Holding → ⊥ })
temp {sigs₀} (Collecting _ .sigs₀) refl .(Collecting _ sigs₀)
base⁇
= L.SubS.⊆-refl
temp {sigs₀} (Collecting _ .sigs₀) refl s″
(step⁇ {s′ = s′} {i = AddSignature sig } s↝s′ (_ , eq) p)
with s′ | temp _ refl _ s↝s′
... | Collecting _ sigs | sigs₀⊆sigs
with sig ∈? Signatories | sig ∈? sigs | s″ | eq
... | yes _ | no _ | .(Collecting _ (sig ∷ sigs)) | refl
= there ∘ sigs₀⊆sigs