Skip to content

Commit f5486cd

Browse files
committed
Add merkle proof implementation
1 parent d00bf8b commit f5486cd

File tree

2 files changed

+415
-0
lines changed

2 files changed

+415
-0
lines changed

contracts/implementation.sol

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pragma solidity ^0.4.24;
22

3+
import {D} from "./data.sol";
34
import {PatriciaTree} from "./tree.sol";
45

56
contract 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

Comments
 (0)