Skip to content
This repository has been archived by the owner on Mar 14, 2019. It is now read-only.

Commit

Permalink
Merge pull request #139 from OpenSTFoundation/sarvesh/merkel-patricia…
Browse files Browse the repository at this point in the history
…-proof-generator

Sarvesh/merkel patricia proof generator
  • Loading branch information
sunilkhedar authored Jul 9, 2018
2 parents 6c7c7c4 + caaeff9 commit 013b4bc
Show file tree
Hide file tree
Showing 33 changed files with 1,149 additions and 20 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ branches:
- master
- develop
- release-0.9
- balances_model_and_cache
- feature/proof
notifications:
email:
recipients:
Expand Down Expand Up @@ -45,7 +45,8 @@ script:
- source $HOME/openst-setup/openst_env_vars.sh
- node tools/setup/branded_token/register.js "ACME Coin" "ACME" 10
- node tools/setup/branded_token/mint.js "ACME" 1000000000000000000000
- mocha --timeout 120000 test/* --exit
- npm run unit_test
- npm run integration_test
after_script:
- kill $(ps aux | grep 'tools/setup/start_services.js' | awk '{print $2}')
- kill $(ps aux | grep 'DynamoDBLocal.jar' | awk '{print $2}')
Expand Down
48 changes: 48 additions & 0 deletions CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,54 @@ serviceObj.perform().then(function(response) {
}
});
```
* Merkel Patricia Proof generation service
1. Account proof generation for an account
```
const platform = require('@openstfoundation/openst-platform');
let chainDataPath = '/path/to/geth/chain_data';
let stateRoot = '0x3d8fc3231b82a6673ebb934925ce8e8eb2e7272d1528039832bb9c6e93d60533';
let accountAddress = '2456F6369a9FCB3FE80a89Cd1Dd74108D86FA875';

let proofGenerator = new platform.services.ProofGenerator(stateRoot, chainDataPath);

proofGenerator.buildAccountProof(accountAddress).then(proof => {
//on success proof data is available in proof.toHash().data
});
```
2. Storage proof generation for non mapping type variable
```
const platform = require('@openstfoundation/openst-platform');
chainDataPath = '/path/to/geth/chain_data';

stateRoot = '0xbb08072c81423885fd2ce6dd49468485d7ca9d7aeeefe02f565aadd32f557c2c';
let index = '0';
proofGenerator = new platform.services.ProofGenerator(stateRoot, chainDataPath);
let contractAddress = '9a260b9d36Ec17a90E46bEd85642aD4c5E999243';

let buildStorageProof = proofGenerator.buildStorageProof(contractAddress, index);
buildStorageProof.then((proof) => {
//on success proof data is available in proof.toHash().data
});
```
3. Storage proof generation for mapping type variable
```
const platform = require('@openstfoundation/openst-platform');
chainDataPath = '/path/to/geth/chain_data';
stateRoot = '0xbb08072c81423885fd2ce6dd49468485d7ca9d7aeeefe02f565aadd32f557c2c';
let index = '1';
let key = 'f774e312f848cbc30567a6aeafef6c605f3f4787a6c0581fbbef2992ecfa77ab';
proofGenerator = new platform.services.ProofGenerator(stateRoot, chainDataPath);
let contractAddress = '9a260b9d36Ec17a90E46bEd85642aD4c5E999243';
let buildStorageProof = proofGenerator.buildStorageProof(contractAddress, index, [key1, key2, key3]);
buildStorageProof.then((proof) => {
//on success proof data is available for key 1 in proof[key1].toHash().data
});
```
* Sync service
```
Expand Down
7 changes: 6 additions & 1 deletion config/core_constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,12 @@ CoreConstants.prototype = {
*/
STANDALONE_MODE: process.env.OST_STANDALONE_MODE || 0,

AUTO_SCALE_DYNAMO: process.env.AUTO_SCALE_DYNAMO
AUTO_SCALE_DYNAMO: process.env.AUTO_SCALE_DYNAMO,

/**
* PROOF BATCH SIZE
*/
PROOF_BATCH_SIZE: 10
};

module.exports = new CoreConstants();
47 changes: 47 additions & 0 deletions config/error/general.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,52 @@
"code": "UNPROCESSABLE_ENTITY",
"message": "No new blocks on chain."
},

"exception": {
"http_code": "500",
"code": "INTERNAL_SERVER_ERROR",
"message": "Something went wrong exception."
},
"db_path_undefined": {
"http_code": "422",
"code": "REQUIRED_ARGUMENT_MISSING",
"message": "Required argument db path is missing"
},
"state_root_undefined": {
"http_code": "422",
"code": "REQUIRED_ARGUMENT_MISSING",
"message": "Required argument state root is missing"
},
"account_address_undefined": {
"http_code": "422",
"code": "REQUIRED_ARGUMENT_MISSING",
"message": "Required argument account address is missing"
},
"account_node_not_found": {
"http_code": "422",
"code": "ACCOUNT_NOT_FOUND",
"message": "Account not found"
},
"storage_node_not_found": {
"http_code": "422",
"code": "STORAGE_NOT_FOUND",
"message": "Storage node not found"
},
"storage_index_undefined": {
"http_code": "422",
"code": "REQUIRED_ARGUMENT_MISSING",
"message": "Required argument storage index is missing"
},
"tree_not_initialized": {
"http_code": "422",
"code": "TRIE_UNINITIALIZED",
"message": "Trie not initialized"
},
"proof_batch_size_exceeds": {
"http_code": "422",
"code": "BATCH_SIZE_EXCEEDS",
"message": "Tree batch size exceeds"
},
"sync_source_undefined": {
"http_code": "422",
"code": "REQUIRED_ARGUMENT_MISSING",
Expand All @@ -204,5 +250,6 @@
"http_code": "422",
"code": "FAILED_DURING_RSYNC",
"message": "Rsync failed"

}
}
38 changes: 38 additions & 0 deletions lib/db/leveldb.js
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();
73 changes: 73 additions & 0 deletions lib/proof/account_proof.js
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;

64 changes: 64 additions & 0 deletions lib/proof/helper.js
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();
Loading

0 comments on commit 013b4bc

Please sign in to comment.