2024-10-23 20:49:24 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
2024-10-25 14:09:21 +00:00
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
2024-10-23 20:49:24 +00:00
|
|
|
|
|
|
|
module Zenith.Tree where
|
|
|
|
|
|
|
|
import Data.HexString
|
2024-10-29 12:01:13 +00:00
|
|
|
import Data.Int (Int64)
|
|
|
|
import ZcashHaskell.Orchard (combineOrchardNodes, getOrchardNodeValue)
|
|
|
|
import ZcashHaskell.Types (OrchardFrontier(..))
|
|
|
|
|
|
|
|
type Level = Integer
|
|
|
|
|
|
|
|
maxLevel :: Level
|
|
|
|
maxLevel = 32
|
|
|
|
|
|
|
|
type Position = Int64
|
2024-10-23 20:49:24 +00:00
|
|
|
|
|
|
|
class Monoid v =>
|
|
|
|
Measured a v
|
|
|
|
where
|
2024-10-29 12:01:13 +00:00
|
|
|
measure :: a -> Position -> v
|
2024-10-23 20:49:24 +00:00
|
|
|
|
2024-10-25 14:09:21 +00:00
|
|
|
class Node v where
|
|
|
|
getLevel :: v -> Level
|
2024-10-29 12:01:13 +00:00
|
|
|
getTag :: v -> HexString
|
|
|
|
getPosition :: v -> Position
|
2024-10-25 14:09:21 +00:00
|
|
|
isFull :: v -> Bool
|
2024-10-29 12:01:13 +00:00
|
|
|
mkNode :: Level -> Position -> HexString -> v
|
2024-10-23 20:49:24 +00:00
|
|
|
|
2024-10-29 12:01:13 +00:00
|
|
|
type OrchardCommitment = HexString
|
2024-10-25 14:09:21 +00:00
|
|
|
|
2024-10-29 12:01:13 +00:00
|
|
|
instance Measured OrchardCommitment OrchardNode where
|
|
|
|
measure oc p =
|
|
|
|
case getOrchardNodeValue (hexBytes oc) of
|
|
|
|
Nothing -> OrchardNode 0 (hexString "00") 0 True
|
|
|
|
Just val -> OrchardNode p val 0 True
|
2024-10-25 14:09:21 +00:00
|
|
|
|
|
|
|
data Tree v
|
2024-10-29 12:01:13 +00:00
|
|
|
= EmptyLeaf
|
|
|
|
| Leaf !v
|
|
|
|
| PrunedBranch !v
|
2024-10-25 14:09:21 +00:00
|
|
|
| Branch !v !(Tree v) !(Tree v)
|
|
|
|
deriving (Eq)
|
|
|
|
|
|
|
|
instance (Node v, Show v) => Show (Tree v) where
|
|
|
|
show EmptyLeaf = "()"
|
|
|
|
show (Leaf v) = "(" ++ show v ++ ")"
|
2024-10-29 12:01:13 +00:00
|
|
|
show (PrunedBranch v) = "{" ++ show v ++ "}"
|
|
|
|
show (Branch s x y) =
|
|
|
|
"<" ++ show (getTag s) ++ ">\n" ++ show x ++ "\n" ++ show y
|
2024-10-25 14:09:21 +00:00
|
|
|
|
|
|
|
instance (Monoid v, Node v) => Semigroup (Tree v) where
|
2024-10-29 12:01:13 +00:00
|
|
|
(<>) EmptyLeaf EmptyLeaf = PrunedBranch $ value $ branch EmptyLeaf EmptyLeaf
|
2024-10-25 14:09:21 +00:00
|
|
|
(<>) EmptyLeaf x = x
|
|
|
|
(<>) (Leaf x) EmptyLeaf = branch (Leaf x) EmptyLeaf
|
|
|
|
(<>) (Leaf x) (Leaf y) = branch (Leaf x) (Leaf y)
|
|
|
|
(<>) (Leaf x) Branch {} = Leaf x
|
2024-10-29 12:01:13 +00:00
|
|
|
(<>) (Leaf x) (PrunedBranch _) = Leaf x
|
|
|
|
(<>) (PrunedBranch x) EmptyLeaf = PrunedBranch $ x <> x
|
|
|
|
(<>) (PrunedBranch x) (Leaf _) = PrunedBranch x
|
|
|
|
(<>) (PrunedBranch x) (Branch s t u) =
|
|
|
|
if getLevel x == getLevel s
|
|
|
|
then branch (PrunedBranch x) (Branch s t u)
|
|
|
|
else EmptyLeaf
|
|
|
|
(<>) (PrunedBranch x) (PrunedBranch y) = PrunedBranch $ x <> y
|
|
|
|
(<>) (Branch s x y) EmptyLeaf =
|
|
|
|
branch (Branch s x y) $ getEmptyRoot (getLevel s)
|
|
|
|
(<>) (Branch s x y) (PrunedBranch _) = Branch s x y
|
2024-10-25 14:09:21 +00:00
|
|
|
(<>) (Branch s x y) (Leaf w)
|
|
|
|
| isFull s = Branch s x y <> mkSubTree (getLevel s) (Leaf w)
|
|
|
|
| isFull (value x) = branch x (y <> Leaf w)
|
|
|
|
| otherwise = branch (x <> Leaf w) y
|
|
|
|
(<>) (Branch s x y) (Branch s1 x1 y1)
|
|
|
|
| getLevel s == getLevel s1 = branch (Branch s x y) (Branch s1 x1 y1)
|
|
|
|
| otherwise = Branch s x y
|
|
|
|
|
|
|
|
value :: Monoid v => Tree v -> v
|
|
|
|
value EmptyLeaf = mempty
|
|
|
|
value (Leaf v) = v
|
2024-10-29 12:01:13 +00:00
|
|
|
value (PrunedBranch v) = v
|
2024-10-23 20:49:24 +00:00
|
|
|
value (Branch v _ _) = v
|
|
|
|
|
2024-10-25 14:09:21 +00:00
|
|
|
branch :: Monoid v => Tree v -> Tree v -> Tree v
|
2024-10-23 20:49:24 +00:00
|
|
|
branch x y = Branch (value x <> value y) x y
|
|
|
|
|
2024-10-29 12:01:13 +00:00
|
|
|
leaf :: Measured a v => a -> Int64 -> Tree v
|
2024-10-25 14:09:21 +00:00
|
|
|
leaf a p = Leaf (measure a p)
|
2024-10-23 20:49:24 +00:00
|
|
|
|
2024-10-29 12:01:13 +00:00
|
|
|
prunedBranch :: Monoid v => Node v => Level -> Position -> HexString -> Tree v
|
|
|
|
prunedBranch level pos val = PrunedBranch $ mkNode level pos val
|
|
|
|
|
|
|
|
root :: Monoid v => Node v => Tree v -> Tree v
|
|
|
|
root tree =
|
|
|
|
if getLevel (value tree) == maxLevel - 1
|
|
|
|
then tree
|
|
|
|
else mkSubTree (maxLevel - 1) tree
|
|
|
|
|
|
|
|
getEmptyRoot :: Monoid v => Node v => Level -> Tree v
|
|
|
|
getEmptyRoot level = iterate (\x -> x <> x) EmptyLeaf !! fromIntegral level
|
|
|
|
|
2024-10-23 20:49:24 +00:00
|
|
|
data OrchardNode = OrchardNode
|
2024-10-29 12:01:13 +00:00
|
|
|
{ on_position :: !Position
|
|
|
|
, on_value :: !HexString
|
2024-10-25 14:09:21 +00:00
|
|
|
, on_level :: !Level
|
|
|
|
, on_full :: !Bool
|
|
|
|
} deriving (Eq)
|
2024-10-23 20:49:24 +00:00
|
|
|
|
|
|
|
instance Semigroup OrchardNode where
|
|
|
|
(<>) x y =
|
2024-10-29 12:01:13 +00:00
|
|
|
case combineOrchardNodes (on_level x) (on_value x) (on_value y) of
|
|
|
|
Nothing -> x
|
|
|
|
Just newHash ->
|
|
|
|
OrchardNode
|
|
|
|
(max (on_position x) (on_position y))
|
|
|
|
newHash
|
|
|
|
(1 + on_level x)
|
|
|
|
(on_full x && on_full y)
|
2024-10-23 20:49:24 +00:00
|
|
|
|
|
|
|
instance Monoid OrchardNode where
|
2024-10-29 12:01:13 +00:00
|
|
|
mempty = OrchardNode 0 (hexString "00") 0 False
|
2024-10-23 20:49:24 +00:00
|
|
|
mappend = (<>)
|
2024-10-25 14:09:21 +00:00
|
|
|
|
|
|
|
instance Node OrchardNode where
|
|
|
|
getLevel = on_level
|
|
|
|
getTag = on_value
|
|
|
|
getPosition = on_position
|
|
|
|
isFull = on_full
|
2024-10-29 12:01:13 +00:00
|
|
|
mkNode l p v = OrchardNode p v l True
|
2024-10-25 14:09:21 +00:00
|
|
|
|
|
|
|
instance Show OrchardNode where
|
2024-10-29 12:01:13 +00:00
|
|
|
show = show . on_value
|
2024-10-25 14:09:21 +00:00
|
|
|
|
|
|
|
instance Measured OrchardNode OrchardNode where
|
|
|
|
measure o p = OrchardNode p (on_value o) (on_level o) (on_full o)
|
|
|
|
|
|
|
|
mkSubTree :: Node v => Monoid v => Level -> Tree v -> Tree v
|
|
|
|
mkSubTree level t =
|
|
|
|
if getLevel (value subtree) == level
|
|
|
|
then subtree
|
|
|
|
else mkSubTree level subtree
|
|
|
|
where
|
|
|
|
subtree = t <> EmptyLeaf
|
2024-10-29 12:01:13 +00:00
|
|
|
|
|
|
|
mkOrchardTree :: OrchardFrontier -> Tree OrchardNode
|
|
|
|
mkOrchardTree (OrchardFrontier p l o) =
|
|
|
|
if odd p
|
|
|
|
then addOrchardOmmers (tail o) $
|
|
|
|
Leaf (OrchardNode (p - 1) (head o) 0 True) <>
|
|
|
|
Leaf (OrchardNode p l 0 True)
|
|
|
|
else addOrchardOmmers o $ Leaf (OrchardNode p l 0 True) <> EmptyLeaf
|
|
|
|
|
|
|
|
addOrchardOmmers :: [HexString] -> Tree OrchardNode -> Tree OrchardNode
|
|
|
|
addOrchardOmmers xs t =
|
|
|
|
foldl
|
|
|
|
(\s x -> PrunedBranch (mkNode (getLevel $ value s) (p (value s)) x) <> s)
|
|
|
|
t
|
|
|
|
xs
|
|
|
|
where
|
|
|
|
p :: OrchardNode -> Position
|
|
|
|
p (OrchardNode pos _ l _) = pos - (2 ^ l)
|