This repository has been archived by the owner on Mar 14, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
Sarvesh/merkel patricia proof generator #139
Merged
sunilkhedar
merged 24 commits into
feature/proof
from
sarvesh/merkel-patricia-proof-generator
Jul 9, 2018
Merged
Changes from 17 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
7d8b228
Adding proof generation service, account_proof_generation, storage_pr…
d593df3
Corrected path generation and storage root generation
9c65ba2
Added service for proof generation
91bd438
Added unit tests for storage proof and file restructuring
a28ff4b
Generating storage proof in batches
8146b37
Corrected constants file error
b33d3ae
Added logic for case insensitivity of levedb
cd6960b
Added general exception handling in service layer
42132f2
Converted proof.js to a class and prototype structure, enhanced comments
b87985e
Added unit test cases of helper and proof lib
28dc10d
Returning RLP encoded data as proof and using response help successWi…
96db709
Increasing mocha test timeout time
f669407
Seperated unit and integration tests folder as they were impacting ea…
3731ecb
Added test scripts for unit tests and integration tests, updated trav…
90f9aca
Refactoring: changing multiple let to single, and oThis to const type
0cc155f
Merge branch 'feature/proof' into sarvesh/merkel-patricia-proof-gener…
83a5159
Corrected travis entry for feature/proof trigger
7d5d03d
Update return type of storage proof generation, returing map of key V…
5a6781d
Corrected return type of storage proof and service in manifest
816b72a
Added read me details for proof generation service in configure.md
d3c6676
Freezing version of dependency in package.json
0705ba4
Renamed variable StorageProof to storageProof
2d4fa0d
renamed variable AccountProof to AccountProofKlass
caaeff9
Merge branch 'feature/proof' into sarvesh/merkel-patricia-proof-gener…
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
const leveldown = require('leveldown') | ||
, levelup = require('levelup') | ||
; | ||
|
||
/** | ||
* @constructor | ||
*/ | ||
function LevelDBFactory() { | ||
this.instanceMap = {}; | ||
} | ||
|
||
LevelDBFactory.prototype = { | ||
/** | ||
* Returns leveldb instance, it creates new in not already exists otherwise returns existing instance | ||
* @param dbPath | ||
* @return leveldb instance | ||
*/ | ||
getInstance: function (dbPath) { | ||
const oThis = this; | ||
|
||
let lowerCasePath = dbPath.toLowerCase(); | ||
|
||
if (!oThis.instanceMap[lowerCasePath]) { | ||
oThis.instanceMap[lowerCasePath] = oThis.create(lowerCasePath); | ||
} | ||
return oThis.instanceMap[lowerCasePath]; | ||
}, | ||
|
||
/** | ||
* | ||
* @param dbPath | ||
* @return leveldb instance | ||
*/ | ||
create: function (dbPath) { | ||
return levelup(leveldown(dbPath)); | ||
}, | ||
}; | ||
module.exports = new LevelDBFactory(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
const Trie = require('merkle-patricia-tree'); | ||
|
||
const rootPrefix = "../.." | ||
, logger = require(rootPrefix + '/helpers/custom_console_logger') | ||
, responseHelper = require(rootPrefix + '/lib/formatter/response') | ||
, proof = require(rootPrefix + "/lib/proof/proof") | ||
, basicHelper = require(rootPrefix + '/helpers/basic_helper') | ||
; | ||
|
||
/** | ||
* @constructor | ||
* @param stateRoot | ||
* @param db | ||
*/ | ||
function AccountProof(stateRoot, db) { | ||
const oThis = this; | ||
|
||
oThis.trie = new Trie(db, stateRoot); | ||
} | ||
|
||
AccountProof.prototype = { | ||
|
||
/** | ||
* Validate and _build proof | ||
* @param address | ||
* @return {Promise<proof>} | ||
*/ | ||
perform: async function (address) { | ||
const oThis = this; | ||
|
||
await oThis._validate(address); | ||
return oThis._build(address); | ||
}, | ||
/** | ||
* Delegates call to _build account proof to lib | ||
* @param address | ||
* @return {Promise<proof>} | ||
*/ | ||
_build: async function (address) { | ||
const oThis = this; | ||
|
||
return proof.accountProof(address, oThis.trie); | ||
}, | ||
/** | ||
* Validate input | ||
* @param address | ||
* @private | ||
*/ | ||
_validate: async function (address) { | ||
const oThis = this; | ||
|
||
let errorConf = { | ||
internal_error_identifier: "s_p_ap_validate_2", | ||
debug_options: {}, | ||
error_config: basicHelper.fetchErrorConfig() | ||
}; | ||
|
||
if (!oThis.trie || oThis.trie.root === oThis.trie.EMPTY_TRIE_ROOT) { | ||
errorConf.api_error_identifier = "tree_not_initialized"; | ||
let errorResponse = responseHelper.error(errorConf); | ||
return Promise.reject(errorResponse); | ||
} | ||
if (address === undefined) { | ||
logger.error("Account address is invalid"); | ||
errorConf.api_error_identifier = "account_address_undefined"; | ||
let errorResponse = responseHelper.error(errorConf); | ||
return Promise.reject(errorResponse); | ||
} | ||
} | ||
}; | ||
|
||
module.exports = AccountProof; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
const ethUtils = require('ethereumjs-util'); | ||
|
||
const rootPrefix = '../..' | ||
, AccountProof = require(rootPrefix + '/lib/proof/account_proof') | ||
; | ||
|
||
/** | ||
* Constructor for helper methods class - ProofHelperKlass | ||
* @constructor | ||
*/ | ||
|
||
const ProofHelperKlass = function () { | ||
}; | ||
|
||
ProofHelperKlass.prototype = { | ||
|
||
/** | ||
* @notice left-pad value to make length 32 bytes | ||
* @param value | ||
* @return {string} padded value of length 32 bytes i.e. 64 nibbles | ||
* @private | ||
*/ | ||
_leftPad: function (value) { | ||
return ("0000000000000000000000000000000000000000000000000000000000000000" + value).substring(value.length) | ||
}, | ||
/** | ||
*@notice generates storagePath of a variable in the storage | ||
* @param storageIndex | ||
* @param mappings, key of mapping variable | ||
* @return {Buffer2} | ||
*/ | ||
storagePath: function (storageIndex, mappings) { | ||
|
||
let path = Buffer.from(this._leftPad(storageIndex), 'hex'); | ||
if (mappings && mappings.length > 0) { | ||
mappings.map(mapping => { | ||
path = Buffer.concat([Buffer.from(this._leftPad(mapping), 'hex'), path]) | ||
}); | ||
path = Buffer.from(ethUtils.sha3(path), 'hex') | ||
} | ||
path = Buffer.from(ethUtils.sha3(path), 'hex'); | ||
return path; | ||
}, | ||
|
||
/** | ||
* @notice generates storage root of a contract | ||
* @param stateRoot | ||
* @param contractAddress | ||
* @param db level db instace | ||
* @return {Promise<string>} | ||
* @private | ||
*/ | ||
fetchStorageRoot: async function (stateRoot, contractAddress, db) { | ||
|
||
let accountProofInstance = new AccountProof(stateRoot, db) | ||
, accountProof = await accountProofInstance.perform(contractAddress) | ||
, accountValue = accountProof.toHash().data.value | ||
, decodedValue = ethUtils.rlp.decode('0x' + accountValue); | ||
|
||
return '0x' + decodedValue[2].toString('hex'); | ||
} | ||
}; | ||
|
||
module.exports = new ProofHelperKlass(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
const rootPrefix = "../.." | ||
, ethUtils = require('ethereumjs-util') | ||
, logger = require(rootPrefix + '/helpers/custom_console_logger') | ||
, responseHelper = require(rootPrefix + '/lib/formatter/response') | ||
, basicHelper = require(rootPrefix + '/helpers/basic_helper') | ||
; | ||
|
||
|
||
function Proof() { | ||
|
||
} | ||
|
||
|
||
Proof.prototype = { | ||
/** | ||
* Generate Account proof for give address in merkel patricia tree | ||
* @param address | ||
* @param trie | ||
* @return {Promise<proof>} | ||
*/ | ||
accountProof: function (address, trie) { | ||
|
||
let errorConf = { | ||
internal_error_identifier: "l_p_accountProof_1", | ||
debug_options: {}, | ||
error_config: basicHelper.fetchErrorConfig() | ||
} | ||
, path = Buffer.from(ethUtils.sha3(Buffer.from(address, 'hex')), 'hex'); | ||
|
||
logger.info('Generating account proof'); | ||
return new Promise(function (resolve, reject) { | ||
|
||
return trie.findPath(path, function (error, accountNode, keyRemainder, rootToLeafPath) { | ||
if (error || !accountNode || keyRemainder.length > 0) { | ||
errorConf.api_error_identifier = "account_node_not_found"; | ||
errorConf.debug_options = {error}; | ||
let errorResponse = responseHelper.error(errorConf); | ||
return reject(errorResponse); | ||
} | ||
let parentNodes = rootToLeafPath.map(node => node.raw) | ||
, proof = { | ||
address: address, | ||
parentNodes: ethUtils.rlp.encode(parentNodes).toString('hex'), | ||
value: accountNode.value.toString('hex') | ||
}; | ||
return resolve(responseHelper.successWithData(proof)); | ||
}); | ||
}); | ||
}, | ||
|
||
/** | ||
* Generate Storage proof for give storagePath in merkel patricia tree | ||
* @param storagePath | ||
* @param trie | ||
* @return {Promise<proof>} | ||
*/ | ||
storageProof: function (storagePath, trie) { | ||
|
||
let errorConf = { | ||
internal_error_identifier: "l_p_accountProof_2", | ||
debug_options: {}, | ||
error_config: basicHelper.fetchErrorConfig() | ||
}; | ||
return new Promise(function (resolve, reject) { | ||
return trie.findPath(storagePath, function (error, storageNode, keyRemainder, rootToLeafPath) { | ||
|
||
if (error || !storageNode || keyRemainder.length > 0) { | ||
logger.error(error || 'Unable to find storage node in the tree'); | ||
errorConf.api_error_identifier = "storage_node_not_found"; | ||
errorConf.debug_options = {error}; | ||
let errorResponse = responseHelper.error(errorConf); | ||
return reject(errorResponse); | ||
} | ||
let parentNodes = rootToLeafPath.map(node => node.raw) | ||
, proof = { | ||
parentNodes: ethUtils.rlp.encode(parentNodes).toString('hex'), | ||
value: storageNode.value.toString('hex') | ||
}; | ||
return resolve(responseHelper.successWithData(proof)); | ||
}) | ||
}); | ||
} | ||
|
||
}; | ||
|
||
module.exports = new Proof(); | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not so critical but like to mention here.
General observation: we follow a pattern to create internal_error_identifier.
Lets take this example, file path is
lib/proof/proof.js
, function name isstorageProof
So the internal_error_identifier will be in this case:
l_p_p_storageProof_1
If we are still following pattern then we need to update
internal_error_identifier
at multiple locations.