11pragma solidity ^ 0.4.24 ;
22
3+ import {D} from "./data.sol " ;
34import {PatriciaTree} from "./tree.sol " ;
45
56contract PatriciaTreeImplementation {
@@ -13,6 +14,10 @@ contract PatriciaTreeImplementation {
1314 return tree.get (key);
1415 }
1516
17+ function getValue (bytes32 hash ) public view returns (bytes ) {
18+ return tree.values[hash];
19+ }
20+
1621 function getRootHash () public view returns (bytes32 ) {
1722 return tree.getRootHash ();
1823 }
@@ -37,3 +42,140 @@ contract PatriciaTreeImplementation {
3742 tree.insert (key, value);
3843 }
3944}
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