@@ -75,19 +75,102 @@ class MerklePatriciaTrie[K, V] private (private[mpt] val rootNode: Option[MptNod
75
75
lazy val getRootHash : Array [Byte ] = rootNode.map(_.hash).getOrElse(EmptyRootHash )
76
76
77
77
/**
78
- * This function obtains the value asociated with the key passed, if there exists one.
78
+ * Get the value associated with the key passed, if there exists one.
79
79
*
80
80
* @param key
81
81
* @return Option object with value if there exists one.
82
82
* @throws io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException if there is any inconsistency in how the trie is build.
83
83
*/
84
84
def get (key : K ): Option [V ] = {
85
- rootNode flatMap { rootNode =>
86
- val keyNibbles = HexPrefix .bytesToNibbles(bytes = kSerializer.toBytes(key))
87
- get(rootNode, keyNibbles).map(bytes => vSerializer.fromBytes(bytes))
85
+ pathTraverse[Option [V ]](None , mkKeyNibbles(key)) { case (_, node) =>
86
+ node match {
87
+ case LeafNode (_, value, _, _, _) =>
88
+ Some (vSerializer.fromBytes(value.toArray[Byte ]))
89
+
90
+ case BranchNode (_, terminator, _, _, _) =>
91
+ terminator.map(term => vSerializer.fromBytes(term.toArray[Byte ]))
92
+
93
+ case _ => None
94
+ }
95
+ }.flatten
96
+ }
97
+
98
+ /**
99
+ * Get the proof associated with the key passed, if there exists one.
100
+ *
101
+ * @param key
102
+ * @return Option object with proof if there exists one.
103
+ * @throws io.iohk.ethereum.mpt.MerklePatriciaTrie.MPTException if there is any inconsistency in how the trie is build.
104
+ */
105
+ def getProof (key : K ): Option [Vector [MptNode ]] = {
106
+ pathTraverse[Vector [MptNode ]](Vector .empty, mkKeyNibbles(key)) { case (acc, node) =>
107
+ node match {
108
+ case nextNodeOnExt @ (_ : BranchNode | _ : ExtensionNode | _ : LeafNode ) => acc :+ nextNodeOnExt
109
+ case _ => acc
110
+ }
88
111
}
89
112
}
90
113
114
+ /**
115
+ * Traverse given path from the root to value and accumulate data.
116
+ * Only nodes which are significant for searching for value are taken into account.
117
+ *
118
+ * @param acc initial accumulator
119
+ * @param searchKey search key
120
+ * @param op accumulating operation
121
+ * @tparam T accumulator type
122
+ * @return accumulated data or None if key doesn't exist
123
+ */
124
+ private def pathTraverse [T ](acc : T , searchKey : Array [Byte ])(op : (T , MptNode ) => T ): Option [T ] = {
125
+
126
+ @ tailrec
127
+ def pathTraverse (acc : T , node : MptNode , searchKey : Array [Byte ], op : (T , MptNode ) => T ): Option [T ] = {
128
+ node match {
129
+ case LeafNode (key, _, _, _, _) =>
130
+ if (key.toArray[Byte ] sameElements searchKey) Some (op(acc, node)) else None
131
+
132
+ case extNode @ ExtensionNode (sharedKey, _, _, _, _) =>
133
+ val (commonKey, remainingKey) = searchKey.splitAt(sharedKey.length)
134
+ if (searchKey.length >= sharedKey.length && (sharedKey.toArray[Byte ] sameElements commonKey)) {
135
+ pathTraverse(op(acc, node), extNode.next, remainingKey, op)
136
+ } else None
137
+
138
+ case branch : BranchNode =>
139
+ if (searchKey.isEmpty) Some (op(acc, node))
140
+ else
141
+ pathTraverse(
142
+ op(acc, node),
143
+ branch.children(searchKey(0 )),
144
+ searchKey.slice(1 , searchKey.length),
145
+ op
146
+ )
147
+
148
+ case HashNode (bytes) =>
149
+ pathTraverse(acc, getFromHash(bytes, nodeStorage), searchKey, op)
150
+
151
+ case NullNode =>
152
+ None
153
+ }
154
+ }
155
+
156
+ rootNode match {
157
+ case Some (root) =>
158
+ pathTraverse(acc, root, searchKey, op)
159
+ case None =>
160
+ None
161
+ }
162
+ }
163
+
164
+ private def getFromHash (nodeId : Array [Byte ], source : MptStorage ): MptNode = {
165
+ val nodeEncoded = source.get(nodeId).encode
166
+ MptTraversals
167
+ .decodeNode(nodeEncoded)
168
+ .withCachedHash(nodeId)
169
+ .withCachedRlpEncoded(nodeEncoded)
170
+ }
171
+
172
+ private def mkKeyNibbles (key : K ): Array [Byte ] = HexPrefix .bytesToNibbles(kSerializer.toBytes(key))
173
+
91
174
/**
92
175
* This function inserts a (key-value) pair into the trie. If the key is already asociated with another value it is updated.
93
176
*
0 commit comments