Skip to content

Commit aa37890

Browse files
committed
Forked from solidity-patricia-tree
1 parent f5486cd commit aa37890

14 files changed

+6690
-1113
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ coverage
2222
coverage.json
2323
.coveralls.yml
2424

25-
# nyc test coverage
25+
# nyc tests coverage
2626
.nyc_output
2727

2828
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)

.solcover.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module.exports = {
22
compileCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle compile --network development',
3-
testCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle test --network development',
3+
testCommand: 'node --max-old-space-size=4096 ../node_modules/.bin/truffle tests --network development',
44
skipFiles: [
55
'contracts/Migrations.sol',
66
'contracts/implementation.sol'

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ install:
99
- npm install
1010

1111
script:
12-
- npm run test
12+
- npm run tests
1313

1414
after_success:
1515
- export CURRENT_VERSION=$(node -p "require('./package.json').version")

README.md

+48-40
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
# Solidity Patricia Tree
1+
# Solidity Sparse Tree
22

33
## Credits
44

5-
This is a rewritten version of [Christian Reitwießner](https://github.com/chriseth)'s [patricia-tree](https://github.com/chriseth/patricia-tree) to use his patricia tree implementation as a solidity library through npm.
5+
This implementation is based on [Christian Reitwießner](https://github.com/chriseth)'s [patricia-tree](https://github.com/chriseth/patricia-tree)
66

77

88
##### latest released version
9-
[![npm](https://img.shields.io/npm/v/solidity-patricia-tree/latest.svg)](https://www.npmjs.com/package/solidity-patricia-tree)
10-
[![Build Status](https://travis-ci.org/commitground/solidity-patricia-tree.svg?branch=master)](https://travis-ci.org/commitground/solidity-patricia-tree)
11-
[![Coverage Status](https://coveralls.io/repos/github/commitground/solidity-patricia-tree/badge.svg?branch=master)](https://coveralls.io/github/commitground/solidity-patricia-tree?branch=develop)
9+
[![npm](https://img.shields.io/npm/v/solidity-sparse-tree/latest.svg)](https://www.npmjs.com/package/solidity-sparse-tree)
10+
[![Build Status](https://travis-ci.org/commitground/solidity-sparse-tree.svg?branch=master)](https://travis-ci.org/commitground/solidity-sparse-tree)
11+
[![Coverage Status](https://coveralls.io/repos/github/commitground/solidity-sparse-tree/badge.svg?branch=master)](https://coveralls.io/github/commitground/solidity-sparse-tree?branch=develop)
1212

1313
##### in progress
14-
[![npm](https://img.shields.io/npm/v/solidity-patricia-tree/next.svg)](https://www.npmjs.com/package/solidity-patricia-tree)
15-
[![Build Status](https://travis-ci.org/commitground/solidity-patricia-tree.svg?branch=develop)](https://travis-ci.org/commitground/solidity-patricia-tree)
16-
[![Coverage Status](https://coveralls.io/repos/github/commitground/solidity-patricia-tree/badge.svg?branch=develop)](https://coveralls.io/github/commitground/solidity-patricia-tree?branch=develop)
14+
[![npm](https://img.shields.io/npm/v/solidity-sparse-tree/next.svg)](https://www.npmjs.com/package/solidity-sparse-tree)
15+
[![Build Status](https://travis-ci.org/commitground/solidity-sparse-tree.svg?branch=develop)](https://travis-ci.org/commitground/solidity-sparse-tree)
16+
[![Coverage Status](https://coveralls.io/repos/github/commitground/solidity-sparse-tree/badge.svg?branch=develop)](https://coveralls.io/github/commitground/solidity-sparse-tree?branch=develop)
1717

1818
[![JavaScript Style Guide](https://cdn.rawgit.com/standard/standard/master/badge.svg)](https://github.com/standard/standard)
1919

@@ -22,47 +22,57 @@ This is a rewritten version of [Christian Reitwießner](https://github.com/chris
2222
## Usage
2323

2424
```bash
25+
npm i solidity-sparse-tree
2526
npm i solidity-patricia-tree
2627
```
2728

2829
```solidity
30+
pragma solidity ^0.4.24;
2931
30-
pragma solidity ^0.4.25;
32+
import {SparseTree} from "solidity-sparse-tree/contracts/tree.sol";
33+
import {PatriciaTree} from "solidity-patricia-tree/contracts/tree.sol";
3134
32-
import {PatriciaTree} from "solidity-patricia-tree/contracts/tree.sol";
33-
34-
contract TestPatriciaTree {
35+
contract TestSparseTree {
36+
using SparseTree for SparseTree.Tree;
3537
using PatriciaTree for PatriciaTree.Tree;
36-
PatriciaTree.Tree tree;
3738
38-
function test() public {
39-
// testInsert();
40-
testProofs();
41-
}
39+
PatriciaTree.Tree patriciaTree;
40+
SparseTree.Tree sparseTree;
4241
43-
function testInsert() internal {
44-
tree.insert("one", "ONE");
45-
tree.insert("two", "ONE");
46-
tree.insert("three", "ONE");
47-
tree.insert("four", "ONE");
48-
tree.insert("five", "ONE");
49-
tree.insert("six", "ONE");
50-
tree.insert("seven", "ONE");
51-
// update
52-
tree.insert("one", "TWO");
53-
}
42+
/**
43+
* @dev we can reenact merkle tree transformation by submitting only referred siblings instead of submitting all nodes
44+
*/
45+
function testSparseTree() public {
46+
// update merkle root
47+
patriciaTree.insert("key1", "val1");
48+
patriciaTree.insert("key2", "val2");
49+
patriciaTree.insert("key3", "val3");
5450
55-
function testProofs() internal {
56-
tree.insert("one", "ONE");
51+
// root hash of patricia tree @ phase A
52+
bytes32 phaseAOfPatriciaTree = patriciaTree.getRootHash();
53+
54+
// get siblings to update "key1"
5755
uint branchMask;
5856
bytes32[] memory siblings;
59-
(branchMask, siblings) = tree.getProof("one");
60-
PatriciaTree.verifyProof(tree.root, "one", "ONE", branchMask, siblings);
61-
tree.insert("two", "TWO");
62-
(branchMask, siblings) = tree.getProof("one");
63-
PatriciaTree.verifyProof(tree.root, "one", "ONE", branchMask, siblings);
64-
(branchMask, siblings) = tree.getProof("two");
65-
PatriciaTree.verifyProof(tree.root, "two", "TWO", branchMask, siblings);
57+
(branchMask, siblings) = patriciaTree.getProof("key1");
58+
59+
// Init sparse tree with the root hash
60+
sparseTree.initialize(phaseAOfPatriciaTree);
61+
// commit branch (we submit sibling data here)
62+
sparseTree.commitBranch("key1", "val1", branchMask, siblings);
63+
64+
// Update key1 of patricia tree
65+
patriciaTree.insert("key1", "val4");
66+
67+
// Update key1 of sparse tree
68+
sparseTree.insert("key1", "val4");
69+
70+
// get updated root hashes of each tree
71+
bytes32 phaseBOfPatriciaTree = patriciaTree.getRootHash();
72+
bytes32 phaseBOfSparseTree = sparseTree.getRootHash();
73+
74+
// We have succeeded to reenact merkle tree transformation without submitting all node data
75+
require(phaseBOfPatriciaTree == phaseBOfSparseTree);
6676
}
6777
}
6878
```
@@ -74,7 +84,7 @@ contract TestPatriciaTree {
7484

7585
```bash
7686
npm install -g truffle
77-
npm install -g ganache
87+
npm install -g ganache-cli
7888
npm install
7989
```
8090

@@ -87,9 +97,7 @@ Running and reading the test cases will help you understand how it works.
8797
npm run test
8898
```
8999

90-
91100
## Contributors
92-
- Original author: [Christian Reitwießner](https://github.com/chriseth)
93101
- [Wanseob Lim](https://github.com/james-lim)<[[email protected]](mailto:[email protected])>
94102

95103
## License

contracts/data.sol

+9
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,20 @@ library D {
1212
}
1313

1414
struct Edge {
15+
bytes32 header; // variable for sparse tree <[email protected]>
1516
bytes32 node;
1617
Label label;
1718
}
1819

1920
struct Node {
2021
Edge[2] children;
2122
}
23+
24+
function isEmpty(Edge edge) internal pure returns (bool) {
25+
return (edge.header == bytes32(0) && edge.node == bytes32(0));
26+
}
27+
28+
function hasNode(Edge edge) internal pure returns (bool) {
29+
return (edge.node != bytes32(0));
30+
}
2231
}

contracts/implementation.sol

+16-155
Original file line numberDiff line numberDiff line change
@@ -1,181 +1,42 @@
11
pragma solidity ^0.4.24;
22

3-
import {D} from "./data.sol";
4-
import {PatriciaTree} from "./tree.sol";
3+
import {SparseTree} from "./tree.sol";
54

6-
contract PatriciaTreeImplementation {
7-
using PatriciaTree for PatriciaTree.Tree;
8-
PatriciaTree.Tree tree;
5+
contract SparseTreeImplementation {
6+
using SparseTree for SparseTree.Tree;
7+
SparseTree.Tree tree;
98

109
constructor () public {
1110
}
1211

13-
function get(bytes key) public view returns (bytes) {
14-
return tree.get(key);
15-
}
16-
17-
function getValue(bytes32 hash) public view returns (bytes) {
18-
return tree.values[hash];
19-
}
20-
21-
function getRootHash() public view returns (bytes32) {
22-
return tree.getRootHash();
23-
}
24-
25-
function getNode(bytes32 hash) public view returns (uint, bytes32, bytes32, uint, bytes32, bytes32) {
26-
return tree.getNode(hash);
27-
}
28-
29-
function getRootEdge() public view returns (uint, bytes32, bytes32) {
30-
return tree.getRootEdge();
31-
}
32-
33-
function getProof(bytes key) public view returns (uint branchMask, bytes32[] _siblings) {
34-
return tree.getProof(key);
35-
}
36-
37-
function verifyProof(bytes32 rootHash, bytes key, bytes value, uint branchMask, bytes32[] siblings) public pure {
38-
PatriciaTree.verifyProof(rootHash, key, value, branchMask, siblings);
39-
}
40-
41-
function insert(bytes key, bytes value) public {
42-
tree.insert(key, value);
43-
}
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-
_;
12+
function initialize (bytes32 initialRoot) public {
13+
tree.initialize(initialRoot);
5714
}
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-
9415
function insert(bytes key, bytes value) public {
95-
bytes32 k = keccak256(value);
96-
committedValues[k] = true;
9716
tree.insert(key, value);
9817
}
9918

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;
19+
function commitBranch(bytes key, bytes value, uint branchMask, bytes32[] siblings) public {
20+
return tree.commitBranch(key, value, branchMask, siblings);
12021
}
12122

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);
23+
function get(bytes key) public view returns (bytes) {
24+
return tree.get(key);
13325
}
13426

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);
27+
function getValue(bytes32 hash) public view returns (bytes) {
28+
return tree.values[hash];
14129
}
14230

14331
function getRootHash() public view returns (bytes32) {
14432
return tree.getRootHash();
14533
}
14634

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];
35+
function getProof(bytes key) public view returns (uint branchMask, bytes32[] _siblings) {
36+
return tree.getProof(key);
17337
}
17438

175-
function _changeStatus(Status _status) internal {
176-
require(status < _status);
177-
// unidirectional
178-
status = _status;
179-
emit OnChangeStatus(status);
39+
function verifyProof(bytes32 rootHash, bytes key, bytes value, uint branchMask, bytes32[] siblings) public pure {
40+
SparseTree.verifyProof(rootHash, key, value, branchMask, siblings);
18041
}
18142
}

0 commit comments

Comments
 (0)