Source code on Github
module UTxOErr.UTxO where
open import Prelude.Init; open SetAsType
open L.Mem
open import Prelude.General
open import Prelude.Maybes
open import Prelude.DecEq
open import Prelude.Decidable
open import Prelude.ToN
open import Prelude.Lists hiding (_⁉_; _‼_; map↦)
open import Prelude.Lists.Dec
open import Prelude.Lists.WithK
open import Prelude.Functor
open import Prelude.Applicative
open import Prelude.FromList
open import Prelude.Membership using (_∈?_; _∉?_)
open import Prelude.Irrelevance
open import Prelude.Apartness
open import Prelude.Allable hiding (All)
open import Prelude.Maps
open import Common public
record TxOutputRef : Type where
constructor _indexed-at_
field txId : HashId
index : ℕ
open TxOutputRef public
unquoteDecl DecEq-TxOR = DERIVE DecEq [ quote TxOutputRef , DecEq-TxOR ]
open CommonInfo TxOutputRef public
S : Type
S = Map⟨ TxOutputRef ↦ TxOutput ⟩
mkUtxo : ∀ {out} tx → out L.Mem.∈ outputs tx → TxOutputRef × TxOutput
mkUtxo {out} tx out∈ = (tx ♯) indexed-at toℕ (L.Any.index out∈) , out
postulate Unique-mkUtxo : ∀ t → Unique $ map proj₁ $ mapWith∈ (t .outputs) (mkUtxo t)
utxoTx : Tx → S
utxoTx tx = fromList $ L.Mem.mapWith∈ (tx .outputs) (mkUtxo tx)
module _ {K V : Type} ⦃ _ : DecEq K ⦄ ⦃ _ : DecEq V ⦄ where
open import Prelude.ToList
import Prelude.Sets as S
import Prelude.Bags as B
_‼_ : {k : K} (m : Map⟨ K ↦ V ⟩) → k ∈ᵈ m → V
m ‼ k∈ = destruct-Is-just (∈ᵈ⇒⁉ m k∈) .proj₁
_─ᵏˢ_ : Map⟨ K ↦ V ⟩ → List K → Map⟨ K ↦ V ⟩
m ─ᵏˢ ks = filterK (_∉? ks) m
keys : Map⟨ K ↦ V ⟩ → List K
keys = map proj₁ ∘ toList
keysˢ : Map⟨ K ↦ V ⟩ → B.Bag⟨ K ⟩
keysˢ = fromList ∘ keys
values⊑ : (m : Map⟨ K ↦ V ⟩) → ∃ $ All (_∈ᵈ m) → List V
values⊑ m (ks , ks⊆) = mapWith∈ ks ((m ‼_) ∘ L.All.lookup ks⊆)
values values′ : Map⟨ K ↦ V ⟩ → List V
values = map proj₂ ∘ toList
values′ m = values⊑ m (keys m , L.All.tabulate id)
values⊑ˢ : (m : Map⟨ K ↦ V ⟩) → ∃ $ All (_∈ᵈ m) → B.Bag⟨ V ⟩
values⊑ˢ = fromList ∘₂ values⊑
valuesˢ valuesˢ′ : Map⟨ K ↦ V ⟩ → B.Bag⟨ V ⟩
valuesˢ = fromList ∘ map proj₂ ∘ toList
valuesˢ′ m = values⊑ˢ m (keys m , L.All.tabulate id)
open ≡-Reasoning
private variable
m m′ : Map⟨ K ↦ V ⟩
ks : List K; kvs : List (K × V)
open import Prelude.Lists.Dec
open import Prelude.Apartness
postulate
nubBy-from∘to : ∀ {A B : Type} ⦃ _ : DecEq B ⦄ {f : A → B} {xs : List A} →
Unique (map f xs) → nubBy f xs ≡ xs
Unique-proj₁ : ∀ {A B : Type} {xys : List (A × B)} →
Unique (map proj₁ xys) → Unique xys
Disjoint-proj₁ : ∀ {A B : Type} {xys xys′ : List (A × B)} →
map proj₁ xys ♯ map proj₁ xys′ → xys ♯ xys′
nub∘nubBy-from∘to : ∀ {A B : Type} ⦃ _ : DecEq A ⦄ ⦃ _ : DecEq B ⦄
{f : A → B} {xs : List A} →
Unique (map f xs) →
nub (nubBy f xs) ≡ xs
nub∘nubBy-from∘to {f = f}{xs} uniq =
begin
nub (nubBy f xs)
≡⟨ nub-from∘to $ Unique-nubBy f xs ⟩
nubBy f xs
≡⟨ nubBy-from∘to uniq ⟩
xs
∎
toList-∪ : keys m ♯ keys m′ → toList (m ∪ m′) ≡ toList m ++ toList m′
toList-∪ {m@(_ ⊣ ·uniq-m)}{m′@(_ ⊣ ·uniq-m′)} m♯m′ =
begin
toList (m ∪ m′)
≡⟨⟩
nub (nubBy proj₁ (toList m ++ toList m′))
≡⟨ cong nub $ nubBy-from∘to uniq-proj₁-++ ⟩
nub (toList m ++ toList m′)
≡⟨ nub-from∘to uniq-++ ⟩
toList m ++ toList m′
∎
where
uniq-m = recompute dec ·uniq-m
uniq-m′ = recompute dec ·uniq-m′
uniq-++ : Unique (toList m ++ toList m′)
uniq-++ = L.Uniq.++⁺ (Unique-proj₁ uniq-m) (Unique-proj₁ uniq-m′)
(Disjoint-proj₁ m♯m′)
uniq-proj₁-++ : Unique $ map proj₁ (toList m ++ toList m′)
uniq-proj₁-++ rewrite L.map-++-commute proj₁ (toList m) (toList m′)
= L.Uniq.++⁺ uniq-m uniq-m′ m♯m′
module _ m m′ (m♯m′ : keys m ♯ keys m′) where
valuesˢ-∪ : valuesˢ (m ∪ m′) ≡ valuesˢ m B.∪ valuesˢ m′
valuesˢ-∪ =
begin
valuesˢ (m ∪ m′)
≡⟨⟩
fromList (proj₂ <$> toList (m ∪ m′))
≡⟨ cong (fromList ∘ map proj₂) $ toList-∪ {m}{m′} m♯m′ ⟩
fromList (proj₂ <$> (toList m ++ toList m′))
≡⟨ cong fromList $ L.map-++-commute proj₂ (toList m) (toList m′) ⟩
fromList ((proj₂ <$> toList m) ++ (proj₂ <$> toList m′))
≡⟨⟩
fromList (proj₂ <$> toList m) B.∪ fromList (proj₂ <$> toList m′)
≡⟨⟩
valuesˢ m B.∪ valuesˢ m′
∎
valuesˢ∘fromList : Unique (proj₁ <$> kvs) →
valuesˢ (fromList kvs) ≡ fromList (proj₂ <$> kvs)
valuesˢ∘fromList = cong (fromList ∘ map proj₂) ∘ nub∘nubBy-from∘to
valuesˢ-─ : ∀ m (p : ∃ $ All (_∈ᵈ m)) →
valuesˢ (m ─ᵏˢ p .proj₁) ≡ valuesˢ m B.─ values⊑ˢ m p
valuesˢ-─ m (ks , ks⊆) =
begin
valuesˢ (m ─ᵏˢ ks)
≡⟨⟩
fromList (proj₂ <$> toList (m ─ᵏˢ ks))
≡⟨⟩
fromList (proj₂ <$> filter ((_∉? ks) ∘ proj₁) (toList m))
≡⟨ cong fromList H ⟩
fromList
(map proj₂ (toList m) ∸[bag] (mapWith∈ ks ((m ‼_) ∘ L.All.lookup ks⊆)))
≡⟨⟩
fromList (proj₂ <$> toList m)
B.─
fromList (mapWith∈ ks ((m ‼_) ∘ L.All.lookup ks⊆))
≡⟨⟩
fromList (proj₂ <$> toList m) B.─ fromList (values⊑ m (-, ks⊆))
≡⟨⟩
valuesˢ m B.─ values⊑ˢ m (-, ks⊆)
∎
where
postulate
H : map proj₂ (filter ((_∉? ks) ∘ proj₁) (toList m))
≡ map proj₂ (toList m) ∸[bag] (mapWith∈ ks ((m ‼_) ∘ L.All.lookup ks⊆))
postulate
values⊆⇒⊆[bag] : ∀ m (p : ∃ $ All (_∈ᵈ m)) → values⊑ m p ⊆[bag] values m
values⊆⇒⊆ˢ : ∀ m (p : ∃ $ All (_∈ᵈ m)) → values⊑ˢ m p B.⊆ˢ valuesˢ m
values⊆⇒⊆ˢ = values⊆⇒⊆[bag]
record IsValidTx (tx : Tx) (utxos : S) : Type where
field
noDoubleSpending :
·Unique (outputRefs tx)
validOutputRefs :
∀[ ref ∈ outputRefs tx ]
(ref ∈ᵈ utxos)
resolved : Resolved tx
resolved = (utxos ‼_) ∘ L.All.lookup validOutputRefs
txInfo = mkTxInfo tx resolved
resolvedInputs = resolveInputs tx resolved
field
preservesValues :
tx .forge + ∑ resolvedInputs (value ∘ proj₂) ≡ ∑ (tx .outputs) value
allInputsValidate :
∀[ i ∈ tx .inputs ]
T (i .validator txInfo (i .redeemer))
validateValidHashes :
∀[ (i , o) ∈ resolvedInputs ]
(o .address ≡ i .validator ♯)
open IsValidTx public
instance
·Valid : ∀ {tx s} → · IsValidTx tx s
·Valid {s = _ ⊣ ·uniq} .∀≡
(record { noDoubleSpending = ndp
; validOutputRefs = vor
; preservesValues = pv
; allInputsValidate = aiv
; validateValidHashes = vvh
})
(record { noDoubleSpending = ndp′
; validOutputRefs = vor′
; preservesValues = pv′
; allInputsValidate = aiv′
; validateValidHashes = vvh′
})
with uniq ← recompute dec ·uniq
rewrite ∀≡ ndp ndp′
| L.All.irrelevant (∈-irr uniq) vor vor′
| ∀≡ pv pv′
| L.All.irrelevant B.T-irrelevant aiv aiv′
| ∀≡ vvh vvh′
= refl
isValidTx? : ∀ tx s → Dec (IsValidTx tx s)
isValidTx? tx s@(_ ⊣ ·uniq)
with uniq ← recompute dec ·uniq
with dec
... | no ¬p = no (¬p ∘ noDoubleSpending)
... | yes ndp with dec
... | no ¬p = no (¬p ∘ validOutputRefs)
... | yes vor with dec
... | no ¬p = no absurd
where absurd : ¬ IsValidTx tx s
absurd (record {validOutputRefs = vor′; preservesValues = p})
rewrite L.All.irrelevant (∈-irr uniq) vor vor′ = ¬p p
... | yes pv with dec
... | no ¬p = no absurd
where absurd : ¬ IsValidTx tx s
absurd (record {validOutputRefs = vor′; allInputsValidate = p})
rewrite L.All.irrelevant (∈-irr uniq) vor vor′ = ¬p p
... | yes aiv with dec
... | no ¬p = no absurd
where absurd : ¬ IsValidTx tx s
absurd (record {validOutputRefs = vor′; validateValidHashes = p})
rewrite L.All.irrelevant (∈-irr uniq) vor vor′ = ¬p p
... | yes vvh = yes record
{ noDoubleSpending = ndp
; validOutputRefs = vor
; preservesValues = pv
; allInputsValidate = aiv
; validateValidHashes = vvh }
isValidTx : Tx → S → Bool
isValidTx tx s = ⌊ isValidTx? tx s ⌋
postulate s♯t : ∀ {t s} → IsValidTx t s → keys (s ─ᵏˢ outputRefs t) ♯ keys (utxoTx t)