ethereumjs / merkle-patricia-tree

Project is in active development and has been moved to the EthereumJS VM monorepo.

Home Page:https://github.com/ethereumjs/ethereumjs-monorepo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Trying to access nonce, balance, storageRoot and codeHash via the state trie

tpmccallum opened this issue · comments

Hi,
Firstly, thanks for this code, much appreciated.
I am wanting to use this merkle-patricia-tree library to fetch nonce, balance, storageRoot and codeHash from my Ethereum (private network) state trie.

I am accessing the keys of the state trie here

I then am using the following code to access (and print the values of each of the 3 accounts which I created on my private Ethereum network).

var Trie = require('merkle-patricia-tree/secure');
var levelup = require('levelup');
var leveldown = require('leveldown');
var RLP = require('rlp');
var assert = require('assert');

//Connecting to the leveldb database
var db = levelup(leveldown('/home/timothymccallum/gethDataDir/geth/chaindata'));

//Obtaining the state root (of the latest block) using this command web3.eth.getBlock(web3.eth.defaultBlock).stateRoot
var root = '0x8c77785e3e9171715dd34117b047dffe44575c32ede59bde39fbf5dc074f2976';

//Creating a trie object of the merkle-patricia-tree library
var trie = new Trie(db, root);

//Creating a nodejs stream object so that we can access the data
var stream = trie.createReadStream()

//Turning on the stream (because the node js stream is set to pause by default)
stream.on('data', function (data){
  //Capture the RLP serialised data structure
  var arrayOfStateValues = RLP.decode(data.value);
  //Loop through the data of the 3 accounts in the array to obtain the nonce, balance, storageRoot and codeHash for each one 
  for (i = 0; i < arrayOfStateValues.length; i++){ 
    console.log(RLP.decode(arrayOfStateValues[i], [skipRemainderCheck=false])); 
    console.log("");
  }
  
});

The above code gives me the following results

<Buffer >

{ data: <Buffer a2 bc 2e c5 00 00>, remainder: <Buffer > }

{ data: <Buffer 56>,
  remainder: <Buffer e8 1f 17 1b cc 55 a6 ff 83 45 e6 92 c0 f8 6e 5b 48 e0 1b 99 6c ad c0 01 62 2f b5 e3 63 b4 21> }

{ data: [ [ <Buffer 46>, <Buffer 01>, <Buffer f7> ] ],
  remainder: <Buffer 23 3c 92 7e 7d b2 dc c7 03 c0 e5 00 b6 53 ca 82 27 3b 7b fa d8 04 5d 85 a4 70> }

<Buffer >

{ data: <Buffer 04>, remainder: <Buffer 93 e0> }

{ data: <Buffer 56>,
  remainder: <Buffer e8 1f 17 1b cc 55 a6 ff 83 45 e6 92 c0 f8 6e 5b 48 e0 1b 99 6c ad c0 01 62 2f b5 e3 63 b4 21> }

{ data: [ [ <Buffer 46>, <Buffer 01>, <Buffer f7> ] ],
  remainder: <Buffer 23 3c 92 7e 7d b2 dc c7 03 c0 e5 00 b6 53 ca 82 27 3b 7b fa d8 04 5d 85 a4 70> }

{ data: <Buffer 01>, remainder: <Buffer > }

{ data: <Buffer 06>,
  remainder: <Buffer 3b 40 6f f8 03 2d 1a 80> }

{ data: <Buffer 56>,
  remainder: <Buffer e8 1f 17 1b cc 55 a6 ff 83 45 e6 92 c0 f8 6e 5b 48 e0 1b 99 6c ad c0 01 62 2f b5 e3 63 b4 21> }

{ data: [ [ <Buffer 46>, <Buffer 01>, <Buffer f7> ] ],
  remainder: <Buffer 23 3c 92 7e 7d b2 dc c7 03 c0 e5 00 b6 53 ca 82 27 3b 7b fa d8 04 5d 85 a4 70> }

Can you please advise on how I would access these values using your code.

Many thanks
Tim

If you are able to provide me with information about using your code to access values in the Ethereum tries I could contribute my examples / diagrams/ explanations etc to your documentation and/or wiki.
Many thanks
Tim

Hi @tpmccallum,

What you are seeing is a dump of objects of the format KECCAK256(account address): RLP(account data).

Checkout this code that de-serializes the RLP account data by creating an instance of ethereumjs-account:

https://github.com/ethereumjs/ethereumjs-vm/blob/master/lib/cache.js#L44

From there, you can access the individual fields for the account and also have access to the account storage trie via the storageRoot field

Hi @jwasinger
Thank's so much. I created an instance of the ethereumjs-account and obtained the account balance using the following code (harnessing your ethereumjs-util and ethereumjs-account).

//Mozilla Public License 2.0 
//As per https://github.com/ethereumjs/ethereumjs-vm/blob/master/LICENSE
//Requires the following packages to run as nodejs file https://gist.github.com/tpmccallum/0e58fc4ba9061a2e634b7a877e60143a

//Getting the requirements
var Trie = require('merkle-patricia-tree/secure');
var levelup = require('levelup');
var leveldown = require('leveldown');
var utils = require('ethereumjs-util');
var BN = utils.BN;
var Account = require('ethereumjs-account');

