1
1
pragma solidity ^ 0.4.24 ;
2
2
3
+ import {D} from "./data.sol " ;
3
4
import {PatriciaTree} from "./tree.sol " ;
4
5
5
6
contract PatriciaTreeImplementation {
@@ -13,6 +14,10 @@ contract PatriciaTreeImplementation {
13
14
return tree.get (key);
14
15
}
15
16
17
+ function getValue (bytes32 hash ) public view returns (bytes ) {
18
+ return tree.values[hash];
19
+ }
20
+
16
21
function getRootHash () public view returns (bytes32 ) {
17
22
return tree.getRootHash ();
18
23
}
@@ -37,3 +42,140 @@ contract PatriciaTreeImplementation {
37
42
tree.insert (key, value);
38
43
}
39
44
}
45
+
46
+ contract PatriciaTreeMerkleProof {
47
+ using PatriciaTree for PatriciaTree.Tree;
48
+ PatriciaTree.Tree tree;
49
+
50
+ enum Status {OPENED, ONGOING, SUCCESS, FAILURE}
51
+
52
+ event OnChangeStatus (Status s );
53
+
54
+ modifier onlyFor (Status _status ) {
55
+ require (status == _status);
56
+ _;
57
+ }
58
+
59
+ mapping (bytes32 => bool ) committedValues;
60
+
61
+ Status public status;
62
+ D.Edge originalRootEdge;
63
+ bytes32 originalRoot;
64
+ D.Edge targetRootEdge;
65
+ bytes32 targetRoot;
66
+
67
+ constructor () public {
68
+ // Init status
69
+ status = Status.OPENED;
70
+ }
71
+
72
+ function commitOriginalEdge (
73
+ uint _originalLabelLength ,
74
+ bytes32 _originalLabel ,
75
+ bytes32 _originalValue
76
+ ) public onlyFor (Status.OPENED) {
77
+ // Init original root edge
78
+ originalRootEdge.label = D.Label (_originalLabel, _originalLabelLength);
79
+ originalRootEdge.node = _originalValue;
80
+ originalRoot = PatriciaTree.edgeHash (originalRootEdge);
81
+ }
82
+
83
+ function commitTargetEdge (
84
+ uint _targetLabelLength ,
85
+ bytes32 _targetLabel ,
86
+ bytes32 _targetValue
87
+ ) public onlyFor (Status.OPENED) {
88
+ // Init target root edge
89
+ targetRootEdge.label = D.Label (_targetLabel, _targetLabelLength);
90
+ targetRootEdge.node = _targetValue;
91
+ targetRoot = PatriciaTree.edgeHash (targetRootEdge);
92
+ }
93
+
94
+ function insert (bytes key , bytes value ) public {
95
+ bytes32 k = keccak256 (value);
96
+ committedValues[k] = true ;
97
+ tree.insert (key, value);
98
+ }
99
+
100
+ function commitNode (
101
+ bytes32 nodeHash ,
102
+ uint firstEdgeLabelLength ,
103
+ bytes32 firstEdgeLabel ,
104
+ bytes32 firstEdgeValue ,
105
+ uint secondEdgeLabelLength ,
106
+ bytes32 secondEdgeLabel ,
107
+ bytes32 secondEdgeValue
108
+ ) public onlyFor (Status.OPENED) {
109
+ D.Label memory k0 = D.Label (firstEdgeLabel, firstEdgeLabelLength);
110
+ D.Edge memory e0 = D.Edge (firstEdgeValue, k0);
111
+ D.Label memory k1 = D.Label (secondEdgeLabel, secondEdgeLabelLength);
112
+ D.Edge memory e1 = D.Edge (secondEdgeValue, k1);
113
+ require (tree.nodes[nodeHash].children[0 ].node == 0 );
114
+ require (tree.nodes[nodeHash].children[1 ].node == 0 );
115
+ require (nodeHash == keccak256 (
116
+ abi.encodePacked (PatriciaTree.edgeHash (e0), PatriciaTree.edgeHash (e1)))
117
+ );
118
+ tree.nodes[nodeHash].children[0 ] = e0;
119
+ tree.nodes[nodeHash].children[1 ] = e1;
120
+ }
121
+
122
+ function commitValue (bytes value ) public onlyFor (Status.OPENED) {
123
+ bytes32 k = keccak256 (value);
124
+ committedValues[k] = true ;
125
+ tree.values[k] = value;
126
+ }
127
+
128
+ function seal () public onlyFor (Status.OPENED) {
129
+ // require(_verifyEdge(originalRootEdge));
130
+ tree.rootEdge = originalRootEdge;
131
+ tree.root = PatriciaTree.edgeHash (tree.rootEdge);
132
+ _changeStatus (Status.ONGOING);
133
+ }
134
+
135
+ function proof () public onlyFor (Status.ONGOING) {
136
+ require (targetRootEdge.node == tree.rootEdge.node);
137
+ require (targetRootEdge.label.length == tree.rootEdge.label.length );
138
+ require (targetRootEdge.label.data == tree.rootEdge.label.data);
139
+ require (_verifyEdge (tree.rootEdge));
140
+ _changeStatus (Status.SUCCESS);
141
+ }
142
+
143
+ function getRootHash () public view returns (bytes32 ) {
144
+ return tree.getRootHash ();
145
+ }
146
+
147
+ function _verifyEdge (D.Edge memory _edge ) internal view returns (bool ) {
148
+ if (_edge.node == 0 ) {
149
+ // Empty. Return true because there is nothing to verify
150
+ return true ;
151
+ } else if (_isLeaf (_edge)) {
152
+ // check stored value of the leaf node
153
+ require (_hasValue (_edge.node));
154
+ } else {
155
+ D.Edge[2 ] memory children = tree.nodes[_edge.node].children;
156
+ // its node value should be the hashed value of its child nodes
157
+ require (_edge.node == keccak256 (
158
+ abi.encodePacked (PatriciaTree.edgeHash (children[0 ]), PatriciaTree.edgeHash (children[1 ]))
159
+ ));
160
+ // check children recursively
161
+ require (_verifyEdge (children[0 ]));
162
+ require (_verifyEdge (children[1 ]));
163
+ }
164
+ return true ;
165
+ }
166
+
167
+ function _isLeaf (D.Edge _edge ) internal view returns (bool ) {
168
+ return (tree.nodes[_edge.node].children[0 ].node == 0 && tree.nodes[_edge.node].children[1 ].node == 0 );
169
+ }
170
+
171
+ function _hasValue (bytes32 valHash ) internal view returns (bool ) {
172
+ return committedValues[valHash];
173
+ }
174
+
175
+ function _changeStatus (Status _status ) internal {
176
+ require (status < _status);
177
+ // unidirectional
178
+ status = _status;
179
+ emit OnChangeStatus (status);
180
+ }
181
+ }
0 commit comments