Source code on Github
open import Prelude.Init
open L.NE using (head; last)
open import Prelude.General
open import Prelude.Nats.Postulates
open import Prelude.Lists
open import Prelude.Lists.Postulates
open import Prelude.Membership
open import Prelude.ToN
open import Prelude.Bifunctor
open import Prelude.Ord

open import UTxO.Hashing
open import UTxO.Value
open import UTxO.Types hiding (I)
open import UTxO.TxUtilities
open import UTxO.Validity


module UTxO.TokenProvenance (nft : TokenClass) where

open FocusTokenClass nft

private
  variable
    L  :  ValidLedger
    tx : Tx
    n  : Quantity

-- Definitions.

_↝⟦_⟧_ : Tx  Quantity  Tx  Set
tx ↝⟦ n  tx′ = Σ[ or∈  Any ((tx ♯ₜₓ ≡_)  hid) (outputRefs tx′) ]
                  ∃[ o ] ( ((outputs tx  index (L.Any.lookup or∈))  just o)
                         × (value o   n) )

data X (n : Quantity) : List⁺ Tx  Set where
  root :

      (tx : Tx)
     forge tx   n
      ---------------
     X n (tx  [])

  cons :  {txs tx}

     X n txs
     head txs ↝⟦ n  tx
      -------------------
     X n (tx ∷⁺ txs)

weakenX :  {n n′ txs}  n′  n  X n txs  X n′ txs
weakenX n′< (root tx n<)                = root tx (≤-trans n′< n<)
weakenX n′< (cons x (or∈ , o , p , n<)) = cons (weakenX n′< x) (or∈ , o , p , ≤-trans n′< n<)

record Trace L (tx : Tx) (n : Quantity) : Set where
  field
    txs    : List⁺ Tx
    trace∈ : All⁺ (_∈′ L) txs
    linked : X n txs
    head≡  : head txs  tx
open Trace public

record Provenance L tx (n : Quantity) : Set where
  field
    traces : List ( $ Trace L tx)
    sums   : ∑₁ traces  n
open Provenance public

-- Utilities.

origin : Trace L tx n  Tx
origin = last  txs

∣_∣ : Provenance L tx n  
∣_∣ = length  traces

weaken-↝ :  {tx tx′ n n′}  tx ↝⟦ n  tx′  n′  n  tx ↝⟦ n′  tx′
weaken-↝ {n = n}{n′} (or∈ , o , p , ≤v) n≤ = or∈ , o , p , ≤-trans {i = n′} {j = n} {k = value o } n≤ ≤v

weakenTrace :  {L L′}  L′ ≼′ L  Trace L′ tx n  Trace L tx n
weakenTrace L′≼ record {txs = txs; trace∈ = tr∈;                          linked = p; head≡ = h≡}
              = record {txs = txs; trace∈ = L.All.map (Suffix⇒⊆ L′≼) tr∈; linked = p; head≡ = h≡}

weakenTraceⁿ :  {n n′}  n′  n  Trace L tx n  Trace L tx n′
weakenTraceⁿ n< record {txs = txs; trace∈ = tr∈; linked = p;            head≡ = h≡}
              = record {txs = txs; trace∈ = tr∈; linked = weakenX n< p; head≡ = h≡}

weakenProvenance :  {L L′}  L′ ≼′ L  Provenance L′ tx n  Provenance L tx n
weakenProvenance {tx = tx} {n = n} {L = L}{L′} L≼
    record { traces = trs;              sums = p }
  = record { traces = map (map₂′ f) trs; sums = subst (_≥ n) (sym $ ∑₁-map₂ {xs = trs} {f = f}) p }
  where
    f :  {n}  Trace L′ tx n  Trace L tx n
    f = weakenTrace L≼

_∷ᵗ_∶-_ :
    (tx′ : Tx)
   (tr : Trace L tx n)
   (tx′ ∈′ L) × (tx ↝⟦ n  tx′)
   Trace L tx′ n
tx ∷ᵗ record {txs = txs;       trace∈ = tr∈;       linked = p;          head≡ = refl} ∶- (tx∈ , tx↝)
    = record {txs = tx ∷⁺ txs; trace∈ = tx∈  tr∈; linked = cons p tx↝; head≡ = refl}

forge◆≥ :  {txs : List⁺ Tx} (x : X n txs)  forge (last txs)   n
forge◆≥ (root _ frg≥)              = frg≥
forge◆≥ (cons {txs = txs}{tx} x _) rewrite last-∷ {x = tx}{txs} = forge◆≥ x

