From 1b1038fe0625a87c35addda9788d326adf420933 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 14 Jan 2016 13:54:29 +0100 Subject: [PATCH] Fix storage stuff and introduce per-item dirty-tracking. --- src/account.rs | 50 +++++++++++++++++++++++++++++++------------------ src/env_info.rs | 13 +++++++------ 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/account.rs b/src/account.rs index d62b07d54..3806aae98 100644 --- a/src/account.rs +++ b/src/account.rs @@ -386,6 +386,12 @@ fn account_diff_storage() { })); } +#[derive(PartialEq,Eq,Clone,Copy)] +pub enum Filth { + Clean, + Dirty, +} + /// Single account in the system. #[derive(Clone)] pub struct Account { @@ -395,8 +401,8 @@ pub struct Account { nonce: U256, // Trie-backed storage. storage_root: H256, - // Overlay on trie-backed storage. - storage_overlay: RefCell>, + // Overlay on trie-backed storage - tuple is (, ). + storage_overlay: RefCell>, // Code hash of the account. If None, means that it's a contract whose code has not yet been set. code_hash: Option, // Code cache of the account. @@ -410,7 +416,7 @@ impl PodAccount { PodAccount { balance: acc.balance.clone(), nonce: acc.nonce.clone(), - storage: acc.storage_overlay.borrow().iter().fold(BTreeMap::new(), |mut m, (k, v)| {m.insert(k.clone(), v.clone()); m}), + storage: acc.storage_overlay.borrow().iter().fold(BTreeMap::new(), |mut m, (k, &(_, ref v))| {m.insert(k.clone(), v.clone()); m}), code: acc.code_cache.clone() } } @@ -433,7 +439,7 @@ impl Account { balance: balance, nonce: nonce, storage_root: SHA3_NULL_RLP, - storage_overlay: RefCell::new(storage), + storage_overlay: RefCell::new(storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()), code_hash: Some(code.sha3()), code_cache: code } @@ -445,7 +451,7 @@ impl Account { balance: pod.balance, nonce: pod.nonce, storage_root: SHA3_NULL_RLP, - storage_overlay: RefCell::new(pod.storage.into_iter().fold(HashMap::new(), |mut m, (k, v)| {m.insert(k, v); m})), + storage_overlay: RefCell::new(pod.storage.into_iter().map(|(k, v)| (k, (Filth::Dirty, v))).collect()), code_hash: Some(pod.code.sha3()), code_cache: pod.code } @@ -505,14 +511,14 @@ impl Account { /// Set (and cache) the contents of the trie's storage at `key` to `value`. pub fn set_storage(&mut self, key: H256, value: H256) { - self.storage_overlay.borrow_mut().insert(key, value); + self.storage_overlay.borrow_mut().insert(key, (Filth::Dirty, value)); } /// Get (and cache) the contents of the trie's storage at `key`. pub fn storage_at(&self, db: &HashDB, key: &H256) -> H256 { self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{ - H256::from_slice(SecTrieDB::new(db, &self.storage_root).get(key.bytes()).unwrap_or(&[0u8;32][..])) - }).clone() + (Filth::Clean, H256::from(SecTrieDB::new(db, &self.storage_root).get(key.bytes()).map(|v| -> U256 {decode(v)}).unwrap_or(U256::zero()))) + }).1.clone() } /// return the balance associated with this account. @@ -573,12 +579,18 @@ impl Account { /// return the storage root associated with this account. pub fn base_root(&self) -> &H256 { &self.storage_root } + + /// Determine whether there are any un-`commit()`-ed storage-setting operations. + pub fn storage_is_clean(&self) -> bool { self.storage_overlay.borrow().iter().find(|&(_, &(f, _))| f == Filth::Dirty).is_none() } /// return the storage root associated with this account or None if it has been altered via the overlay. - pub fn storage_root(&self) -> Option<&H256> { if self.storage_overlay.borrow().is_empty() {Some(&self.storage_root)} else {None} } + pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} } - /// rturn the storage overlay. - pub fn storage_overlay(&self) -> Ref> { self.storage_overlay.borrow() } + /// return the storage root associated with this account or None if it has been altered via the overlay. + pub fn recent_storage_root(&self) -> &H256 { &self.storage_root } + + /// return the storage overlay. + pub fn storage_overlay(&self) -> Ref> { self.storage_overlay.borrow() } /// Increment the nonce of the account by one. pub fn inc_nonce(&mut self) { self.nonce = self.nonce + U256::from(1u8); } @@ -592,12 +604,14 @@ impl Account { /// Commit the `storage_overlay` to the backing DB and update `storage_root`. pub fn commit_storage(&mut self, db: &mut HashDB) { let mut t = SecTrieDBMut::new(db, &mut self.storage_root); - for (k, v) in self.storage_overlay.borrow().iter() { - // cast key and value to trait type, - // so we can call overloaded `to_bytes` method - t.insert(k, &encode(&U256::from(v.as_slice()))); + for (k, &mut (ref mut f, ref mut v)) in self.storage_overlay.borrow_mut().iter_mut() { + if f == &Filth::Dirty { + // cast key and value to trait type, + // so we can call overloaded `to_bytes` method + t.insert(k, &encode(&U256::from(v.as_slice()))); + *f = Filth::Clean; + } } -// self.storage_overlay.borrow_mut().clear(); } /// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this. @@ -654,7 +668,7 @@ fn storage_at() { }; let a = Account::from_rlp(&rlp); - assert_eq!(a.storage_root().unwrap().hex(), "3541f181d6dad5c504371884684d08c29a8bad04926f8ceddf5e279dbc3cc769"); + assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2"); assert_eq!(a.storage_at(&mut db, &H256::from(&U256::from(0x00u64))), H256::from(&U256::from(0x1234u64))); assert_eq!(a.storage_at(&mut db, &H256::from(&U256::from(0x01u64))), H256::new()); } @@ -684,7 +698,7 @@ fn commit_storage() { a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64))); assert_eq!(a.storage_root(), None); a.commit_storage(&mut db); - assert_eq!(a.storage_root().unwrap().hex(), "3541f181d6dad5c504371884684d08c29a8bad04926f8ceddf5e279dbc3cc769"); + assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2"); } #[test] diff --git a/src/env_info.rs b/src/env_info.rs index 361e55f60..88367fca9 100644 --- a/src/env_info.rs +++ b/src/env_info.rs @@ -30,22 +30,23 @@ impl EnvInfo { number: 0, author: Address::new(), timestamp: 0, - difficulty: U256::zero(), - gas_limit: U256::zero(), + difficulty: x!(0), + gas_limit: x!(0), last_hashes: vec![], - gas_used: U256::zero() + gas_used: x!(0), } } pub fn from_json(json: &Json) -> EnvInfo { + let current_number = u64_from_json(&json["currentNumber"]); EnvInfo { - number: u64_from_json(&json["currentNumber"]), + number: current_number, author: address_from_json(&json["currentCoinbase"]), difficulty: u256_from_json(&json["currentDifficulty"]), gas_limit: u256_from_json(&json["currentGasLimit"]), timestamp: u64_from_json(&json["currentTimestamp"]), - last_hashes: vec![h256_from_json(&json["previousHash"])], - gas_used: U256::zero(), + last_hashes: (1..257).map(|i| format!("{}", current_number - i).as_bytes().sha3()).collect(), + gas_used: x!(0), } } }