-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnode.go
208 lines (165 loc) · 6.02 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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
package mpt
import (
"fmt"
"io"
"github.com/mit-dci/go-bverify/utils"
)
// NodeType is an enum for the various types of nodes we know.
// Used in serialization/deserialization
type NodeType byte
const (
// NodeTypeStub indicates the node is of type Stub
NodeTypeStub NodeType = 0x00
// NodeTypeDictionaryLeaf indicates the node is of type DictionaryLeafNode
NodeTypeDictionaryLeaf NodeType = 0x01
// NodeTypeEmptyLeaf indicates the node is of type EmptyLeafNode
NodeTypeEmptyLeaf NodeType = 0x02
// NodeTypeInterior indicates the node is of type InteriorNode
NodeTypeInterior NodeType = 0x03
// NodeTypeSetLeaf indicates the node is of type SetLeafNode
NodeTypeSetLeaf NodeType = 0x04
)
// Node is the building blocks of the MPT data structure.
// A node is MUTABLE - the children of interior nodes can change
// and the value stored at a leaf node can change. Nodes track
// these changes and re-calculate hashes accordingly.
type Node interface {
// GetValue returns the value stored at this node, if it exists. This is only
// applicable for a non-empty leaf.
GetValue() []byte
// SetValue sets the value stored at this node, if it exists. This is only
// applicable for a non-empty leaf.
SetValue(value []byte)
// GetHash returns the hash of this node
GetHash() []byte
// GetGraphHash returns the hash of this node when presenting in a graph
// for most node types this'll be equal - but for EmptyLeafNodes this will
// hash the address of the object to make sure empty leaf nodes have unique
// hashes
GetGraphHash() []byte
// CountHashesRequiredForGetHash will count the number of hashes required
// to (re)calculate the hash of this Node
CountHashesRequiredForGetHash() int
// GetKey returns the key of this Node
GetKey() []byte
// IsLeaf will return true if this node is a (possibly empty) leaf
IsLeaf() bool
// IsEmpty returns true if this node is an empty leaf
IsEmpty() bool
// IsStub return true if this node is a stub
IsStub() bool
// GetLeftChild returns the left child of this node, if it exists
// Only applicable if this is an interior node
GetLeftChild() Node
// GetRightChild returns the right child of this node, if it exists
// Only applicable if this is an interior node
GetRightChild() Node
// SetLeftChild sets the left child of this node, if possible
// Only applicable if this is an interior node
SetLeftChild(child Node)
// SetRightChild sets the right child of this node, if possible
// Only applicable if this is an interior node
SetRightChild(child Node)
// Changed returns true if this node has been Changed
Changed() bool
// MarkChangedAll marks the entire (sub)tree rooted at this node as changed
MarkChangedAll()
// MarkUnchangedAll marks the entire (sub)tree rooted at this node as unchanged
MarkUnchangedAll()
// Serialize writes a serialized representation of this node into a io.Writer
Serialize(w io.Writer)
// ByteSize returns the length of Bytes() without actually serializing first
ByteSize() int
// NodesInSubtree returns the number of nodes of any kind in the subtree rooted
// at this node (includes this node).
NodesInSubtree() int
// InteriorNodesInSubtree returns the number of interior nodes in the subtree rooted
// at this node (includes this node).
InteriorNodesInSubtree() int
// EmptyLeafNodesInSubtree returns the number of empty leaf nodes in the subtree rooted
// at this node (includes this node).
EmptyLeafNodesInSubtree() int
// NonEmptyLeafNodesInSubtree returns the number of non-empty leaf nodes in the subtree rooted
// at this node (includes this node).
NonEmptyLeafNodesInSubtree() int
// Returns true if the passed node is equal to the object the method is called on
Equals(node Node) bool
// Writes a visualization of the node and its children to the writer in DOT format
WriteGraphNodes(w io.Writer)
// Dispose sets all used memory to nil and disposes children
Dispose()
DeepCopy() (Node, error)
}
// GetNodeHeight returns the height of a node in the MPT, calculated bottom (leaves) up.
func GetNodeHeight(node Node) int {
if node.IsLeaf() {
// each leaf is at height zero
return 0
}
return utils.Max(GetNodeHeight(node.GetLeftChild()), GetNodeHeight(node.GetRightChild())) + 1
}
// NodeFromBytes will deserialize the proper node type from a byte slice
func DeserializeNode(r io.Reader) (Node, error) {
typeByte := make([]byte, 1)
i, err := r.Read(typeByte)
if err != nil {
return nil, err
}
if i != 1 {
return nil, fmt.Errorf("Unable to read type byte")
}
if typeByte[0] == byte(NodeTypeStub) {
return DeserializeNewStub(r)
}
if typeByte[0] == byte(NodeTypeDictionaryLeaf) {
return DeserializeNewDictionaryLeafNode(r)
}
if typeByte[0] == byte(NodeTypeEmptyLeaf) {
return NewEmptyLeafNode()
}
if typeByte[0] == byte(NodeTypeInterior) {
return DeserializeNewInteriorNode(r)
}
return nil, fmt.Errorf("Unknown leaf type %x", typeByte[0])
}
// UpdateNodeFromBytes tries updating from the passed byte slice creating
// new nodes where it's not needed, preserving ones known in n and not in the update.
func UpdateNodeFromReader(n Node, r io.Reader) (Node, error) {
n2, err := DeserializeNode(r)
if err != nil {
return nil, err
}
return UpdateNode(n, n2)
}
// UpdateNode tries updating from the passed node creating
// new nodes where it's not needed, preserving ones known in n and not in the update.
func UpdateNode(n, n2 Node) (Node, error) {
// var err error
in, ok := n2.(*InteriorNode)
if ok {
var left Node
var right Node
if n != nil {
left = n.GetLeftChild()
right = n.GetRightChild()
}
if in.HasLeft() {
left, _ = UpdateNode(left, in.GetLeftChild())
// Error handling only needed when there's actual errors possible
// Not now, maybe remove error return?
/*if err != nil {
return nil, err
}*/
}
if in.HasRight() {
right, _ = UpdateNode(right, in.GetRightChild())
// Error handling only needed when there's actual errors possible
// Not now, maybe remove error return?
/*if err != nil {
return nil, err
}*/
}
return NewInteriorNode(left, right)
}
return n2, nil
}