singleton-Provenance :  {tx l} {vl : ValidLedger (tx  l)}  Provenance (_ , vl) tx (forge tx )
singleton-Provenance {tx = tx}{l}{vl} = record {traces = [ tr ]; sums = ∑≥}
  where
    tr :  $ Trace (_ , vl) tx
    tr = _ , record {txs = tx  []; trace∈ = here refl  []; linked = root tx ≤-refl; head≡ = refl}

    ∑≥ : ∑₁ [ tr ]  forge tx 
    ∑≥ = subst (_≥ forge tx ) (sym $ ∑₁-single {n = forge tx } {x = tr}) ≤-refl

combine : (prs : List ( $ Provenance L tx))  ∑₁ prs  n  Provenance L tx n
combine [] z≤n = record {traces = []; sums = z≤n}
combine {L = L} {tx = tx} {n = n} ((n′ , pr)  prs) ∑≥ = record
  { traces = traces pr ++ traces pr′
  ; sums   = ∑≥′
  }
  where
    pr′ : Provenance L tx (∑₁ prs)
    pr′ = combine {n = ∑₁ prs} prs ≤-refl

    ∑≥′ : ∑₁ (traces pr ++ traces pr′)  n
    ∑≥′ = begin n                                ≤⟨ ∑≥ 
                n′ + ∑₁ prs                      ≤⟨ ≥-+-swapˡʳ (sums pr) (sums pr′) 
                ∑₁ (traces pr) + ∑₁ (traces pr′) ≡⟨ sym $ ∑₁-++ {xs = traces pr}{traces pr′} 
                ∑₁ (traces pr ++ traces pr′)     
          where open ≤-Reasoning

-- Token provenance.

provenance :  {tx l} (vl : ValidLedger (tx  l))   {o}  o  outputs tx  Provenance (_ , vl) tx (value o )
provenance {tx}{l} vl = go vl (≺′-wf (_ , vl))
  module Provenance₀ where
    go :  {tx l} (vl : ValidLedger (tx  l))  Acc _≺′_ (_ , vl)
        (∀ {o}  o  outputs tx  Provenance (_ , vl) tx (value o ))
    go {tx}{l} vl₀@(vl  tx ∶- vtx) (acc a) {o} o∈
      = combine allPrevs ∑≥
      module Provenance₁ where
        L₀ = _ , vl₀
        v  = value o 
        rs = prevs vl vtx

        fromForge : List ( $ Provenance L₀ tx)
        fromForge
          with ◆∈? forge tx
        ... | yes _ = [ _ , singleton-Provenance {tx = tx}{l}{vl₀} ]
        ... | no  _ = []

        res→traces : Res vl vtx  Maybe ( $ Provenance L₀ tx)
        res→traces r@(record { prevTx = tx′; vl′ = vl′; prevOut = o′; prevOut∈ = o∈′; vl′≺vl = vl′≺vl
                             ; or∈ = or∈; ⁉≡just = ⁉≡just })
          with ◆∈? resValue r
        ... | no  _ = nothing
        ... | yes _ = just $ _ , pr
          where
            r◆ = resValue r 

            ↝tx : tx′ ↝⟦ r◆  tx
            ↝tx = or∈ , o′ , ⁉≡just , ≤-refl

            pr′ : Provenance L₀ tx′ r◆
            pr′ = weakenProvenance (≺′⇒≼′ {l = L₀}{_ , vl′} vl′≺vl) (go vl′ (a _ vl′≺vl) o∈′)

            pr : Provenance L₀ tx r◆
            pr = record { traces = limit r◆ k₁ k₂ (traces pr′)
                        ; sums = ∑₁-limit {xs = traces pr′} {k₁ = k₁} {k₂ = k₂} (sums pr′) }
              where
                k₁ :  {n}  r◆  n  Trace L₀ tx′ n  Trace L₀ tx r◆
                k₁ {n} r≤ tr = tx ∷ᵗ weakenTraceⁿ r≤ tr ∶- (here refl , ↝tx)

                k₂ :  {n}  n  r◆  Trace L₀ tx′ n  Trace L₀ tx n
                k₂ {n} n≤ tr = tx ∷ᵗ tr ∶- (here refl , weaken-↝ {tx = tx′}{tx} ↝tx n≤)


        fromPrevs : List ( $ Provenance L₀ tx)
        fromPrevs = mapMaybe res→traces rs

        allPrevs : List ( $ Provenance L₀ tx)
        allPrevs = fromForge ++ fromPrevs

