Source code on Githubmodule UTxO.Validity where
open import Data.List.Membership.Propositional.Properties using (∈-map⁺; ∈-map⁻)
open import Data.List.Relation.Binary.Suffix.Heterogeneous using (tail)
open import Data.List.Relation.Binary.Pointwise using (Pointwise-≡⇒≡)
import Data.Maybe.Relation.Unary.Any as M
open import Prelude.Init hiding (module M; _∋_)
open import Prelude.Lists
open import Prelude.Lists.Dec
open import Prelude.Lists.Postulates
open import Prelude.Decidable
open import Prelude.DecEq
open import Prelude.Functor
open import Prelude.Sets
open L.Mem
open import Prelude.Ord
open import UTxO.Hashing
open import UTxO.Value
open import UTxO.Types
open import UTxO.TxUtilities
record IsValidTx (tx : Tx) (l : Ledger) : Set where
field
withinInterval :
T (range tx ∋ length l)
validOutputRefs :
outputRefs tx ⊆ map outRef (utxo l)
preservesValues :
M.Any (λ q → forge tx +ᶜ q ≡ ∑ (outputs tx) value)
(∑M (map (getSpentOutput l) (inputs tx)) value)
noDoubleSpending :
Unique (outputRefs tx)
allInputsValidate :
All (λ{ (n , i) → T (validator i (toPendingTx l tx n) (redeemer i) (datum i)) })
(enumerate (inputs tx))
allPoliciesValidate :
All (λ f → T (f (toPendingMPS l tx (f ♯))))
(policies tx)
validateValidHashes :
All (λ i → M.Any (λ o → (address o ≡ validator i ♯) × (datumHash o ≡ datum i ♯ᵈ)) (getSpentOutput l i))
(inputs tx)
forging :
All (λ c → Any (λ f → c ≡ f ♯) (policies tx))
(currencies (forge tx))
open IsValidTx public
data ValidLedger : Ledger → Set where
∙ : ValidLedger []
_⊕_∶-_ : ∀ {l}
→ ValidLedger l
→ (t : Tx)
→ IsValidTx t l
→ ValidLedger (t ∷ l)
infixl 5 _⊕_∶-_
infixl 5 _⊕_
_⊕_ : ∀ {l}
→ ValidLedger l
→ (tx : Tx)
→ {wi : True (T? (range tx ∋ length l))}
→ {vor : True (outputRefs tx ⊆? map outRef (utxo l))}
→ {pv : True (M.dec (λ q → forge tx +ᶜ q ≟ ∑ (outputs tx) value)
(∑M (map (getSpentOutput l) (inputs tx)) value))}
→ {ndp : True (unique? (outputRefs tx))}
→ {aiv : True (all? (λ{ (n , i) → T? (validator i (toPendingTx l tx n) (redeemer i) (datum i))})
(enumerate (inputs tx)))}
→ {apv : True (all? (λ f → T? (f (toPendingMPS l tx (f ♯))))
(policies tx))}
→ {vvh : True (all? (λ i → M.dec (λ o → (address o ≟ validator i ♯) ×-dec (datumHash o ≟ datum i ♯ᵈ))
(getSpentOutput l i))
(inputs tx))}
→ {frg : True (all? (λ c → any? (λ f → c ≟ f ♯) (policies tx))
(currencies (forge tx)))}
→ ValidLedger (tx ∷ l)
(vl ⊕ tx) {wi} {vor} {pv} {ndp} {aiv} {apv} {vvh} {frg}
= vl ⊕ tx ∶- record { withinInterval = toWitness wi
; validOutputRefs = toWitness vor
; preservesValues = toWitness pv
; noDoubleSpending = toWitness ndp
; allInputsValidate = toWitness aiv
; allPoliciesValidate = toWitness apv
; validateValidHashes = toWitness vvh
; forging = toWitness frg }
outputsₘ : ∃ ValidLedger → List TxOutput
outputsₘ ([] , _) = []
outputsₘ (tx ∷ _ , _) = outputs tx
_∈′_ : Tx → ∃ ValidLedger → Set
tx ∈′ (l , _) = tx ∈ l
infix 4 _≼_ _≼′_ _≺_ _≺′_
_≼_ : Rel Ledger 0ℓ
_≼_ = Suffix≡
_≺_ : Rel Ledger 0ℓ
l′ ≺ l = ∃ λ tx → tx ∷ l′ ≼ l
_≼′_ : Rel (∃ ValidLedger) 0ℓ
(l′ , _) ≼′ (l , _) = l′ ≼ l
_≺′_ : Rel (∃ ValidLedger) 0ℓ
(l , _) ≺′ (l′ , _) = l ≺ l′
postulate
≺-trans : Transitive _≺_
≺-transˡ : ∀ {x y z} → x ≼ y → y ≺ z → x ≺ z
≺-∑forge : ∀ {l′ l} → l′ ≺ l → T $ ∑ l forge ≥ᶜ ∑ l′ forge
≺′⇒≼′ : ∀ {l l′} → l′ ≺′ l → l′ ≼′ l
≺′⇒≼′ (_ , p) = tail p
≺-wf : WellFounded _≺_
≺-wf l = acc $ go l
where
go : ∀ l l′ → l′ ≺ l → Acc _≺_ l′
go (_ ∷ l) l′ (_ , here (refl ∷ eq)) = acc λ y y<l′ → go l y (subst (y ≺_) (Pointwise-≡⇒≡ eq) y<l′)
go (_ ∷ l) l′ (_ , there l′<l) = acc λ y y<l′ → go l y (≺-trans y<l′ (_ , l′<l))
≺′-wf : WellFounded _≺′_
≺′-wf vl = vl ≺′⇒≺ ≺-wf (proj₁ vl)
where
_≺′⇒≺_ : ∀ vl → Acc _≺_ (proj₁ vl) → Acc _≺′_ vl
(l , _) ≺′⇒≺ acc w = acc λ{ (l′ , _) l′<l → (l′ , _) ≺′⇒≺ w l′ l′<l }
≺′-rec = WF.All.wfRec ≺′-wf 0ℓ
≼⇒valid : ∀ {l l′}
→ ValidLedger l
→ l′ ≼ l
→ ValidLedger l′
≼⇒valid vl (here eq) rewrite Pointwise-≡⇒≡ eq = vl
≼⇒valid (vl ⊕ t ∶- x) (there suf) = ≼⇒valid vl suf
tx∈⇒valid : ∀ {L tx}
→ (tx∈ : tx ∈′ L)
→ IsValidTx tx (proj₁ $ ∈⇒Suffix tx∈)
tx∈⇒valid {L = _ , vl} {tx = tx} tx∈
with l , l≺ ← ∈⇒Suffix tx∈
with _ ⊕ .tx ∶- vtx ← ≼⇒valid vl l≺
= vtx
postulate
suf-utxo : ∀ {tx l l′ x}
→ ValidLedger l
→ Suffix≡ (tx ∷ l′) l
→ x ∈ map outRef (utxo l′)
→ x ∈ outputRefs tx
→ x ∉ map outRef (utxo l)
record Res {tx : Tx} {l : Ledger} (vl : ValidLedger l) (vtx : IsValidTx tx l) : Set where
field
prevTx : Tx
l′ : Ledger
prevOut : TxOutput
vl′ : ValidLedger (prevTx ∷ l′)
prevOut∈ : prevOut ∈ outputs prevTx
vl′≺vl : (prevTx ∷ l′ , vl′) ≺′ (tx ∷ l , (vl ⊕ tx ∶- vtx))
spent≡ : ∃ λ i → (i ∈ inputs tx) × (getSpentOutput l i ≡ just prevOut)
or∈ : Any ((prevTx ♯ₜₓ ≡_) ∘ hid) (outputRefs tx)
⁉≡just : outputs prevTx ⟦ index (L.Any.lookup or∈) ⟧ ≡ just prevOut
resValue : ∀ {tx l} {vl : ValidLedger l} {vtx : IsValidTx tx l} → Res vl vtx → Value
resValue = value ∘ Res.prevOut
prevs : ∀ {tx l} (vl : ValidLedger l) (vtx : IsValidTx tx l) → List (Res vl vtx)
prevs {tx} {l} vl vtx
= mapWith∈ (inputs tx) go
module P₀ where
go : ∀ {i} → i ∈ inputs tx → Res vl vtx
go {i} i∈
with outRef∈ ← validOutputRefs vtx (∈-map⁺ outputRef i∈)
with u , u∈ , refl ← ∈-map⁻ outRef outRef∈
with prev∈ , prevOut∈ , refl ← ∈utxo⇒outRef≡ {l = l} u∈
with l′ , suf ← ∈⇒Suffix prev∈
= record { prevTx = prevTx u
; l′ = l′
; prevOut = out u
; vl′ = vl′
; prevOut∈ = prevOut∈
; vl′≺vl = vl′≺vl
; spent≡ = i , i∈ , utxo-getSpent {l = l} u∈
; or∈ = or∈
; ⁉≡just = ⁉≡just
}
where
id≡ : prevTx u ♯ₜₓ ≡ hid (outputRef i)
id≡ = sym $ ⟨⟩≡just {l}{outputRef i}{prevTx u} (utxo-[] {l} u∈)
P⊆Q : ∀ {or} → outputRef i ≡ or → prevTx u ♯ₜₓ ≡ hid or
P⊆Q refl = id≡
or∈ : Any ((prevTx u ♯ₜₓ ≡_) ∘ hid) (outputRefs tx)
or∈ = L.Any.map P⊆Q (∈-map⁺ outputRef i∈)
outRef≡ : L.Any.lookup or∈ ≡ outputRef i
outRef≡ = begin L.Any.lookup or∈ ≡⟨ Any-lookup∘map P⊆Q (∈-map⁺ outputRef i∈) ⟩
L.Any.lookup (∈-map⁺ outputRef i∈) ≡⟨ lookup∘∈-map⁺ {f = outputRef} i∈ ⟩
outputRef i ∎
where open ≡-Reasoning
⁉≡just : (outputs (prevTx u) ⁉ index (L.Any.lookup or∈)) ≡ just (out u)
⁉≡just rewrite outRef≡ = utxo-⟨⟩ {l} u∈
v = value $ out u
vl′ = ≼⇒valid vl suf
vl′≺vl : (prevTx u ∷ l′ , vl′) ≺′ (tx ∷ l , (vl ⊕ tx ∶- vtx))
vl′≺vl = ≺-transˡ suf (tx , suffix-refl (tx ∷ l))
∑prevs≡ : ∀ {tx l} (vl : ValidLedger l) (vtx : IsValidTx tx l)
→ ∑M (map (getSpentOutput l) (inputs tx)) value ≡ just (∑ (prevs vl vtx) resValue)
∑prevs≡ {tx} {l} vl vtx = ∑M-help {A = TxInput} {xs = inputs tx} {f = getSpentOutput l} {g = value}
{R = Res vl vtx} {go = go} {r = resValue} (cong (_<$>_ value) ∘ s≡)
where
open P₀ vl vtx
i′≡ : ∀ {i} i∈ → proj₁ (Res.spent≡ $ go {i} i∈) ≡ i
i′≡ {i} i∈
with u , u∈ , refl ← ∈-map⁻ outRef (validOutputRefs vtx (∈-map⁺ outputRef i∈))
with prev∈ , prevOut∈ , refl ← ∈utxo⇒outRef≡ {l = l} u∈
with l′ , suf ← ∈⇒Suffix prev∈
= refl
s≡ : ∀ {i} i∈ → getSpentOutput l i ≡ just (Res.prevOut $ go {i} i∈)
s≡ {i} i∈
with Res.spent≡ (go {i} i∈) | inspect Res.spent≡ (go {i} i∈)
... | i′ , _ , spent≡ | ≡[ go≡ ]
= trans (cong (getSpentOutput l) i≡) spent≡
where
i≡ : i ≡ i′
i≡ = trans (sym $ i′≡ {i} i∈) (cong proj₁ go≡)
prevs⊆utxo : ∀ {tx l} {vl : ValidLedger l} {vtx : IsValidTx tx l}
→ map resValue (prevs vl vtx)
⊆ map (value ∘ out) (utxo l)
prevs⊆utxo {tx}{l}{vl}{vtx} v∈
with _ , pr∈ , refl ← ∈-map⁻ resValue v∈
with _ , i∈ , refl ← ∈-mapWith∈⁻ {f = P₀.go vl vtx} pr∈
with _ , u∈ , refl ← ∈-map⁻ outRef (validOutputRefs vtx (∈-map⁺ outputRef i∈))
with _ , _ , refl ← ∈utxo⇒outRef≡ {l = l} u∈
= ∈-map⁺ (value ∘ out) u∈
NonFungible : ∃ ValidLedger → TokenClass → Set
NonFungible (l , _) nft = ∑ l forge ◇ nft ≤ 1
NF-weaken : ∀ {nft l l′} → l′ ≺′ l → NonFungible l nft → NonFungible l′ nft
NF-weaken {nft}{l , _}{l′ , _} vl′≺ = Nat.≤-trans (≥ᶜ-◆ {x = ∑ l forge} {y = ∑ l′ forge} $ ≺-∑forge vl′≺)
where open FocusTokenClass nft