-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
**Motivation** Obtain world state from account info stored in db **Description** * Implement storage root computation * Implement word state <!-- Link to issues: Resolves #111, Resolves #222 --> Closes #44
- Loading branch information
Showing
8 changed files
with
275 additions
and
12 deletions.
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
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,160 @@ | ||
use std::collections::HashMap; | ||
|
||
use anyhow::anyhow; | ||
use ethereum_rust_core::{ | ||
rlp::{decode::RLPDecode, encode::RLPEncode}, | ||
types::{compute_storage_root, AccountInfo, AccountState}, | ||
Address, H256, | ||
}; | ||
use libmdbx::orm::Database; | ||
use patricia_merkle_tree::PatriciaMerkleTree; | ||
use sha3::{digest::core_api::CoreWrapper, Keccak256Core}; | ||
|
||
use crate::{AccountInfos, AccountStorages}; | ||
|
||
/// A Merkle Tree containing a mapping from account addresses to account states | ||
#[allow(unused)] | ||
#[derive(Default)] | ||
pub struct WorldState(pub PatriciaMerkleTree<Vec<u8>, Vec<u8>, CoreWrapper<Keccak256Core>>); | ||
|
||
#[allow(unused)] | ||
impl WorldState { | ||
pub fn get_account_state(&self, addr: &Address) -> Option<AccountState> { | ||
self.0 | ||
.get(&addr.encode_to_vec()) | ||
.and_then(|encoded| AccountState::decode(encoded).ok()) | ||
} | ||
|
||
pub fn build_from_db(db: &Database) -> Result<WorldState, anyhow::Error> { | ||
let db = db.begin_read()?; | ||
// Fetch & Decode AccountInfos | ||
let mut account_infos = HashMap::<_, _>::new(); | ||
let mut account_infos_db = db.cursor::<AccountInfos>()?; | ||
while let Some((rlp_address, rlp_info)) = account_infos_db.next()? { | ||
account_infos.insert( | ||
Address::decode(&rlp_address.0)?, | ||
AccountInfo::decode(&rlp_info.0)?, | ||
); | ||
} | ||
// Fetch & Decode Account Storages | ||
let mut account_storages = HashMap::<Address, HashMap<H256, H256>>::new(); | ||
let mut account_storages_db = db.cursor::<AccountStorages>()?; | ||
while let Some((rlp_address, (storage_key_bytes, storage_value_bytes))) = | ||
account_storages_db.next()? | ||
{ | ||
let entry = account_storages | ||
.entry(Address::decode(&rlp_address.0)?) | ||
.or_default(); | ||
entry.insert( | ||
H256::from(&storage_key_bytes.0), | ||
H256::from(&storage_value_bytes.0), | ||
); | ||
} | ||
// Fill World State merkle tree | ||
let mut world_state = WorldState::default(); | ||
for (addr, account_info) in account_infos { | ||
let storage = account_storages | ||
.get(&addr) | ||
.ok_or(anyhow!("No storage found in db for account address {addr}"))?; | ||
let account_state = AccountState { | ||
nonce: account_info.nonce, | ||
balance: account_info.balance, | ||
storage_root: compute_storage_root(storage), | ||
code_hash: account_info.code_hash, | ||
}; | ||
|
||
world_state | ||
.0 | ||
.insert(addr.encode_to_vec(), account_state.encode_to_vec()); | ||
} | ||
|
||
Ok(world_state) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use ethereum_rust_core::rlp::encode::RLPEncode; | ||
use std::str::FromStr; | ||
|
||
use crate::{ | ||
account::{AccountInfoRLP, AccountStorageKeyRLP, AccountStorageValueRLP, AddressRLP}, | ||
init_db, | ||
}; | ||
|
||
use super::*; | ||
|
||
#[test] | ||
fn test_build_world_state() { | ||
let db = init_db(None::<String>); | ||
let write = db.begin_readwrite().unwrap(); | ||
let account_info = AccountInfo { | ||
code_hash: H256::from_slice( | ||
&hex::decode("3d9209c0aa535c1b05fb6000abf2e8239ac31d12ff08b2c6db0c6ef68cf7795f") | ||
.unwrap(), | ||
), | ||
balance: 12.into(), | ||
nonce: 0, | ||
}; | ||
let address = | ||
Address::from_slice(&hex::decode("a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap()); | ||
|
||
let storage = [ | ||
( | ||
H256::from_str( | ||
"0x1000000000000000000000000000000000000000000000000000000000000022", | ||
) | ||
.unwrap(), | ||
H256::from_str( | ||
"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", | ||
) | ||
.unwrap(), | ||
), | ||
( | ||
H256::from_str( | ||
"0x1000000000000000000000000000000000000000000000000000000000000038", | ||
) | ||
.unwrap(), | ||
H256::from_str( | ||
"0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", | ||
) | ||
.unwrap(), | ||
), | ||
]; | ||
write | ||
.upsert::<AccountInfos>( | ||
AddressRLP(address.encode_to_vec()), | ||
AccountInfoRLP(account_info.encode_to_vec()), | ||
) | ||
.unwrap(); | ||
write | ||
.upsert::<AccountStorages>( | ||
AddressRLP(address.encode_to_vec()), | ||
( | ||
AccountStorageKeyRLP(storage[0].0 .0), | ||
AccountStorageValueRLP(storage[0].1 .0), | ||
), | ||
) | ||
.unwrap(); | ||
write | ||
.upsert::<AccountStorages>( | ||
AddressRLP(address.encode_to_vec()), | ||
( | ||
AccountStorageKeyRLP(storage[1].0 .0), | ||
AccountStorageValueRLP(storage[1].1 .0), | ||
), | ||
) | ||
.unwrap(); | ||
write.commit().unwrap(); | ||
|
||
let world_state = WorldState::build_from_db(&db).unwrap(); | ||
let account_state = world_state.get_account_state(&address).unwrap(); | ||
let expected_account_state = AccountState { | ||
nonce: account_info.nonce, | ||
balance: account_info.balance, | ||
storage_root: compute_storage_root(&HashMap::from(storage)), | ||
code_hash: account_state.code_hash, | ||
}; | ||
assert_eq!(account_state, expected_account_state); | ||
} | ||
} |