Skip to content

Instantly share code, notes, and snippets.

@daragao
Last active October 11, 2018 22:37
Show Gist options
  • Save daragao/ff847f08db214d881db3bf64eb337700 to your computer and use it in GitHub Desktop.
Save daragao/ff847f08db214d881db3bf64eb337700 to your computer and use it in GitHub Desktop.
Simple example on how to get accounts from state trie
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