Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions contracts/implementation.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pragma solidity ^0.4.24;

import {D} from "./data.sol";
import {PatriciaTree} from "./tree.sol";

contract PatriciaTreeImplementation {
Expand All @@ -13,6 +14,10 @@ contract PatriciaTreeImplementation {
return tree.get(key);
}

function getValue(bytes32 hash) public view returns (bytes) {
return tree.values[hash];
}

function getRootHash() public view returns (bytes32) {
return tree.getRootHash();
}
Expand All @@ -37,3 +42,140 @@ contract PatriciaTreeImplementation {
tree.insert(key, value);
}
}

contract PatriciaTreeMerkleProof {
using PatriciaTree for PatriciaTree.Tree;
PatriciaTree.Tree tree;

enum Status {OPENED, ONGOING, SUCCESS, FAILURE}

event OnChangeStatus(Status s);

modifier onlyFor(Status _status) {
require(status == _status);
_;
}

mapping(bytes32 => bool) committedValues;

Status public status;
D.Edge originalRootEdge;
bytes32 originalRoot;
D.Edge targetRootEdge;
bytes32 targetRoot;

constructor() public {
// Init status
status = Status.OPENED;
}

function commitOriginalEdge(
uint _originalLabelLength,
bytes32 _originalLabel,
bytes32 _originalValue
) public onlyFor(Status.OPENED) {
// Init original root edge
originalRootEdge.label = D.Label(_originalLabel, _originalLabelLength);
originalRootEdge.node = _originalValue;
originalRoot = PatriciaTree.edgeHash(originalRootEdge);
}

function commitTargetEdge(
uint _targetLabelLength,
bytes32 _targetLabel,
bytes32 _targetValue
) public onlyFor(Status.OPENED) {
// Init target root edge
targetRootEdge.label = D.Label(_targetLabel, _targetLabelLength);
targetRootEdge.node = _targetValue;
targetRoot = PatriciaTree.edgeHash(targetRootEdge);
}

function insert(bytes key, bytes value) public {
bytes32 k = keccak256(value);
committedValues[k] = true;
tree.insert(key, value);
}

function commitNode(
bytes32 nodeHash,
uint firstEdgeLabelLength,
bytes32 firstEdgeLabel,
bytes32 firstEdgeValue,
uint secondEdgeLabelLength,
bytes32 secondEdgeLabel,
bytes32 secondEdgeValue
) public onlyFor(Status.OPENED) {
D.Label memory k0 = D.Label(firstEdgeLabel, firstEdgeLabelLength);
D.Edge memory e0 = D.Edge(firstEdgeValue, k0);
D.Label memory k1 = D.Label(secondEdgeLabel, secondEdgeLabelLength);
D.Edge memory e1 = D.Edge(secondEdgeValue, k1);
require(tree.nodes[nodeHash].children[0].node == 0);
require(tree.nodes[nodeHash].children[1].node == 0);
require(nodeHash == keccak256(
abi.encodePacked(PatriciaTree.edgeHash(e0), PatriciaTree.edgeHash(e1)))
);
tree.nodes[nodeHash].children[0] = e0;
tree.nodes[nodeHash].children[1] = e1;
}

function commitValue(bytes value) public onlyFor(Status.OPENED) {
bytes32 k = keccak256(value);
committedValues[k] = true;
tree.values[k] = value;
}

function seal() public onlyFor(Status.OPENED) {
// require(_verifyEdge(originalRootEdge));
tree.rootEdge = originalRootEdge;
tree.root = PatriciaTree.edgeHash(tree.rootEdge);
_changeStatus(Status.ONGOING);
}

function proof() public onlyFor(Status.ONGOING) {
require(targetRootEdge.node == tree.rootEdge.node);
require(targetRootEdge.label.length == tree.rootEdge.label.length);
require(targetRootEdge.label.data == tree.rootEdge.label.data);
require(_verifyEdge(tree.rootEdge));
_changeStatus(Status.SUCCESS);
}

function getRootHash() public view returns (bytes32) {
return tree.getRootHash();
}

function _verifyEdge(D.Edge memory _edge) internal view returns (bool) {
if (_edge.node == 0) {
// Empty. Return true because there is nothing to verify
return true;
} else if (_isLeaf(_edge)) {
// check stored value of the leaf node
require(_hasValue(_edge.node));
} else {
D.Edge[2] memory children = tree.nodes[_edge.node].children;
// its node value should be the hashed value of its child nodes
require(_edge.node == keccak256(
abi.encodePacked(PatriciaTree.edgeHash(children[0]), PatriciaTree.edgeHash(children[1]))
));
// check children recursively
require(_verifyEdge(children[0]));
require(_verifyEdge(children[1]));
}
return true;
}

function _isLeaf(D.Edge _edge) internal view returns (bool) {
return (tree.nodes[_edge.node].children[0].node == 0 && tree.nodes[_edge.node].children[1].node == 0);
}

function _hasValue(bytes32 valHash) internal view returns (bool) {
return committedValues[valHash];
}

function _changeStatus(Status _status) internal {
require(status < _status);
// unidirectional
status = _status;
emit OnChangeStatus(status);
}
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "solidity-patricia-tree",
"version": "1.0.3",
"version": "1.0.4",
"description": "Patricia Tree solidity implemenation",
"directories": {
"test": "test"
Expand Down
Loading