--

        ∑prev =  rs resValue
        ∑all  = forge tx +ᶜ ∑prev

        pv₀ : ∑all  ∑ᵥ (outputs tx)
        pv₀ = ∑M≡just (∑prevs≡ vl vtx) (preservesValues vtx)

        pv₁ : T $ ∑all ≥ᶜ value o
        pv₁ = ≥ᶜ-trans {x = ∑all} {y = ∑ᵥ (outputs tx)} {z = value o} (≥ᶜ-refl′ pv₀) (∑-≥ᶜ {fv = value} o∈)

        pv₂ : ∑all   v
        pv₂ = ≥ᶜ-◆ {x = ∑all} {y = value o} pv₁

        ∑forge≡ : ∑₁ fromForge  forge tx 
        ∑forge≡ with ◆∈? forge tx
        ... | yes _ = Nat.+-identityʳ (forge tx )
        ... | no ¬p = sym $ ¬x>0⇒x≡0 ¬p

        ∑-helper : ∑ℕ (map (_◆  resValue) rs)  ∑₁ (mapMaybe res→traces rs)
        ∑-helper = ∑-mapMaybe {xs = rs} {fm = res→traces} {g = resValue} {fv = proj₁} p₁ p₂
          where
            p₁ :  r  Is-nothing (res→traces r)  resValue r   0
            p₁ r rn with ◆∈? resValue r | rn
            ... | yes _ | M.All.just ()
            ... | no ¬p | _ = ¬x>0⇒x≡0 ¬p

            p₂ :  r v  res→traces r  just v  resValue r   proj₁ v
            p₂ r v rj with ◆∈? resValue r | rj
            ... | yes _ | refl = refl
            ... | no  _ | ()

        ∑fromPrevs≡ : ∑prev   ∑₁ fromPrevs
        ∑fromPrevs≡ = begin ∑prev                      ≡⟨ ∑-◆ {xs = rs} {f = resValue} 
                            ∑ℕ (map (_◆  resValue) rs) ≡⟨ ∑-helper 
                            ∑₁ (mapMaybe res→traces rs) ≡⟨⟩
                            ∑₁ fromPrevs                
                      where open ≡-Reasoning

        ∑≥ : ∑₁ allPrevs  v
        ∑≥ = begin v                             ≤⟨ pv₂ 
                   ∑all                         ≡⟨⟩
                   (forge tx +ᶜ ∑prev)          ≡⟨ +ᶜ-◆ {x = forge tx} {y = ∑prev} 
                   forge tx      + ∑prev       ≡⟨ cong (forge tx  +_) ∑fromPrevs≡ 
                   forge tx      + ∑₁ fromPrevs ≡⟨ cong (_+ ∑₁ fromPrevs) (sym ∑forge≡) 
                   ∑₁ fromForge + ∑₁ fromPrevs   ≡⟨ sym $ ∑₁-++ {xs = fromForge}{fromPrevs} 
                   ∑₁ (fromForge ++ fromPrevs)   ≡⟨⟩
                   ∑₁ allPrevs 
              where open ≤-Reasoning

provenance⁺ :  {tx l} (vl : ValidLedger (tx  l)) {o} (o∈ : o  outputs tx)
   ◆∈ value o
    provenance vl o∈  > 0
provenance⁺ vl o∈ ◆∈v
  with provenance vl o∈
... | record {traces = []; sums = p} = ⊥-elim $ x≡0⇒¬x>0 (x≤0⇒x≡0 p) ◆∈v
... | record {traces = _  _}        = s≤s z≤n

origin∈ : (tr : Trace L tx n)  origin tr ∈′ L
origin∈ = All⁺-last  trace∈

mkPendingMPS : Trace L tx n  HashId  PendingMPS
mkPendingMPS tr = toPendingMPS (proj₁ $ ∈⇒Suffix $ origin∈ tr) (origin tr)

mps≡ :  {L L′} (l≺ : L′ ≼′ L) (tr : Trace L′ tx n)
   (proj₁ $ ∈⇒Suffix $ origin∈ {L = L} $ weakenTrace l≺ tr)
   (proj₁ $ ∈⇒Suffix $ origin∈ tr)
mps≡ {L = L}{L′} l≺ tr = proj₁∘∈⇒Suffix≡ {xs = txs tr}{proj₁ L′}{proj₁ L} (trace∈ tr) l≺