This repository has been archived by the owner on Nov 6, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from gavofyork/state
Add Account and State classes.
- Loading branch information
Showing
3 changed files
with
179 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
use std::collections::HashMap; | ||
use util::hash::*; | ||
use util::hashdb::*; | ||
use util::bytes::*; | ||
use util::trie::*; | ||
use util::rlp::*; | ||
use util::uint::*; | ||
|
||
enum HashOrData { | ||
Hash(H256), | ||
Data(Bytes), | ||
Both(H256, Bytes), | ||
} | ||
|
||
pub struct Account { | ||
balance: U256, | ||
nonce: U256, | ||
// Trie-backed storage. | ||
storage_root: H256, | ||
// Overlay on trie-backed storage. | ||
storage_overlay: HashMap<H256, H256>, | ||
code: HashOrData, | ||
} | ||
|
||
impl Account { | ||
pub fn new_with_balance(balance: U256) -> Account { | ||
Account { | ||
balance: balance, | ||
nonce: U256::from(0u8), | ||
code: HashOrData::Data(vec![]), | ||
storage_root: SHA3_NULL_RLP, | ||
storage_overlay: HashMap::new(), | ||
} | ||
} | ||
|
||
pub fn from_rlp(_rlp: &[u8]) -> Account { | ||
//TODO | ||
Account { | ||
balance: U256::from(0u8), | ||
nonce: U256::from(0u8), | ||
code: HashOrData::Hash(SHA3_NULL_RLP), | ||
storage_root: SHA3_NULL_RLP, | ||
storage_overlay: HashMap::new(), | ||
} | ||
} | ||
|
||
pub fn balance(&self) -> &U256 { &self.balance } | ||
pub fn nonce(&self) -> &U256 { &self.nonce } | ||
pub fn code_hash(&self) -> Option<&H256> { | ||
match self.code { | ||
HashOrData::Hash(ref h) | HashOrData::Both(ref h, _) => Some(h), | ||
_ => None, | ||
} | ||
} | ||
pub fn storage_root(&self) -> Option<&H256> { if self.storage_overlay.is_empty() {Some(&self.storage_root)} else {None} } | ||
|
||
/// Commit the `storage_overlay` to the backing DB and update `storage_root`. | ||
pub fn commit_storage(&mut self, db: &mut HashDB) { | ||
let mut t = TrieDB::new(db, &mut self.storage_root); | ||
for (k, v) in self.storage_overlay.iter() { | ||
// cast key and value to trait type, | ||
// so we can call overloaded `to_bytes` method | ||
t.insert(k, v); | ||
} | ||
self.storage_overlay.clear(); | ||
} | ||
|
||
/// Commit any unsaved code and ensure code is not `HashOrData::Data`. | ||
pub fn commit_code(&mut self, db: &mut HashDB) { | ||
if let Some(new_code) = match self.code { | ||
HashOrData::Data(ref d) => { Some(HashOrData::Both(db.insert(d), d.clone())) }, | ||
_ => None, | ||
}{ | ||
self.code = new_code; | ||
} | ||
|
||
// that nasty bit of code should really be: | ||
/*if let HashOrData::Data(ref d) = self.code { | ||
let h = db.insert(d); | ||
self.code = HashOrData::Both(h, d.clone()); | ||
}*/ | ||
// a rewrite it closer to this would be good... | ||
|
||
} | ||
} |
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,93 @@ | ||
use std::collections::HashMap; | ||
use util::hash::*; | ||
use util::hashdb::*; | ||
use util::overlaydb::*; | ||
use util::trie::*; | ||
use util::rlp::*; | ||
use util::uint::*; | ||
use account::Account; | ||
|
||
pub struct State { | ||
db: OverlayDB, | ||
root: H256, | ||
_cache: HashMap<Address, Option<Account>>, | ||
|
||
_account_start_nonce: U256, | ||
} | ||
|
||
impl State { | ||
/// Creates new state with empty state root | ||
pub fn new(mut db: OverlayDB, account_start_nonce: U256) -> State { | ||
let mut root = H256::new(); | ||
{ | ||
// init trie and reset root too null | ||
let _ = TrieDB::new(&mut db, &mut root); | ||
} | ||
|
||
State { | ||
db: db, | ||
root: root, | ||
_cache: HashMap::new(), | ||
_account_start_nonce: account_start_nonce, | ||
} | ||
} | ||
|
||
/// Creates new state with existing state root | ||
pub fn new_existing(mut db: OverlayDB, mut root: H256, account_start_nonce: U256) -> State { | ||
{ | ||
// trie should panic! if root does not exist | ||
let _ = TrieDB::new_existing(&mut db, &mut root); | ||
} | ||
|
||
State { | ||
db: db, | ||
root: root, | ||
_cache: HashMap::new(), | ||
_account_start_nonce: account_start_nonce, | ||
} | ||
} | ||
|
||
/// Create temporary state object | ||
pub fn new_temp() -> State { | ||
Self::new(OverlayDB::new_temp(), U256::from(0u8)) | ||
} | ||
|
||
/// Return reference to root | ||
pub fn root(&self) -> &H256 { | ||
&self.root | ||
} | ||
|
||
/// Commit everything to the disk | ||
pub fn commit_db(&mut self) { | ||
self.db.commit().expect("Number of kills exceeded number of inserts!"); | ||
} | ||
|
||
/// Commit accounts to TrieDB. This is simplified version of | ||
/// cpp-ethereum's dev::eth::commit. | ||
/// accounts mutable because we may need to commit the code or storage and record that. | ||
pub fn commit(db: &mut HashDB, mut root: H256, accounts: &mut HashMap<Address, Account>) -> H256 { | ||
// first, commit the sub trees. | ||
for (_, ref mut account) in accounts.iter_mut() { | ||
account.commit_storage(db); | ||
account.commit_code(db); | ||
} | ||
|
||
{ | ||
let mut trie = TrieDB::new_existing(db, &mut root); | ||
for (address, account) in accounts.iter() { | ||
let mut stream = RlpStream::new_list(4); | ||
stream.append(account.nonce()); | ||
stream.append(account.balance()); | ||
stream.append(account.storage_root().unwrap()); | ||
stream.append(account.code_hash().unwrap()); | ||
trie.insert(address, &stream.out()); | ||
} | ||
} | ||
root | ||
} | ||
|
||
pub fn insert_accounts(&mut self, accounts: &mut HashMap<Address, Account>) { | ||
let r = self.root.clone(); // would prefer not to do this, really. | ||
self.root = Self::commit(&mut self.db, r, accounts); | ||
} | ||
} |