Fix storage stuff and introduce per-item dirty-tracking.
This commit is contained in:
parent
5a9ac6a329
commit
1b1038fe06
@ -386,6 +386,12 @@ fn account_diff_storage() {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq,Eq,Clone,Copy)]
|
||||||
|
pub enum Filth {
|
||||||
|
Clean,
|
||||||
|
Dirty,
|
||||||
|
}
|
||||||
|
|
||||||
/// Single account in the system.
|
/// Single account in the system.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
@ -395,8 +401,8 @@ pub struct Account {
|
|||||||
nonce: U256,
|
nonce: U256,
|
||||||
// Trie-backed storage.
|
// Trie-backed storage.
|
||||||
storage_root: H256,
|
storage_root: H256,
|
||||||
// Overlay on trie-backed storage.
|
// Overlay on trie-backed storage - tuple is (<clean>, <value>).
|
||||||
storage_overlay: RefCell<HashMap<H256, H256>>,
|
storage_overlay: RefCell<HashMap<H256, (Filth, H256)>>,
|
||||||
// Code hash of the account. If None, means that it's a contract whose code has not yet been set.
|
// Code hash of the account. If None, means that it's a contract whose code has not yet been set.
|
||||||
code_hash: Option<H256>,
|
code_hash: Option<H256>,
|
||||||
// Code cache of the account.
|
// Code cache of the account.
|
||||||
@ -410,7 +416,7 @@ impl PodAccount {
|
|||||||
PodAccount {
|
PodAccount {
|
||||||
balance: acc.balance.clone(),
|
balance: acc.balance.clone(),
|
||||||
nonce: acc.nonce.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()
|
code: acc.code_cache.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -433,7 +439,7 @@ impl Account {
|
|||||||
balance: balance,
|
balance: balance,
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
storage_root: SHA3_NULL_RLP,
|
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_hash: Some(code.sha3()),
|
||||||
code_cache: code
|
code_cache: code
|
||||||
}
|
}
|
||||||
@ -445,7 +451,7 @@ impl Account {
|
|||||||
balance: pod.balance,
|
balance: pod.balance,
|
||||||
nonce: pod.nonce,
|
nonce: pod.nonce,
|
||||||
storage_root: SHA3_NULL_RLP,
|
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_hash: Some(pod.code.sha3()),
|
||||||
code_cache: pod.code
|
code_cache: pod.code
|
||||||
}
|
}
|
||||||
@ -505,14 +511,14 @@ impl Account {
|
|||||||
|
|
||||||
/// Set (and cache) the contents of the trie's storage at `key` to `value`.
|
/// Set (and cache) the contents of the trie's storage at `key` to `value`.
|
||||||
pub fn set_storage(&mut self, key: H256, value: H256) {
|
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`.
|
/// Get (and cache) the contents of the trie's storage at `key`.
|
||||||
pub fn storage_at(&self, db: &HashDB, key: &H256) -> H256 {
|
pub fn storage_at(&self, db: &HashDB, key: &H256) -> H256 {
|
||||||
self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{
|
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][..]))
|
(Filth::Clean, H256::from(SecTrieDB::new(db, &self.storage_root).get(key.bytes()).map(|v| -> U256 {decode(v)}).unwrap_or(U256::zero())))
|
||||||
}).clone()
|
}).1.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return the balance associated with this account.
|
/// return the balance associated with this account.
|
||||||
@ -574,11 +580,17 @@ impl Account {
|
|||||||
/// return the storage root associated with this account.
|
/// return the storage root associated with this account.
|
||||||
pub fn base_root(&self) -> &H256 { &self.storage_root }
|
pub fn base_root(&self) -> &H256 { &self.storage_root }
|
||||||
|
|
||||||
/// return the storage root associated with this account or None if it has been altered via the overlay.
|
/// Determine whether there are any un-`commit()`-ed storage-setting operations.
|
||||||
pub fn storage_root(&self) -> Option<&H256> { if self.storage_overlay.borrow().is_empty() {Some(&self.storage_root)} else {None} }
|
pub fn storage_is_clean(&self) -> bool { self.storage_overlay.borrow().iter().find(|&(_, &(f, _))| f == Filth::Dirty).is_none() }
|
||||||
|
|
||||||
/// rturn the storage overlay.
|
/// return the storage root associated with this account or None if it has been altered via the overlay.
|
||||||
pub fn storage_overlay(&self) -> Ref<HashMap<H256, H256>> { self.storage_overlay.borrow() }
|
pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} }
|
||||||
|
|
||||||
|
/// 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<HashMap<H256, (Filth, H256)>> { self.storage_overlay.borrow() }
|
||||||
|
|
||||||
/// Increment the nonce of the account by one.
|
/// Increment the nonce of the account by one.
|
||||||
pub fn inc_nonce(&mut self) { self.nonce = self.nonce + U256::from(1u8); }
|
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`.
|
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
|
||||||
pub fn commit_storage(&mut self, db: &mut HashDB) {
|
pub fn commit_storage(&mut self, db: &mut HashDB) {
|
||||||
let mut t = SecTrieDBMut::new(db, &mut self.storage_root);
|
let mut t = SecTrieDBMut::new(db, &mut self.storage_root);
|
||||||
for (k, v) in self.storage_overlay.borrow().iter() {
|
for (k, &mut (ref mut f, ref mut v)) in self.storage_overlay.borrow_mut().iter_mut() {
|
||||||
// cast key and value to trait type,
|
if f == &Filth::Dirty {
|
||||||
// so we can call overloaded `to_bytes` method
|
// cast key and value to trait type,
|
||||||
t.insert(k, &encode(&U256::from(v.as_slice())));
|
// 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.
|
/// 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);
|
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(0x00u64))), H256::from(&U256::from(0x1234u64)));
|
||||||
assert_eq!(a.storage_at(&mut db, &H256::from(&U256::from(0x01u64))), H256::new());
|
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)));
|
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
|
||||||
assert_eq!(a.storage_root(), None);
|
assert_eq!(a.storage_root(), None);
|
||||||
a.commit_storage(&mut db);
|
a.commit_storage(&mut db);
|
||||||
assert_eq!(a.storage_root().unwrap().hex(), "3541f181d6dad5c504371884684d08c29a8bad04926f8ceddf5e279dbc3cc769");
|
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -30,22 +30,23 @@ impl EnvInfo {
|
|||||||
number: 0,
|
number: 0,
|
||||||
author: Address::new(),
|
author: Address::new(),
|
||||||
timestamp: 0,
|
timestamp: 0,
|
||||||
difficulty: U256::zero(),
|
difficulty: x!(0),
|
||||||
gas_limit: U256::zero(),
|
gas_limit: x!(0),
|
||||||
last_hashes: vec![],
|
last_hashes: vec![],
|
||||||
gas_used: U256::zero()
|
gas_used: x!(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_json(json: &Json) -> EnvInfo {
|
pub fn from_json(json: &Json) -> EnvInfo {
|
||||||
|
let current_number = u64_from_json(&json["currentNumber"]);
|
||||||
EnvInfo {
|
EnvInfo {
|
||||||
number: u64_from_json(&json["currentNumber"]),
|
number: current_number,
|
||||||
author: address_from_json(&json["currentCoinbase"]),
|
author: address_from_json(&json["currentCoinbase"]),
|
||||||
difficulty: u256_from_json(&json["currentDifficulty"]),
|
difficulty: u256_from_json(&json["currentDifficulty"]),
|
||||||
gas_limit: u256_from_json(&json["currentGasLimit"]),
|
gas_limit: u256_from_json(&json["currentGasLimit"]),
|
||||||
timestamp: u64_from_json(&json["currentTimestamp"]),
|
timestamp: u64_from_json(&json["currentTimestamp"]),
|
||||||
last_hashes: vec![h256_from_json(&json["previousHash"])],
|
last_hashes: (1..257).map(|i| format!("{}", current_number - i).as_bytes().sha3()).collect(),
|
||||||
gas_used: U256::zero(),
|
gas_used: x!(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user