Skip to content
This repository has been archived by the owner on Jan 19, 2021. It is now read-only.

Commit

Permalink
Merge pull request #27 from ethereumjs/new-release
Browse files Browse the repository at this point in the history
[Release] v2.3.0
  • Loading branch information
holgerd77 authored Nov 30, 2017
2 parents df14ad1 + 580589e commit d3baf12
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 27 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
(modification: no type change headlines) and this project adheres to
[Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [2.3.0] - 2017-11-30
- Methods for merkle proof generation ``Trie.prove()`` and verification ``Trie.verifyProof()`` (see [./proof.js](./proof.js))

[2.3.0]: https://github.com/ethereumjs/merkle-patricia-tree/compare/v2.2.0...v2.3.0

## [2.2.0] - 2017-08-03
- Renamed ``root`` functions argument to ``nodeRef`` for passing a node reference
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ The only backing store supported is LevelDB through the ```levelup``` module.
`npm install merkle-patricia-tree`

# USAGE

## Initialization and Basic Usage

```javascript
var Trie = require('merkle-patricia-tree'),
levelup = require('levelup'),
Expand All @@ -30,6 +33,19 @@ trie.put('test', 'one', function () {
});
```

## Merkle Proofs

```javascript
Trie.prove(trie, 'test', function (err, prove) {
if (err) return cb(err)
Trie.verifyProof(trie.root, 'test', prove, function (err, value) {
if (err) return cb(err)
console.log(value.toString())
cb()
})
})
```

# API
[./docs/](./docs/index.md)

Expand Down
62 changes: 45 additions & 17 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,51 @@ Reverts the trie to the state it was at when `checkpoint` was first called.

- `cb` **Function** the callback

## findPath

[baseTrie.js:252-300](https://github.com/wanderer/merkle-patricia-tree/blob/dc436426d717fed408f4d46fed23f6d26d03d39d/baseTrie.js#L252-L300 "Source code on GitHub")

Trys to find a path to the node for the given key.
It returns a `stack` of nodes to the closet node.

**Parameters**

- `Function` cb - the callback function. Its is given the following
arguments- err - any errors encontered
- node - the last node found
- keyRemainder - the remaining key nibbles not accounted for
- stack - an array of nodes that forms the path to node we are searching for
- `targetKey`
- `cb`

# Merkle Proof
Static functions for creating/verifying a merkle proof.

## prove

[proof.js:12-29](https://github.com/ethereumjs/merkle-patricia-tree/blob/df14ad1fbf861160abdb5954973cf4a570473ce9/proof.js#L12-L29 "Source code on GitHub")

Returns a merkle proof for a given key

**Parameters**

- `trie` **Trie**
- `key` **String**
- `cb` **Function** A callback `Function` (arguments {Error} `err`, {Array.<TrieNode>} `proof`)

## verifyProof

[proof.js:39-95](https://github.com/ethereumjs/merkle-patricia-tree/blob/df14ad1fbf861160abdb5954973cf4a570473ce9/proof.js#L39-L95 "Source code on GitHub")

Verifies a merkle proof for a given key

**Parameters**

- `rootHash` **Buffer**
- `key` **String**
- `proof` **Array&lt;TrieNode&gt;**
- `cb` **Function** A callback `Function` (arguments {Error} `err`, {String} `val`)


# Internal Util Functions
These are not exposed.
Expand Down Expand Up @@ -220,23 +265,6 @@ Returns the number of in order matching nibbles of two give nibble arrayes
- `nib1` **Array**
- `nib2` **Array**

## _findPath

[baseTrie.js:252-300](https://github.com/wanderer/merkle-patricia-tree/blob/dc436426d717fed408f4d46fed23f6d26d03d39d/baseTrie.js#L252-L300 "Source code on GitHub")

Trys to find a path to the node for the given key.
It returns a `stack` of nodes to the closet node.

**Parameters**

- `Function` cb - the callback function. Its is given the following
arguments- err - any errors encontered
- node - the last node found
- keyRemainder - the remaining key nibbles not accounted for
- stack - an array of nodes that forms the path to node we are searching for
- `targetKey`
- `cb`

## _saveStack

[baseTrie.js:502-529](https://github.com/wanderer/merkle-patricia-tree/blob/dc436426d717fed408f4d46fed23f6d26d03d39d/baseTrie.js#L502-L529 "Source code on GitHub")
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "merkle-patricia-tree",
"version": "2.2.0",
"version": "2.3.0",
"description": "This is an implementation of the modified merkle patricia tree as speficed in the Ethereum's yellow paper.",
"main": "index.js",
"scripts": {
Expand All @@ -12,7 +12,7 @@
"test:browser": "karma start karma.conf.js",
"test:node": "tape ./test/*.js",
"build": "browserify --s Trie index.js > ./dist/trie.js",
"build:docs": "documentation --github -f md ./index.js ./secure.js > ./docs/index.md"
"build:docs": "documentation --github -f md ./index.js ./secure.js ./proof.js > ./docs/index-template.md"
},
"author": {
"name": "mjbecze",
Expand Down
31 changes: 23 additions & 8 deletions proof.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ const TrieNode = require('./trieNode')
const ethUtil = require('ethereumjs-util')
const matchingNibbleLength = require('./util').matchingNibbleLength

/**
* Returns a merkle proof for a given key
* @method Trie.prove
* @param {Trie} trie
* @param {String} key
* @param {Function} cb A callback `Function` (arguments {Error} `err`, {Array.<TrieNode>} `proof`)
*/
exports.prove = function (trie, key, cb) {
var nodes

Expand All @@ -21,21 +28,29 @@ exports.prove = function (trie, key, cb) {
})
}

/**
* Verifies a merkle proof for a given key
* @method Trie.verifyProof
* @param {Buffer} rootHash
* @param {String} key
* @param {Array.<TrieNode>} proof
* @param {Function} cb A callback `Function` (arguments {Error} `err`, {String} `val`)
*/
exports.verifyProof = function (rootHash, key, proof, cb) {
key = TrieNode.stringToNibbles(key)
var wantHash = ethUtil.toBuffer(rootHash)
for (var i = 0; i < proof.length; i++) {
var p = ethUtil.toBuffer(proof[i])
var hash = ethUtil.sha3(proof[i])
if (Buffer.compare(hash, wantHash)) {
return cb(new Error('bad proof node ' + i + ': hash mismatch'))
return cb(new Error('Bad proof node ' + i + ': hash mismatch'))
}
var node = new TrieNode(ethUtil.rlp.decode(p))
var cld
if (node.type === 'branch') {
if (key.length === 0) {
if (i !== proof.length - 1) {
return cb(new Error('additional nodes at end of proof'))
return cb(new Error('Additional nodes at end of proof (branch)'))
}
return cb(null, node.value)
}
Expand All @@ -44,29 +59,29 @@ exports.verifyProof = function (rootHash, key, proof, cb) {
if (cld.length === 2) {
var embeddedNode = new TrieNode(cld)
if (i !== proof.length - 1) {
return cb(new Error('Key does not match with the proof one'))
return cb(new Error('Additional nodes at end of proof (embeddedNode)'))
}

if (matchingNibbleLength(embeddedNode.key, key) !== embeddedNode.key.length) {
return cb(new Error('Key does not match with the proof one'))
return cb(new Error('Key length does not match with the proof one (embeddedNode)'))
}
key = key.slice(embeddedNode.key.length)
if (key.length !== 0) {
return cb(new Error('Key does not match with the proof one'))
return cb(new Error('Key does not match with the proof one (embeddedNode)'))
}
return cb(null, embeddedNode.value)
} else {
wantHash = cld
}
} else if ((node.type === 'extention') || (node.type === 'leaf')) {
if (matchingNibbleLength(node.key, key) !== node.key.length) {
return cb(new Error('Key does not match with the proof one'))
return cb(new Error('Key does not match with the proof one (extention|leaf)'))
}
cld = node.value
key = key.slice(node.key.length)
if (key.length === 0) {
if (i !== proof.length - 1) {
return cb(new Error('Key does not match with the proof one'))
return cb(new Error('Additional nodes at end of proof (extention|leaf)'))
}
return cb(null, cld)
} else {
Expand All @@ -76,5 +91,5 @@ exports.verifyProof = function (rootHash, key, proof, cb) {
return cb(new Error('Invalid node type'))
}
}
cb(new Error('unexpected end of proof'))
cb(new Error('Unexpected end of proof'))
}
28 changes: 28 additions & 0 deletions test/proof.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,34 @@ tape('simple merkle proofs generation and verification', function (tester) {
cb()
})
})
},
function (cb) {
Trie.prove(trie, 'key2bb', function (err, prove) {
if (err) return cb(err)
Trie.verifyProof(trie.root, 'randomkey', prove, function (err, val) {
t.notEqual(err, null, 'Expected error: ' + err.message)
cb()
})
})
},
function (cb) {
Trie.prove(trie, 'key2bb', function (err, prove) {
if (err) return cb(err)
Trie.verifyProof(trie.root, 'key2b', prove, function (err, val) {
t.notEqual(err, null, 'Expected error: ' + err.message)
cb()
})
})
},
function (cb) {
Trie.prove(trie, 'key2bb', function (err, prove) {
if (err) return cb(err)
prove.push(Buffer.from('123456'))
Trie.verifyProof(trie.root, 'key2b', prove, function (err, val) {
t.notEqual(err, null, 'Expected error: ' + err.message)
cb()
})
})
}
], function (err) {
t.end(err)
Expand Down

0 comments on commit d3baf12

Please sign in to comment.