Last active
October 11, 2018 22:37
-
-
Save daragao/ff847f08db214d881db3bf64eb337700 to your computer and use it in GitHub Desktop.
Simple example on how to get accounts from state trie
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
const level = require('level') | |
const rlp = require('rlp') | |
const chaindatadirectory = './data_node_0/geth/chaindata' | |
const TX_ROOT_HASH = '146d436eb3af4eeaf1f421d86a8994ef9f6e3670393837e9141f7f44b00e01cf' | |
const STATE_ROOT_HASH = '0c773fdbbe314cbeb0908d1b4949b39d1edca0653efee339882679538fce3318' | |
level(chaindatadirectory, { keyEncoding: 'utf8', valueEncoding: 'binary'}, async (err, db) => { | |
if(err) { | |
console.log('ERROR: ',err) | |
return | |
} | |
const printData = async (triePath,root) => { | |
if(!root || root.length == 0) return | |
let data | |
try { | |
data = await db.get(root) | |
} catch(err) { | |
console.log(`ERROR getting data [${root.toString('hex')}]\n `)//,err) | |
return | |
} | |
const dataBin = Buffer.from(data) | |
const decodedRLP = rlp.decode(dataBin) | |
//console.log("===============================================================================================================") | |
//console.log(root) | |
//console.log(decodedRLP) | |
let nodeHash = [] | |
let value | |
if(decodedRLP.length === 17) { | |
nodeHash = decodedRLP.slice(0,16) | |
value = decodedRLP[16].length ? decodedRLP[16] : null | |
} | |
if(decodedRLP.length === 2) { | |
const firstNibble = decodedRLP[0][0] & 0xf0 | |
const secondNibble = decodedRLP[0][0] & 0x0f | |
const isLeaf = (firstNibble === 0x20 || firstNibble === 0x30) | |
const isOdd = (firstNibble === 0x10 || firstNibble === 0x30) | |
let newAddrHash = decodedRLP[0].toString('hex') | |
if(isOdd) newAddrHash = '0' + newAddrHash | |
triePath = triePath.concat(newAddrHash.slice(2)) | |
if(isLeaf) { | |
value = decodedRLP[1] | |
} else { | |
// TODO didn't test extentions, my db is not large enough | |
nodeHash = decodedRLP[1] | |
} | |
} | |
if(value) { | |
const decodedValue = rlp.decode(value) | |
const account = createAccount(triePath, decodedValue) | |
try { | |
const code = await db.get(decodedValue[3]) | |
account.code = code.toString('hex') | |
} catch(err) { | |
console.log(`ERROR getting code [${account.codeHash}]\n `)//,err) | |
} | |
//accounts.push(account) | |
return account | |
} else { | |
const accounts = await Promise.all(nodeHash.map(async (h,idx) => { | |
let newAddr = !(decodedRLP.length === 2) ? triePath + idx.toString(16) : triePath | |
return h.length ? await printData(newAddr,h) : null | |
})) | |
return [].concat(...accounts).filter(acc => acc) | |
} | |
} | |
const createAccount = (triePath, rlpDecodedValue) => ({ | |
addressHash: triePath, | |
nonce: rlpDecodedValue[0].toString('hex'), | |
balance: rlpDecodedValue[1].toString('hex'), | |
storageRoot: rlpDecodedValue[2].toString('hex'), | |
codeHash: rlpDecodedValue[3].toString('hex'), | |
}) | |
const root = new Buffer(STATE_ROOT_HASH, 'hex') | |
const accounts = await printData('',root) | |
console.log(">>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<") | |
console.log(">>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<") | |
console.log("All Accounts: ", JSON.stringify(accounts,4,4)) | |
// Example of how to get a block | |
// const blockHash = Buffer.from('LastHeader') | |
//const blockHash = Buffer.from('b815b580e518203367c6dda3302faf37fdcbcdcfdef6045a57715987c5d1183d6','hex') | |
// const blockHash = Buffer.concat([Buffer.from('b'), Buffer.from('000000000000010d','hex'), Buffer.from('815b580e518203367c6dda3302faf37fdcbcdcfdef6045a57715987c5d1183d6','hex')]) | |
//const blockHash = Buffer.concat([Buffer.from('H'), Buffer.from('815b580e518203367c6dda3302faf37fdcbcdcfdef6045a57715987c5d1183d6','hex')]) | |
const createTransaction = (rlpDecodedValue) => { | |
return { | |
nonce: rlpDecodedValue[0], | |
price: rlpDecodedValue[1], | |
gasLimit: rlpDecodedValue[2], | |
recipient: rlpDecodedValue[3], | |
amount: rlpDecodedValue[4], | |
payload: rlpDecodedValue[5], | |
v: rlpDecodedValue[6], | |
r: rlpDecodedValue[7], | |
s: rlpDecodedValue[8], | |
} | |
} | |
const getBlock = async (number,hash) => { | |
const blockHash = Buffer.concat([ | |
Buffer.from('b'), | |
Buffer.from(number.toString(16).padStart(16,0),'hex'), | |
Buffer.from(hash,'hex') | |
]) | |
try { | |
const data = await db.get(blockHash) | |
const dataBin = Buffer.from(data) | |
const decodedRLP = rlp.decode(dataBin) | |
return { transactions: decodedRLP[0].map(d => createTransaction(d)), ommers: decodedRLP[1]} | |
} catch(err) { | |
console.log(`ERROR getting data [${blockHash.toString('hex')}]`,err) | |
return | |
} | |
} | |
console.log(await getBlock(154,'b70e0b9752c4127263ca831f7a6908f8f4ac5e9f6b5d7ee7d18e1a01e60d0ebe')) | |
}) | |
// really good post on db details | |
// https://ethereum.stackexchange.com/a/57888/2688 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment