-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathnode.go
146 lines (133 loc) · 3.97 KB
/
node.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package merkletree
import (
"fmt"
"math/big"
)
// NodeType defines the type of node in the MT.
type NodeType byte
const (
// NodeTypeMiddle indicates the type of middle Node that has children.
NodeTypeMiddle NodeType = 0
// NodeTypeLeaf indicates the type of a leaf Node that contains a key &
// value.
NodeTypeLeaf NodeType = 1
// NodeTypeEmpty indicates the type of an empty Node.
NodeTypeEmpty NodeType = 2
// DBEntryTypeRoot indicates a type of DB entry that indicates the
// current Root of a MerkleTree
DBEntryTypeRoot NodeType = 3
)
// Node is the struct that represents a node in the MT. The node should not be
// modified after creation because the cached key won't be updated.
type Node struct {
// Type is the type of node in the tree.
Type NodeType
// ChildL is the left child of a middle node.
ChildL *Hash
// ChildR is the right child of a middle node.
ChildR *Hash
// Entry is the data stored in a leaf node.
Entry [2]*Hash
// key is a cache used to avoid recalculating key
key *Hash
}
// NewNodeLeaf creates a new leaf node.
func NewNodeLeaf(k, v *Hash) *Node {
return &Node{Type: NodeTypeLeaf, Entry: [2]*Hash{k, v}}
}
// NewNodeMiddle creates a new middle node.
func NewNodeMiddle(childL *Hash, childR *Hash) *Node {
return &Node{Type: NodeTypeMiddle, ChildL: childL, ChildR: childR}
}
// NewNodeEmpty creates a new empty node.
func NewNodeEmpty() *Node {
return &Node{Type: NodeTypeEmpty}
}
// NewNodeFromBytes creates a new node by parsing the input []byte.
func NewNodeFromBytes(b []byte) (*Node, error) {
if len(b) < 1 {
return nil, ErrNodeBytesBadSize
}
n := Node{Type: NodeType(b[0])}
b = b[1:]
switch n.Type {
case NodeTypeMiddle:
if len(b) != 2*ElemBytesLen {
return nil, ErrNodeBytesBadSize
}
n.ChildL, n.ChildR = &Hash{}, &Hash{}
copy(n.ChildL[:], b[:ElemBytesLen])
copy(n.ChildR[:], b[ElemBytesLen:ElemBytesLen*2])
case NodeTypeLeaf:
if len(b) != 2*ElemBytesLen {
return nil, ErrNodeBytesBadSize
}
n.Entry = [2]*Hash{{}, {}}
copy(n.Entry[0][:], b[0:32])
copy(n.Entry[1][:], b[32:64])
case NodeTypeEmpty:
break
default:
return nil, ErrInvalidNodeFound
}
return &n, nil
}
// LeafKey computes the key of a leaf node given the hIndex and hValue of the
// entry of the leaf.
func LeafKey(k, v *Hash) (*Hash, error) {
return HashElemsKey(big.NewInt(1), k.BigInt(), v.BigInt())
}
// Key computes the key of the node by hashing the content in a specific way
// for each type of node. This key is used as the hash of the merkle tree for
// each node.
func (n *Node) Key() (*Hash, error) {
if n.key == nil { // Cache the key to avoid repeated hash computations.
// NOTE: We are not using the type to calculate the hash!
switch n.Type {
case NodeTypeMiddle: // H(ChildL || ChildR)
var err error
n.key, err = HashElems(n.ChildL.BigInt(), n.ChildR.BigInt())
if err != nil {
return nil, err
}
case NodeTypeLeaf:
var err error
n.key, err = LeafKey(n.Entry[0], n.Entry[1])
if err != nil {
return nil, err
}
case NodeTypeEmpty: // Zero
n.key = &HashZero
default:
n.key = &HashZero
}
}
return n.key, nil
}
// Value returns the value of the node. This is the content that is stored in
// the backend database.
func (n *Node) Value() []byte {
switch n.Type {
case NodeTypeMiddle: // {Type || ChildL || ChildR}
return append([]byte{byte(n.Type)}, append(n.ChildL[:], n.ChildR[:]...)...)
case NodeTypeLeaf: // {Type || Data...}
return append([]byte{byte(n.Type)}, append(n.Entry[0][:], n.Entry[1][:]...)...)
case NodeTypeEmpty: // {}
return []byte{}
default:
return []byte{}
}
}
// String outputs a string representation of a node (different for each type).
func (n *Node) String() string {
switch n.Type {
case NodeTypeMiddle: // {Type || ChildL || ChildR}
return fmt.Sprintf("Middle L:%s R:%s", n.ChildL, n.ChildR)
case NodeTypeLeaf: // {Type || Data...}
return fmt.Sprintf("Leaf I:%v D:%v", n.Entry[0], n.Entry[1])
case NodeTypeEmpty: // {}
return "Empty"
default:
return "Invalid Node"
}
}