//Connecting to the leveldb database
var db = levelup(leveldown('/home/timothymccallum/gethDataDir/geth/chaindata'));

//Adding the "stateRoot" value from the block so that we can inspect the state root at that block height.
var root = '0x9369577baeb7c4e971ebe76f5d5daddba44c2aa42193248245cf686d20a73028';

//Creating a trie object of the merkle-patricia-tree library
var trie = new Trie(db, root);

var address = '0xccc6b46fa5606826ce8c18fece6f519064e6130b';
trie.get(address, function (err, raw) {
    if (err) return cb(err)
    //Using ethereumjs-account to create an instance of an account
    var account = new Account(raw)
    console.log('Account Address: ' + address);
    //Using ethereumjs-util to decode and present the account balance 
    console.log('Balance: ' + (new BN(account.balance)).toString());
})

@tpmccallum don't you need to keccak the address first before getting the entry from the trie?

trie.get(keccak256(address), function (err, raw) {

Hi @medvedev1088
I was able to obtain the entry from the trie by passing in the address in its standard form (not keccak).
Not sure if it makes a difference but I am using the "secure" requirement as the Trie var

var Trie = require('merkle-patricia-tree/secure');

which is found at

https://github.com/ethereumjs/merkle-patricia-tree/blob/master/secure-interface.js

as apposed to just using the standard

var Trie = require('merkle-patricia-tree');

Hi all,
I attempting to access nonce, balance, storageRoot and codeHash via the state trie given @tpmccallum example in the 1st comment without success. I'm using a data directory within my geth node, an existing stateRoot in the Ethereum Blockchain

db = levelup(leveldown('/root/.ethereum/geth/chaindata'));
var root = '0xc23aebee71a1e6f988773af2eba7b55a57f659b565c392edaf99b5f765d30574';

It produces a black output despite me accessing a stateRoot within the correct block height indicating that the stateRoot exist.

Help would be greatly appreciated.

Thank You,
Joshua

var Trie = require('merkle-patricia-tree/secure');
var levelup = require('levelup');
var leveldown = require('leveldown');
var RLP = require('rlp');
var assert = require('assert');

//Connecting to the leveldb database
// var db = levelup(leveldown('/home/timothymccallum/gethDataDir/geth/chaindata'));
db = levelup(leveldown('/root/.ethereum/geth/chaindata'));

//Obtaining the state root (of the latest block) using this command web3.eth.getBlock(web3.eth.defaultBlock).stateRoot
// var root = '0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544';
var root = '0xc23aebee71a1e6f988773af2eba7b55a57f659b565c392edaf99b5f765d30574';

//Creating a trie object of the merkle-patricia-tree library
var trie = new Trie(db, root);

//Creating a nodejs stream object so that we can access the data
var stream = trie.createReadStream()

//Turning on the stream (because the node js stream is set to pause by default)
stream.on('data', function (data){
  //Capture the RLP serialised data structure
  var arrayOfStateValues = RLP.decode(data.value);
  //Loop through the data of the 3 accounts in the array to obtain the nonce, balance, storageRoot and codeHash for each one 
  for (i = 0; i < arrayOfStateValues.length; i++){ 
    console.log(RLP.decode(arrayOfStateValues[i], [skipRemainderCheck=false])); 
    console.log("");
  }
  
});

Hi @JEJodesty
It has been a few weeks since I have played with this.
Please look at the following and compare and contrast the differences between what you are trying and what I have provided in my installation and code examples.
Installing npm, node, level and ethereumjs
https://gist.githubusercontent.com/tpmccallum/0e58fc4ba9061a2e634b7a877e60143a/raw/ec53049533d08f8db226f0fbe3510191bb94de55/epn_18.md
Print a list of the Etherem account keys
https://gist.githubusercontent.com/tpmccallum/2dfa62c820d87e0105ee14bfe77b59ce/raw/bb14bea5a22f8d7d39a12bc3cc3e5f2a850a8022/epn_19.md
Example of getting the account balance
https://gist.githubusercontent.com/tpmccallum/bd9e5538346e1defb1234f37cfd33eda/raw/43456edfcc46f603539de610876c9d843de20990/get_account_balance.md

Hope this helps.

I wrote up a whole article on this
https://medium.com/cybermiles/diving-into-ethereums-world-state-c893102030ed
Feel free to check it out, the code comes in at the end (after we talk about Ethereum state etc etc.)

Kind regards
Tim

Hi @tpmccallum ,
Solved it! Issue: Corrupted leveldb database.

Thanks for your help!
-Josh

Hi @tpmccallum,
I am trying your code from https://gist.githubusercontent.com/tpmccallum/2dfa62c820d87e0105ee14bfe77b59ce/raw/bb14bea5a22f8d7d39a12bc3cc3e5f2a850a8022/epn_19.md

I have two questions if you could help:-
(i) i get the output only for Block 0 stateRoot hash as input. For any other blocks, i get the blank or null output. Why is it so?
(ii)Sometimes i get the error related to unhandled exception:Corrupted database,files missing
OpenError: Corruption: 1 missing files; e.g.: /root/eth_testnet/geth/chaindata//000003.ldb