forked from celestiaorg/smt
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathtypes.go
97 lines (86 loc) · 2.13 KB
/
types.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package smt
import (
"errors"
"hash"
)
const (
left = 0
)
var (
defaultValue []byte = nil
ErrKeyNotPresent = errors.New("key already empty")
)
// SparseMerkleTree represents a Sparse Merkle tree.
type SparseMerkleTree interface {
// Update inserts a value into the SMT.
Update(key, value []byte) error
// Delete deletes a value from the SMT. Raises an error if the key is not present.
Delete(key []byte) error
// Get descends the tree to access a value. Returns nil if key is not present.
Get(key []byte) ([]byte, error)
// Root computes the Merkle root digest.
Root() []byte
// Prove computes a Merkle proof of membership or non-membership of a key.
Prove(key []byte) (SparseMerkleProof, error)
// Commit saves the tree's state to its persistent storage.
Commit() error
base() *BaseSMT
}
type BaseSMT struct {
th treeHasher
ph PathHasher
vh ValueHasher
}
func newBaseSMT(hasher hash.Hash) BaseSMT {
smt := BaseSMT{th: *newTreeHasher(hasher)}
smt.ph = &pathHasher{smt.th}
smt.vh = &smt.th
return smt
}
func (smt *BaseSMT) base() *BaseSMT { return smt }
func (smt *BaseSMT) depth() int { return smt.ph.PathSize() * 8 }
func (smt *BaseSMT) digestValue(data []byte) []byte {
if smt.vh == nil {
return data
}
return smt.vh.digest(data)
}
func (smt *BaseSMT) serialize(node treeNode) (data []byte) {
switch n := node.(type) {
case *lazyNode:
panic("serialize(lazyNode)")
case *leafNode:
return encodeLeaf(n.path, n.valueHash)
case *innerNode:
lchild := smt.hashNode(n.leftChild)
rchild := smt.hashNode(n.rightChild)
return encodeInner(lchild, rchild)
case *extensionNode:
child := smt.hashNode(n.child)
return encodeExtension(n.pathBounds, n.path, child)
}
return nil
}
func (smt *BaseSMT) hashNode(node treeNode) []byte {
if node == nil {
return smt.th.placeholder()
}
var cache *[]byte
switch n := node.(type) {
case *lazyNode:
return n.digest
case *leafNode:
cache = &n.digest
case *innerNode:
cache = &n.digest
case *extensionNode:
if n.digest == nil {
n.digest = smt.hashNode(n.expand())
}
return n.digest
}
if *cache == nil {
*cache = smt.th.digest(smt.serialize(node))
}
return *cache
}