2019-01-07 11:33:07 +01:00
|
|
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
|
|
|
// This file is part of Parity Ethereum.
|
2016-02-05 13:40:41 +01:00
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
2016-02-05 13:40:41 +01:00
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
2016-02-05 13:40:41 +01:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2019-01-07 11:33:07 +01:00
|
|
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
2016-02-05 13:40:41 +01:00
|
|
|
|
2016-02-02 15:29:53 +01:00
|
|
|
//! Single account in the system.
|
2019-07-04 15:20:44 +02:00
|
|
|
use log::{warn, trace};
|
2017-07-29 17:12:07 +02:00
|
|
|
use std::fmt;
|
2017-07-29 21:56:42 +02:00
|
|
|
use std::sync::Arc;
|
2018-02-27 18:37:36 +01:00
|
|
|
use std::collections::{HashMap, BTreeMap};
|
2019-07-04 15:20:44 +02:00
|
|
|
use keccak_hash::{KECCAK_EMPTY, KECCAK_NULL_RLP, keccak};
|
2019-06-03 15:36:21 +02:00
|
|
|
use ethereum_types::{H256, U256, Address, BigEndianHash};
|
2019-02-20 19:09:34 +01:00
|
|
|
use hash_db::HashDB;
|
2018-07-02 18:50:05 +02:00
|
|
|
use keccak_hasher::KeccakHasher;
|
2018-01-10 13:35:18 +01:00
|
|
|
use kvdb::DBValue;
|
2019-07-04 15:20:44 +02:00
|
|
|
use parity_bytes::{Bytes, ToPretty};
|
|
|
|
use trie_db::{Trie, Recorder};
|
2018-07-02 18:50:05 +02:00
|
|
|
use ethtrie::{TrieFactory, TrieDB, SecTrieDB, Result as TrieResult};
|
2019-07-04 15:20:44 +02:00
|
|
|
use pod_account::PodAccount;
|
|
|
|
use rlp::{RlpStream, DecoderError, encode};
|
2016-09-27 18:02:11 +02:00
|
|
|
use lru_cache::LruCache;
|
2019-07-04 15:20:44 +02:00
|
|
|
use common_types::basic_account::BasicAccount;
|
2016-02-04 02:40:35 +01:00
|
|
|
|
2016-09-27 18:02:11 +02:00
|
|
|
use std::cell::{RefCell, Cell};
|
|
|
|
|
2016-10-06 01:53:23 +02:00
|
|
|
const STORAGE_CACHE_ITEMS: usize = 8192;
|
2016-08-03 18:35:48 +02:00
|
|
|
|
2017-12-22 14:37:39 +01:00
|
|
|
/// Boolean type for clean/dirty status.
|
|
|
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
|
|
|
pub enum Filth {
|
|
|
|
/// Data has not been changed.
|
|
|
|
Clean,
|
|
|
|
/// Data has been changed.
|
|
|
|
Dirty,
|
|
|
|
}
|
|
|
|
|
2016-01-13 01:19:05 +01:00
|
|
|
/// Single account in the system.
|
2016-10-06 01:53:23 +02:00
|
|
|
/// Keeps track of changes to the code and storage.
|
|
|
|
/// The changes are applied in `commit_storage` and `commit_code`
|
2015-12-13 21:36:17 +01:00
|
|
|
pub struct Account {
|
2015-12-13 23:12:22 +01:00
|
|
|
// Balance of the account.
|
2015-12-13 21:36:17 +01:00
|
|
|
balance: U256,
|
2015-12-13 23:12:22 +01:00
|
|
|
// Nonce of the account.
|
2015-12-13 21:36:17 +01:00
|
|
|
nonce: U256,
|
|
|
|
// Trie-backed storage.
|
|
|
|
storage_root: H256,
|
2016-09-27 18:02:11 +02:00
|
|
|
// LRU Cache of the trie-backed storage.
|
|
|
|
// This is limited to `STORAGE_CACHE_ITEMS` recent queries
|
|
|
|
storage_cache: RefCell<LruCache<H256, H256>>,
|
2018-09-07 12:51:08 +02:00
|
|
|
// LRU Cache of the trie-backed storage for original value.
|
|
|
|
// This is only used when the initial storage root is different compared to
|
|
|
|
// what is in the database. That is, it is only used for new contracts.
|
|
|
|
original_storage_cache: Option<(H256, RefCell<LruCache<H256, H256>>)>,
|
2016-09-27 18:02:11 +02:00
|
|
|
// Modified storage. Accumulates changes to storage made in `set_storage`
|
|
|
|
// Takes precedence over `storage_cache`.
|
|
|
|
storage_changes: HashMap<H256, H256>,
|
2016-10-02 18:45:36 +02:00
|
|
|
// Code hash of the account.
|
|
|
|
code_hash: H256,
|
2018-03-20 15:46:03 +01:00
|
|
|
// Size of the account code.
|
2016-09-27 18:02:11 +02:00
|
|
|
code_size: Option<usize>,
|
2015-12-13 23:12:22 +01:00
|
|
|
// Code cache of the account.
|
2016-10-02 18:45:36 +02:00
|
|
|
code_cache: Arc<Bytes>,
|
|
|
|
// Account code new or has been modified.
|
|
|
|
code_filth: Filth,
|
2016-08-18 09:42:46 +02:00
|
|
|
// Cached address hash.
|
|
|
|
address_hash: Cell<Option<H256>>,
|
2015-12-13 21:36:17 +01:00
|
|
|
}
|
|
|
|
|
2017-01-03 16:32:50 +01:00
|
|
|
impl From<BasicAccount> for Account {
|
|
|
|
fn from(basic: BasicAccount) -> Self {
|
|
|
|
Account {
|
|
|
|
balance: basic.balance,
|
|
|
|
nonce: basic.nonce,
|
|
|
|
storage_root: basic.storage_root,
|
|
|
|
storage_cache: Self::empty_storage_cache(),
|
2018-09-07 12:51:08 +02:00
|
|
|
original_storage_cache: None,
|
2017-01-03 16:32:50 +01:00
|
|
|
storage_changes: HashMap::new(),
|
|
|
|
code_hash: basic.code_hash,
|
|
|
|
code_size: None,
|
|
|
|
code_cache: Arc::new(vec![]),
|
|
|
|
code_filth: Filth::Clean,
|
|
|
|
address_hash: Cell::new(None),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 21:36:17 +01:00
|
|
|
impl Account {
|
2016-02-02 23:45:50 +01:00
|
|
|
#[cfg(test)]
|
2015-12-13 23:12:22 +01:00
|
|
|
/// General constructor.
|
|
|
|
pub fn new(balance: U256, nonce: U256, storage: HashMap<H256, H256>, code: Bytes) -> Account {
|
|
|
|
Account {
|
|
|
|
balance: balance,
|
|
|
|
nonce: nonce,
|
2017-08-30 19:18:28 +02:00
|
|
|
storage_root: KECCAK_NULL_RLP,
|
2016-09-27 18:02:11 +02:00
|
|
|
storage_cache: Self::empty_storage_cache(),
|
2018-09-07 12:51:08 +02:00
|
|
|
original_storage_cache: None,
|
2016-09-27 18:02:11 +02:00
|
|
|
storage_changes: storage,
|
2017-08-30 19:18:28 +02:00
|
|
|
code_hash: keccak(&code),
|
2016-09-27 18:02:11 +02:00
|
|
|
code_size: Some(code.len()),
|
2016-10-02 18:45:36 +02:00
|
|
|
code_cache: Arc::new(code),
|
|
|
|
code_filth: Filth::Dirty,
|
2016-08-18 09:42:46 +02:00
|
|
|
address_hash: Cell::new(None),
|
2015-12-13 23:12:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 18:02:11 +02:00
|
|
|
fn empty_storage_cache() -> RefCell<LruCache<H256, H256>> {
|
|
|
|
RefCell::new(LruCache::new(STORAGE_CACHE_ITEMS))
|
|
|
|
}
|
|
|
|
|
2016-01-13 01:19:05 +01:00
|
|
|
/// General constructor.
|
|
|
|
pub fn from_pod(pod: PodAccount) -> Account {
|
|
|
|
Account {
|
|
|
|
balance: pod.balance,
|
|
|
|
nonce: pod.nonce,
|
2017-08-30 19:18:28 +02:00
|
|
|
storage_root: KECCAK_NULL_RLP,
|
2016-09-27 18:02:11 +02:00
|
|
|
storage_cache: Self::empty_storage_cache(),
|
2018-09-07 12:51:08 +02:00
|
|
|
original_storage_cache: None,
|
2016-09-27 18:02:11 +02:00
|
|
|
storage_changes: pod.storage.into_iter().collect(),
|
2017-08-30 19:18:28 +02:00
|
|
|
code_hash: pod.code.as_ref().map_or(KECCAK_EMPTY, |c| keccak(c)),
|
2016-10-02 18:45:36 +02:00
|
|
|
code_filth: Filth::Dirty,
|
2016-09-27 18:02:11 +02:00
|
|
|
code_size: Some(pod.code.as_ref().map_or(0, |c| c.len())),
|
2016-10-02 18:45:36 +02:00
|
|
|
code_cache: Arc::new(pod.code.map_or_else(|| { warn!("POD account with unknown code is being created! Assuming no code."); vec![] }, |c| c)),
|
2016-08-18 09:42:46 +02:00
|
|
|
address_hash: Cell::new(None),
|
2016-01-13 01:19:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-04 15:20:44 +02:00
|
|
|
/// Convert Account to a PodAccount.
|
|
|
|
/// NOTE: This will silently fail unless the account is fully cached.
|
|
|
|
pub fn to_pod(&self) -> PodAccount {
|
|
|
|
PodAccount {
|
|
|
|
balance: self.balance,
|
|
|
|
nonce: self.nonce,
|
|
|
|
storage: self.storage_changes.iter().fold(BTreeMap::new(), |mut m, (k, v)| {
|
|
|
|
m.insert(k.clone(), v.clone());
|
|
|
|
m
|
|
|
|
}),
|
|
|
|
code: self.code().map(|x| x.to_vec()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 23:12:22 +01:00
|
|
|
/// Create a new account with the given balance.
|
2015-12-19 22:15:22 +01:00
|
|
|
pub fn new_basic(balance: U256, nonce: U256) -> Account {
|
2015-12-13 23:12:22 +01:00
|
|
|
Account {
|
|
|
|
balance: balance,
|
2015-12-19 22:15:22 +01:00
|
|
|
nonce: nonce,
|
2017-08-30 19:18:28 +02:00
|
|
|
storage_root: KECCAK_NULL_RLP,
|
2016-09-27 18:02:11 +02:00
|
|
|
storage_cache: Self::empty_storage_cache(),
|
2018-09-07 12:51:08 +02:00
|
|
|
original_storage_cache: None,
|
2016-09-27 18:02:11 +02:00
|
|
|
storage_changes: HashMap::new(),
|
2017-08-30 19:18:28 +02:00
|
|
|
code_hash: KECCAK_EMPTY,
|
2016-10-02 18:45:36 +02:00
|
|
|
code_cache: Arc::new(vec![]),
|
2016-09-27 18:02:11 +02:00
|
|
|
code_size: Some(0),
|
2016-10-02 18:45:36 +02:00
|
|
|
code_filth: Filth::Clean,
|
2016-08-18 09:42:46 +02:00
|
|
|
address_hash: Cell::new(None),
|
2015-12-13 23:12:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-14 11:32:12 +01:00
|
|
|
/// Create a new account from RLP.
|
2019-07-04 15:20:44 +02:00
|
|
|
pub fn from_rlp(rlp: &[u8]) -> Result<Account, DecoderError> {
|
2018-05-08 11:22:12 +02:00
|
|
|
::rlp::decode::<BasicAccount>(rlp)
|
|
|
|
.map(|ba| ba.into())
|
2015-12-13 21:36:17 +01:00
|
|
|
}
|
|
|
|
|
2015-12-14 11:32:12 +01:00
|
|
|
/// Create a new contract account.
|
2016-01-09 12:30:41 +01:00
|
|
|
/// NOTE: make sure you use `init_code` on this before `commit`ing.
|
2018-09-07 12:51:08 +02:00
|
|
|
pub fn new_contract(balance: U256, nonce: U256, original_storage_root: H256) -> Account {
|
2015-12-13 21:36:17 +01:00
|
|
|
Account {
|
2015-12-14 11:32:12 +01:00
|
|
|
balance: balance,
|
2016-03-01 18:17:59 +01:00
|
|
|
nonce: nonce,
|
2017-08-30 19:18:28 +02:00
|
|
|
storage_root: KECCAK_NULL_RLP,
|
2016-09-27 18:02:11 +02:00
|
|
|
storage_cache: Self::empty_storage_cache(),
|
2018-09-07 12:51:08 +02:00
|
|
|
original_storage_cache: if original_storage_root == KECCAK_NULL_RLP {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some((original_storage_root, Self::empty_storage_cache()))
|
|
|
|
},
|
2016-09-27 18:02:11 +02:00
|
|
|
storage_changes: HashMap::new(),
|
2017-08-30 19:18:28 +02:00
|
|
|
code_hash: KECCAK_EMPTY,
|
2016-10-02 18:45:36 +02:00
|
|
|
code_cache: Arc::new(vec![]),
|
2016-09-27 18:02:11 +02:00
|
|
|
code_size: None,
|
2016-10-02 18:45:36 +02:00
|
|
|
code_filth: Filth::Clean,
|
2016-08-18 09:42:46 +02:00
|
|
|
address_hash: Cell::new(None),
|
2015-12-13 21:36:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 23:12:22 +01:00
|
|
|
/// Set this account's code to the given code.
|
2016-02-02 23:06:34 +01:00
|
|
|
/// NOTE: Account should have been created with `new_contract()`
|
2016-01-09 12:30:41 +01:00
|
|
|
pub fn init_code(&mut self, code: Bytes) {
|
2017-08-30 19:18:28 +02:00
|
|
|
self.code_hash = keccak(&code);
|
2016-10-02 18:45:36 +02:00
|
|
|
self.code_cache = Arc::new(code);
|
2016-09-27 18:02:11 +02:00
|
|
|
self.code_size = Some(self.code_cache.len());
|
2016-10-02 18:45:36 +02:00
|
|
|
self.code_filth = Filth::Dirty;
|
2015-12-13 23:12:22 +01:00
|
|
|
}
|
|
|
|
|
2016-06-29 16:29:04 +02:00
|
|
|
/// Reset this account's code to the given code.
|
|
|
|
pub fn reset_code(&mut self, code: Bytes) {
|
|
|
|
self.init_code(code);
|
|
|
|
}
|
|
|
|
|
2018-04-09 16:14:33 +02:00
|
|
|
/// Reset this account's code and storage to given values.
|
|
|
|
pub fn reset_code_and_storage(&mut self, code: Arc<Bytes>, storage: HashMap<H256, H256>) {
|
|
|
|
self.code_hash = keccak(&*code);
|
|
|
|
self.code_cache = code;
|
|
|
|
self.code_size = Some(self.code_cache.len());
|
|
|
|
self.code_filth = Filth::Dirty;
|
|
|
|
self.storage_cache = Self::empty_storage_cache();
|
|
|
|
self.storage_changes = storage;
|
2018-10-31 16:55:11 +01:00
|
|
|
if self.storage_root != KECCAK_NULL_RLP {
|
|
|
|
self.original_storage_cache = Some((self.storage_root, Self::empty_storage_cache()));
|
|
|
|
}
|
|
|
|
self.storage_root = KECCAK_NULL_RLP;
|
2018-04-09 16:14:33 +02:00
|
|
|
}
|
|
|
|
|
2015-12-16 12:46:25 +01:00
|
|
|
/// Set (and cache) the contents of the trie's storage at `key` to `value`.
|
2015-12-14 11:32:12 +01:00
|
|
|
pub fn set_storage(&mut self, key: H256, value: H256) {
|
2016-10-06 01:53:23 +02:00
|
|
|
self.storage_changes.insert(key, value);
|
2015-12-14 11:32:12 +01:00
|
|
|
}
|
|
|
|
|
2015-12-16 12:46:25 +01:00
|
|
|
/// Get (and cache) the contents of the trie's storage at `key`.
|
2018-03-20 15:46:03 +01:00
|
|
|
/// Takes modified storage into account.
|
2019-06-14 18:48:35 +02:00
|
|
|
pub fn storage_at(&self, db: &dyn HashDB<KeccakHasher, DBValue>, key: &H256) -> TrieResult<H256> {
|
2016-09-27 18:02:11 +02:00
|
|
|
if let Some(value) = self.cached_storage_at(key) {
|
2017-02-26 13:10:50 +01:00
|
|
|
return Ok(value);
|
2016-09-27 18:02:11 +02:00
|
|
|
}
|
2018-09-07 12:51:08 +02:00
|
|
|
Self::get_and_cache_storage(
|
|
|
|
&self.storage_root,
|
|
|
|
&mut self.storage_cache.borrow_mut(),
|
|
|
|
db,
|
|
|
|
key)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get (and cache) the contents of the trie's storage at `key`.
|
|
|
|
/// Does not take modified storage into account.
|
2019-06-14 18:48:35 +02:00
|
|
|
pub fn original_storage_at(&self, db: &dyn HashDB<KeccakHasher, DBValue>, key: &H256) -> TrieResult<H256> {
|
2018-09-07 12:51:08 +02:00
|
|
|
if let Some(value) = self.cached_original_storage_at(key) {
|
|
|
|
return Ok(value);
|
|
|
|
}
|
|
|
|
match &self.original_storage_cache {
|
|
|
|
Some((ref original_storage_root, ref original_storage_cache)) =>
|
|
|
|
Self::get_and_cache_storage(
|
|
|
|
original_storage_root,
|
|
|
|
&mut original_storage_cache.borrow_mut(),
|
|
|
|
db,
|
|
|
|
key
|
|
|
|
),
|
|
|
|
None =>
|
|
|
|
Self::get_and_cache_storage(
|
|
|
|
&self.storage_root,
|
|
|
|
&mut self.storage_cache.borrow_mut(),
|
|
|
|
db,
|
|
|
|
key
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-14 18:48:35 +02:00
|
|
|
fn get_and_cache_storage(storage_root: &H256, storage_cache: &mut LruCache<H256, H256>, db: &dyn HashDB<KeccakHasher, DBValue>, key: &H256) -> TrieResult<H256> {
|
2019-02-20 19:09:34 +01:00
|
|
|
let db = SecTrieDB::new(&db, storage_root)?;
|
2018-05-08 11:22:12 +02:00
|
|
|
let panicky_decoder = |bytes:&[u8]| ::rlp::decode(&bytes).expect("decoding db value failed");
|
2019-06-03 15:36:21 +02:00
|
|
|
let item: U256 = db.get_with(key.as_bytes(), panicky_decoder)?.unwrap_or_else(U256::zero);
|
|
|
|
let value: H256 = BigEndianHash::from_uint(&item);
|
2018-09-07 12:51:08 +02:00
|
|
|
storage_cache.insert(key.clone(), value.clone());
|
2017-02-26 13:10:50 +01:00
|
|
|
Ok(value)
|
2016-09-27 18:02:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Get cached storage value if any. Returns `None` if the
|
|
|
|
/// key is not in the cache.
|
|
|
|
pub fn cached_storage_at(&self, key: &H256) -> Option<H256> {
|
|
|
|
if let Some(value) = self.storage_changes.get(key) {
|
|
|
|
return Some(value.clone())
|
|
|
|
}
|
2018-09-07 12:51:08 +02:00
|
|
|
self.cached_moved_original_storage_at(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get cached original storage value after last state commitment. Returns `None` if the key is not in the cache.
|
|
|
|
pub fn cached_original_storage_at(&self, key: &H256) -> Option<H256> {
|
|
|
|
match &self.original_storage_cache {
|
|
|
|
Some((_, ref original_storage_cache)) => {
|
|
|
|
if let Some(value) = original_storage_cache.borrow_mut().get_mut(key) {
|
|
|
|
Some(value.clone())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
self.cached_moved_original_storage_at(key)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get cached original storage value since last contract creation on this address. Returns `None` if the key is not in the cache.
|
|
|
|
fn cached_moved_original_storage_at(&self, key: &H256) -> Option<H256> {
|
|
|
|
// If storage root is empty RLP, then early return zero value. Practically, this makes it so that if
|
|
|
|
// `original_storage_cache` is used, then `storage_cache` will always remain empty.
|
|
|
|
if self.storage_root == KECCAK_NULL_RLP {
|
2019-06-03 15:36:21 +02:00
|
|
|
return Some(H256::zero());
|
2018-09-07 12:51:08 +02:00
|
|
|
}
|
|
|
|
|
2016-09-27 18:02:11 +02:00
|
|
|
if let Some(value) = self.storage_cache.borrow_mut().get_mut(key) {
|
2018-09-07 12:51:08 +02:00
|
|
|
Some(value.clone())
|
|
|
|
} else {
|
|
|
|
None
|
2016-09-27 18:02:11 +02:00
|
|
|
}
|
2015-12-16 12:46:25 +01:00
|
|
|
}
|
|
|
|
|
2015-12-13 23:12:22 +01:00
|
|
|
/// return the balance associated with this account.
|
2015-12-13 21:36:17 +01:00
|
|
|
pub fn balance(&self) -> &U256 { &self.balance }
|
2015-12-15 13:09:50 +01:00
|
|
|
|
2015-12-13 23:12:22 +01:00
|
|
|
/// return the nonce associated with this account.
|
2015-12-13 21:36:17 +01:00
|
|
|
pub fn nonce(&self) -> &U256 { &self.nonce }
|
2015-12-15 13:09:50 +01:00
|
|
|
|
2015-12-13 23:12:22 +01:00
|
|
|
/// return the code hash associated with this account.
|
|
|
|
pub fn code_hash(&self) -> H256 {
|
2016-10-02 18:45:36 +02:00
|
|
|
self.code_hash.clone()
|
2015-12-13 21:36:17 +01:00
|
|
|
}
|
2015-12-15 13:09:50 +01:00
|
|
|
|
2018-09-04 11:25:22 +02:00
|
|
|
/// return and cache `keccak(address)`, `address` must be the address of this
|
|
|
|
/// account.
|
2016-08-18 09:42:46 +02:00
|
|
|
pub fn address_hash(&self, address: &Address) -> H256 {
|
|
|
|
let hash = self.address_hash.get();
|
|
|
|
hash.unwrap_or_else(|| {
|
2017-08-30 19:18:28 +02:00
|
|
|
let hash = keccak(address);
|
2016-08-18 09:42:46 +02:00
|
|
|
self.address_hash.set(Some(hash.clone()));
|
|
|
|
hash
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-12-14 11:32:12 +01:00
|
|
|
/// returns the account's code. If `None` then the code cache isn't available -
|
|
|
|
/// get someone who knows to call `note_code`.
|
2016-10-02 18:45:36 +02:00
|
|
|
pub fn code(&self) -> Option<Arc<Bytes>> {
|
2017-08-30 19:18:28 +02:00
|
|
|
if self.code_hash != KECCAK_EMPTY && self.code_cache.is_empty() {
|
2016-10-02 18:45:36 +02:00
|
|
|
return None;
|
2015-12-14 11:32:12 +01:00
|
|
|
}
|
2016-10-02 18:45:36 +02:00
|
|
|
Some(self.code_cache.clone())
|
2015-12-14 11:32:12 +01:00
|
|
|
}
|
|
|
|
|
2016-09-27 18:02:11 +02:00
|
|
|
/// returns the account's code size. If `None` then the code cache or code size cache isn't available -
|
|
|
|
/// get someone who knows to call `note_code`.
|
|
|
|
pub fn code_size(&self) -> Option<usize> {
|
|
|
|
self.code_size.clone()
|
|
|
|
}
|
|
|
|
|
2016-02-03 15:33:58 +01:00
|
|
|
#[cfg(test)]
|
2015-12-14 11:32:12 +01:00
|
|
|
/// Provide a byte array which hashes to the `code_hash`. returns the hash as a result.
|
2015-12-16 12:46:25 +01:00
|
|
|
pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> {
|
2017-08-30 19:18:28 +02:00
|
|
|
let h = keccak(&code);
|
2016-10-02 18:45:36 +02:00
|
|
|
if self.code_hash == h {
|
|
|
|
self.code_cache = Arc::new(code);
|
|
|
|
self.code_size = Some(self.code_cache.len());
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(h)
|
2015-12-14 11:32:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-16 12:46:25 +01:00
|
|
|
/// Is `code_cache` valid; such that code is going to return Some?
|
|
|
|
pub fn is_cached(&self) -> bool {
|
2017-08-30 19:18:28 +02:00
|
|
|
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == KECCAK_EMPTY)
|
2015-12-16 12:46:25 +01:00
|
|
|
}
|
|
|
|
|
2018-07-31 07:27:57 +02:00
|
|
|
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code. Returns the cached code, if successful.
|
|
|
|
#[must_use]
|
2019-06-14 18:48:35 +02:00
|
|
|
pub fn cache_code(&mut self, db: &dyn HashDB<KeccakHasher, DBValue>) -> Option<Arc<Bytes>> {
|
2015-12-16 12:46:25 +01:00
|
|
|
// TODO: fill out self.code_cache;
|
2016-01-26 15:00:22 +01:00
|
|
|
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
|
2016-10-28 16:04:44 +02:00
|
|
|
|
2018-07-31 07:27:57 +02:00
|
|
|
if self.is_cached() { return Some(self.code_cache.clone()); }
|
2016-10-28 16:04:44 +02:00
|
|
|
|
2019-06-19 13:54:05 +02:00
|
|
|
match db.get(&self.code_hash, hash_db::EMPTY_PREFIX) {
|
2016-10-02 18:45:36 +02:00
|
|
|
Some(x) => {
|
|
|
|
self.code_size = Some(x.len());
|
2017-06-28 14:16:53 +02:00
|
|
|
self.code_cache = Arc::new(x.into_vec());
|
2016-10-28 16:04:44 +02:00
|
|
|
Some(self.code_cache.clone())
|
2016-10-02 18:45:36 +02:00
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
warn!("Failed reverse get of {}", self.code_hash);
|
2016-10-28 16:04:44 +02:00
|
|
|
None
|
2016-10-02 18:45:36 +02:00
|
|
|
},
|
|
|
|
}
|
2016-09-27 18:02:11 +02:00
|
|
|
}
|
|
|
|
|
2018-07-31 07:27:57 +02:00
|
|
|
/// Provide code to cache. For correctness, should be the correct code for the account.
|
2016-10-28 16:04:44 +02:00
|
|
|
pub fn cache_given_code(&mut self, code: Arc<Bytes>) {
|
|
|
|
trace!("Account::cache_given_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
|
|
|
|
|
|
|
|
self.code_size = Some(code.len());
|
|
|
|
self.code_cache = code;
|
|
|
|
}
|
|
|
|
|
2018-07-31 07:27:57 +02:00
|
|
|
/// Provide a database to get `code_size`. Should not be called if it is a contract without code. Returns whether
|
|
|
|
/// the cache succeeds.
|
|
|
|
#[must_use]
|
2019-06-14 18:48:35 +02:00
|
|
|
pub fn cache_code_size(&mut self, db: &dyn HashDB<KeccakHasher, DBValue>) -> bool {
|
2016-09-27 18:02:11 +02:00
|
|
|
// TODO: fill out self.code_cache;
|
|
|
|
trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
|
|
|
|
self.code_size.is_some() ||
|
2017-08-30 19:18:28 +02:00
|
|
|
if self.code_hash != KECCAK_EMPTY {
|
2019-06-19 13:54:05 +02:00
|
|
|
match db.get(&self.code_hash, hash_db::EMPTY_PREFIX) {
|
2016-09-27 18:02:11 +02:00
|
|
|
Some(x) => {
|
|
|
|
self.code_size = Some(x.len());
|
|
|
|
true
|
|
|
|
},
|
2016-01-26 15:00:22 +01:00
|
|
|
_ => {
|
2016-10-02 18:45:36 +02:00
|
|
|
warn!("Failed reverse get of {}", self.code_hash);
|
2016-01-26 15:00:22 +01:00
|
|
|
false
|
|
|
|
},
|
2016-10-02 18:45:36 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-07-31 07:27:57 +02:00
|
|
|
// If the code hash is empty hash, then the code size is zero.
|
|
|
|
self.code_size = Some(0);
|
|
|
|
true
|
2015-12-16 12:46:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-14 13:54:29 +01:00
|
|
|
/// Determine whether there are any un-`commit()`-ed storage-setting operations.
|
2016-09-27 18:02:11 +02:00
|
|
|
pub fn storage_is_clean(&self) -> bool { self.storage_changes.is_empty() }
|
2016-02-09 22:32:47 +01:00
|
|
|
|
2016-10-20 16:49:27 +02:00
|
|
|
/// Check if account has zero nonce, balance, no code and no storage.
|
2016-11-03 22:22:25 +01:00
|
|
|
///
|
|
|
|
/// NOTE: Will panic if `!self.storage_is_clean()`
|
2016-10-20 16:49:27 +02:00
|
|
|
pub fn is_empty(&self) -> bool {
|
2016-11-03 22:22:25 +01:00
|
|
|
assert!(self.storage_is_clean(), "Account::is_empty() may only legally be called when storage is clean.");
|
2017-08-30 19:18:28 +02:00
|
|
|
self.is_null() && self.storage_root == KECCAK_NULL_RLP
|
2016-11-03 22:22:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Check if account has zero nonce, balance, no code.
|
|
|
|
pub fn is_null(&self) -> bool {
|
2016-10-20 16:49:27 +02:00
|
|
|
self.balance.is_zero() &&
|
|
|
|
self.nonce.is_zero() &&
|
2017-08-30 19:18:28 +02:00
|
|
|
self.code_hash == KECCAK_EMPTY
|
2016-10-20 16:49:27 +02:00
|
|
|
}
|
|
|
|
|
2017-06-28 09:10:57 +02:00
|
|
|
/// Check if account is basic (Has no code).
|
|
|
|
pub fn is_basic(&self) -> bool {
|
2017-08-30 19:18:28 +02:00
|
|
|
self.code_hash == KECCAK_EMPTY
|
2017-06-28 09:10:57 +02:00
|
|
|
}
|
|
|
|
|
2016-11-27 11:11:56 +01:00
|
|
|
/// Return the storage root associated with this account or None if it has been altered via the overlay.
|
2018-09-07 12:51:08 +02:00
|
|
|
pub fn storage_root(&self) -> Option<H256> {
|
|
|
|
if self.storage_is_clean() {
|
|
|
|
Some(self.storage_root)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the original storage root of this account.
|
|
|
|
pub fn original_storage_root(&self) -> H256 {
|
|
|
|
if let Some((original_storage_root, _)) = self.original_storage_cache {
|
|
|
|
original_storage_root
|
|
|
|
} else {
|
|
|
|
self.storage_root
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-15 10:21:44 +01:00
|
|
|
/// Whether the base storage root of this account is unchanged.
|
|
|
|
pub fn is_base_storage_root_unchanged(&self) -> bool {
|
|
|
|
self.original_storage_cache.is_none()
|
|
|
|
}
|
|
|
|
|
2018-09-07 12:51:08 +02:00
|
|
|
/// Storage root where the account changes are based upon.
|
|
|
|
pub fn base_storage_root(&self) -> H256 {
|
|
|
|
self.storage_root
|
|
|
|
}
|
2016-02-09 22:32:47 +01:00
|
|
|
|
2016-11-27 11:11:56 +01:00
|
|
|
/// Return the storage overlay.
|
2016-09-27 18:02:11 +02:00
|
|
|
pub fn storage_changes(&self) -> &HashMap<H256, H256> { &self.storage_changes }
|
2015-12-14 11:32:12 +01:00
|
|
|
|
|
|
|
/// Increment the nonce of the account by one.
|
2016-07-17 09:18:15 +02:00
|
|
|
pub fn inc_nonce(&mut self) {
|
2019-02-11 23:20:51 +01:00
|
|
|
self.nonce = self.nonce.saturating_add(U256::from(1u8));
|
2016-07-17 09:18:15 +02:00
|
|
|
}
|
2015-12-14 11:32:12 +01:00
|
|
|
|
2016-10-06 01:53:23 +02:00
|
|
|
/// Increase account balance.
|
2016-07-17 09:18:15 +02:00
|
|
|
pub fn add_balance(&mut self, x: &U256) {
|
2019-02-11 23:20:51 +01:00
|
|
|
self.balance = self.balance.saturating_add(*x);
|
2016-07-17 09:18:15 +02:00
|
|
|
}
|
2015-12-14 11:32:12 +01:00
|
|
|
|
2016-10-06 01:53:23 +02:00
|
|
|
/// Decrease account balance.
|
2016-02-09 22:32:47 +01:00
|
|
|
/// Panics if balance is less than `x`
|
|
|
|
pub fn sub_balance(&mut self, x: &U256) {
|
2016-10-06 01:53:23 +02:00
|
|
|
assert!(self.balance >= *x);
|
|
|
|
self.balance = self.balance - *x;
|
2016-02-09 22:32:47 +01:00
|
|
|
}
|
2015-12-14 11:32:12 +01:00
|
|
|
|
2016-09-27 18:02:11 +02:00
|
|
|
/// Commit the `storage_changes` to the backing DB and update `storage_root`.
|
2019-06-14 18:48:35 +02:00
|
|
|
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut dyn HashDB<KeccakHasher, DBValue>) -> TrieResult<()> {
|
2017-02-26 13:10:50 +01:00
|
|
|
let mut t = trie_factory.from_existing(db, &mut self.storage_root)?;
|
2016-09-27 18:02:11 +02:00
|
|
|
for (k, v) in self.storage_changes.drain() {
|
|
|
|
// cast key and value to trait type,
|
|
|
|
// so we can call overloaded `to_bytes` method
|
2017-02-26 13:10:50 +01:00
|
|
|
match v.is_zero() {
|
2019-06-03 15:36:21 +02:00
|
|
|
true => t.remove(k.as_bytes())?,
|
|
|
|
false => t.insert(k.as_bytes(), &encode(&v.into_uint()))?,
|
2016-09-27 18:02:11 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
self.storage_cache.borrow_mut().insert(k, v);
|
2015-12-13 21:36:17 +01:00
|
|
|
}
|
2018-09-07 12:51:08 +02:00
|
|
|
self.original_storage_cache = None;
|
2017-02-26 13:10:50 +01:00
|
|
|
Ok(())
|
2015-12-13 21:36:17 +01:00
|
|
|
}
|
|
|
|
|
2015-12-14 11:32:12 +01:00
|
|
|
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
|
2019-06-14 18:48:35 +02:00
|
|
|
pub fn commit_code(&mut self, db: &mut dyn HashDB<KeccakHasher, DBValue>) {
|
2016-10-02 18:45:36 +02:00
|
|
|
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_filth == Filth::Dirty, self.code_cache.is_empty());
|
|
|
|
match (self.code_filth == Filth::Dirty, self.code_cache.is_empty()) {
|
2016-09-27 18:02:11 +02:00
|
|
|
(true, true) => {
|
|
|
|
self.code_size = Some(0);
|
2016-10-02 18:45:36 +02:00
|
|
|
self.code_filth = Filth::Clean;
|
2016-09-27 18:02:11 +02:00
|
|
|
},
|
2015-12-19 19:00:19 +01:00
|
|
|
(true, false) => {
|
2019-06-19 13:54:05 +02:00
|
|
|
db.emplace(self.code_hash.clone(), hash_db::EMPTY_PREFIX, DBValue::from_slice(&*self.code_cache));
|
2016-09-27 18:02:11 +02:00
|
|
|
self.code_size = Some(self.code_cache.len());
|
2016-10-02 18:45:36 +02:00
|
|
|
self.code_filth = Filth::Clean;
|
2015-12-19 19:00:19 +01:00
|
|
|
},
|
2015-12-16 12:46:25 +01:00
|
|
|
(false, _) => {},
|
2015-12-13 21:36:17 +01:00
|
|
|
}
|
2015-12-13 23:12:22 +01:00
|
|
|
}
|
2015-12-13 21:49:40 +01:00
|
|
|
|
2015-12-13 23:12:22 +01:00
|
|
|
/// Export to RLP.
|
|
|
|
pub fn rlp(&self) -> Bytes {
|
|
|
|
let mut stream = RlpStream::new_list(4);
|
|
|
|
stream.append(&self.nonce);
|
|
|
|
stream.append(&self.balance);
|
|
|
|
stream.append(&self.storage_root);
|
2016-10-02 18:45:36 +02:00
|
|
|
stream.append(&self.code_hash);
|
2015-12-13 23:12:22 +01:00
|
|
|
stream.out()
|
2015-12-13 21:36:17 +01:00
|
|
|
}
|
2016-09-27 18:02:11 +02:00
|
|
|
|
|
|
|
/// Clone basic account data
|
|
|
|
pub fn clone_basic(&self) -> Account {
|
|
|
|
Account {
|
|
|
|
balance: self.balance.clone(),
|
|
|
|
nonce: self.nonce.clone(),
|
|
|
|
storage_root: self.storage_root.clone(),
|
|
|
|
storage_cache: Self::empty_storage_cache(),
|
2018-09-07 12:51:08 +02:00
|
|
|
original_storage_cache: self.original_storage_cache.as_ref().map(|(r, _)| (*r, Self::empty_storage_cache())),
|
2016-09-27 18:02:11 +02:00
|
|
|
storage_changes: HashMap::new(),
|
|
|
|
code_hash: self.code_hash.clone(),
|
|
|
|
code_size: self.code_size.clone(),
|
2016-10-02 18:45:36 +02:00
|
|
|
code_cache: self.code_cache.clone(),
|
|
|
|
code_filth: self.code_filth,
|
2016-09-27 18:02:11 +02:00
|
|
|
address_hash: self.address_hash.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Clone account data and dirty storage keys
|
|
|
|
pub fn clone_dirty(&self) -> Account {
|
|
|
|
let mut account = self.clone_basic();
|
|
|
|
account.storage_changes = self.storage_changes.clone();
|
|
|
|
account
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Clone account data, dirty storage keys and cached storage keys.
|
|
|
|
pub fn clone_all(&self) -> Account {
|
|
|
|
let mut account = self.clone_dirty();
|
|
|
|
account.storage_cache = self.storage_cache.clone();
|
2018-09-07 12:51:08 +02:00
|
|
|
account.original_storage_cache = self.original_storage_cache.clone();
|
2016-09-27 18:02:11 +02:00
|
|
|
account
|
|
|
|
}
|
|
|
|
|
2016-10-06 01:53:23 +02:00
|
|
|
/// Replace self with the data from other account merging storage cache.
|
|
|
|
/// Basic account data and all modifications are overwritten
|
|
|
|
/// with new values.
|
2016-10-06 15:54:05 +02:00
|
|
|
pub fn overwrite_with(&mut self, other: Account) {
|
2016-09-27 18:02:11 +02:00
|
|
|
self.balance = other.balance;
|
|
|
|
self.nonce = other.nonce;
|
|
|
|
self.code_hash = other.code_hash;
|
2016-10-02 18:45:36 +02:00
|
|
|
self.code_filth = other.code_filth;
|
2016-09-27 18:02:11 +02:00
|
|
|
self.code_cache = other.code_cache;
|
|
|
|
self.code_size = other.code_size;
|
|
|
|
self.address_hash = other.address_hash;
|
2018-09-07 12:51:08 +02:00
|
|
|
if self.storage_root == other.storage_root {
|
|
|
|
let mut cache = self.storage_cache.borrow_mut();
|
|
|
|
for (k, v) in other.storage_cache.into_inner() {
|
|
|
|
cache.insert(k, v);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.storage_cache = other.storage_cache;
|
2016-09-27 18:02:11 +02:00
|
|
|
}
|
2018-09-07 12:51:08 +02:00
|
|
|
self.original_storage_cache = other.original_storage_cache;
|
|
|
|
self.storage_root = other.storage_root;
|
2016-10-06 01:53:23 +02:00
|
|
|
self.storage_changes = other.storage_changes;
|
2016-09-27 18:02:11 +02:00
|
|
|
}
|
2015-12-13 21:36:17 +01:00
|
|
|
}
|
2015-12-14 11:32:12 +01:00
|
|
|
|
2016-11-15 14:53:30 +01:00
|
|
|
// light client storage proof.
|
|
|
|
impl Account {
|
|
|
|
/// Prove a storage key's existence or nonexistence in the account's storage
|
|
|
|
/// trie.
|
|
|
|
/// `storage_key` is the hash of the desired storage key, meaning
|
|
|
|
/// this will only work correctly under a secure trie.
|
2019-06-14 18:48:35 +02:00
|
|
|
pub fn prove_storage(&self, db: &dyn HashDB<KeccakHasher, DBValue>, storage_key: H256) -> TrieResult<(Vec<Bytes>, H256)> {
|
2017-03-23 13:17:05 +01:00
|
|
|
let mut recorder = Recorder::new();
|
2016-11-15 14:53:30 +01:00
|
|
|
|
2019-02-20 19:09:34 +01:00
|
|
|
let trie = TrieDB::new(&db, &self.storage_root)?;
|
2017-03-23 13:17:05 +01:00
|
|
|
let item: U256 = {
|
2018-05-08 11:22:12 +02:00
|
|
|
let panicky_decoder = |bytes:&[u8]| ::rlp::decode(bytes).expect("decoding db value failed");
|
|
|
|
let query = (&mut recorder, panicky_decoder);
|
2019-06-03 15:36:21 +02:00
|
|
|
trie.get_with(storage_key.as_bytes(), query)?.unwrap_or_else(U256::zero)
|
2017-03-23 13:17:05 +01:00
|
|
|
};
|
2016-11-15 14:53:30 +01:00
|
|
|
|
2019-06-03 15:36:21 +02:00
|
|
|
Ok((recorder.drain().into_iter().map(|r| r.data).collect(), BigEndianHash::from_uint(&item)))
|
2016-11-15 14:53:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-13 01:19:05 +01:00
|
|
|
impl fmt::Debug for Account {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2018-02-27 18:37:36 +01:00
|
|
|
f.debug_struct("Account")
|
|
|
|
.field("balance", &self.balance)
|
|
|
|
.field("nonce", &self.nonce)
|
|
|
|
.field("code", &self.code())
|
|
|
|
.field("storage", &self.storage_changes.iter().collect::<BTreeMap<_, _>>())
|
|
|
|
.finish()
|
2016-01-13 01:19:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-15 13:09:50 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2018-02-23 10:12:52 +01:00
|
|
|
use rlp_compress::{compress, decompress, snapshot_swapper};
|
2018-02-09 09:32:06 +01:00
|
|
|
use ethereum_types::{H256, Address};
|
2019-02-20 19:09:34 +01:00
|
|
|
use journaldb::new_memory_db;
|
2019-07-04 15:20:44 +02:00
|
|
|
use parity_bytes::Bytes;
|
2016-01-14 16:46:32 +01:00
|
|
|
use super::*;
|
2019-07-04 17:50:31 +02:00
|
|
|
use account_db::*;
|
2019-06-03 15:36:21 +02:00
|
|
|
use std::str::FromStr;
|
2016-01-14 16:46:32 +01:00
|
|
|
|
Blocks and snapshot compression (#1687)
* new Compressible rlp trait
* new Compressible rlp trait
* make compressed rlp iterable
* make compressed rlp iterable
* invalid rlp slice swapper
* switch compress to swapper, add reverse swapper test case
* add basic account compression test
* add new rlp trait
* new Compressible rlp trait
* make compressed rlp iterable
* invalid rlp slice swapper
* invalid rlp slice swapper
* switch compress to swapper, add reverse swapper test case
* switch compress to swapper, add reverse swapper test case
* add account compress/ decompress test
* make compressor cleaner, use hashmaps for swapper
* improve compression tests
* add a DecompressingDecoder, change Decoder to take refernce
* separate rlp compression related stuff
* new Compressible rlp trait
* new Compressible rlp trait
* new Compressible rlp trait
* make compressed rlp iterable
* make compressed rlp iterable
* make compressed rlp iterable
* invalid rlp slice swapper
* invalid rlp slice swapper
* invalid rlp slice swapper
* switch compress to swapper, add reverse swapper test case
* switch compress to swapper, add reverse swapper test case
* switch compress to swapper, add reverse swapper test case
* add basic account compression test
* add new rlp trait
* add account compress/ decompress test
* make compressor cleaner, use hashmaps for swapper
* improve compression tests
* add a DecompressingDecoder, change Decoder to take refernce
* separate rlp compression related stuff
* DecompressingDecoder test
* initial compressing HashDB wrapper
* remove unused test
* change CompressedDB to struct wrapper with overlay
* simplify compressor
* failed RefCell attempt
* use denote to return reference
* compiled compresseddb
* compressdb test, add overlay emplace
* fix overlay reference count handling
* add immutable compresseddb, make account use hashdb
* simplify using trait objects
* enable hashdb for account
* initial state compression attempt
* wrap state db
* add tests for analyzing db
* add account predicate
* try to compress data fields as rlp too
* remove compression for storage trie
* add a compressing migration
* more compression stats tests
* fix migration import
* nested encoding compression test
* fix decompression, move db stats tests to rlpcompression
* added malformed rlp tests, cover a few edge cases
* new CompressingEncoder struct
* extend migrations to state
* first version working on the whole db
* clean up Compressible impl
* tests cleanup
* add a testing migration
* refactor deep compression using option, add simple compression
* put tests in a module
* fix compressed overlay loading
* simple compression for snapshots
* remove unused DecompressingDecoder
* add a general compressing migration
* add more common rlps to compress
* use static slices for swapper
* add precomputed hashes and invalid rlps
* make decoder private again
* cover more cases with tests
* style
* fix weird indentation
* remove possible panic in payload_info
* make prefix checking safe
* fix db existence check
* remove db dir from test
* pass usize by value [ci skip]
* Improve comment on panic removal.
* add common blocks db rlps
* add compression to blockchain db
* add blocks db migration
* fix the migrations
* remove state compression
* add a separate snapshot swapper
* ability to use different swappers and traversal
* update tests to new interface
* clean up code ordering
* update usage
* fix compilation
* remove unnecessary changes
* move methods to functions to reduce interface
* move test to module
* update common rlps to blocks db
* move tests to tests modules
* remove redundant &
2016-07-27 17:11:41 +02:00
|
|
|
#[test]
|
|
|
|
fn account_compress() {
|
|
|
|
let raw = Account::new_basic(2.into(), 4.into()).rlp();
|
2018-02-23 10:12:52 +01:00
|
|
|
let compact_vec = compress(&raw, snapshot_swapper());
|
Blocks and snapshot compression (#1687)
* new Compressible rlp trait
* new Compressible rlp trait
* make compressed rlp iterable
* make compressed rlp iterable
* invalid rlp slice swapper
* switch compress to swapper, add reverse swapper test case
* add basic account compression test
* add new rlp trait
* new Compressible rlp trait
* make compressed rlp iterable
* invalid rlp slice swapper
* invalid rlp slice swapper
* switch compress to swapper, add reverse swapper test case
* switch compress to swapper, add reverse swapper test case
* add account compress/ decompress test
* make compressor cleaner, use hashmaps for swapper
* improve compression tests
* add a DecompressingDecoder, change Decoder to take refernce
* separate rlp compression related stuff
* new Compressible rlp trait
* new Compressible rlp trait
* new Compressible rlp trait
* make compressed rlp iterable
* make compressed rlp iterable
* make compressed rlp iterable
* invalid rlp slice swapper
* invalid rlp slice swapper
* invalid rlp slice swapper
* switch compress to swapper, add reverse swapper test case
* switch compress to swapper, add reverse swapper test case
* switch compress to swapper, add reverse swapper test case
* add basic account compression test
* add new rlp trait
* add account compress/ decompress test
* make compressor cleaner, use hashmaps for swapper
* improve compression tests
* add a DecompressingDecoder, change Decoder to take refernce
* separate rlp compression related stuff
* DecompressingDecoder test
* initial compressing HashDB wrapper
* remove unused test
* change CompressedDB to struct wrapper with overlay
* simplify compressor
* failed RefCell attempt
* use denote to return reference
* compiled compresseddb
* compressdb test, add overlay emplace
* fix overlay reference count handling
* add immutable compresseddb, make account use hashdb
* simplify using trait objects
* enable hashdb for account
* initial state compression attempt
* wrap state db
* add tests for analyzing db
* add account predicate
* try to compress data fields as rlp too
* remove compression for storage trie
* add a compressing migration
* more compression stats tests
* fix migration import
* nested encoding compression test
* fix decompression, move db stats tests to rlpcompression
* added malformed rlp tests, cover a few edge cases
* new CompressingEncoder struct
* extend migrations to state
* first version working on the whole db
* clean up Compressible impl
* tests cleanup
* add a testing migration
* refactor deep compression using option, add simple compression
* put tests in a module
* fix compressed overlay loading
* simple compression for snapshots
* remove unused DecompressingDecoder
* add a general compressing migration
* add more common rlps to compress
* use static slices for swapper
* add precomputed hashes and invalid rlps
* make decoder private again
* cover more cases with tests
* style
* fix weird indentation
* remove possible panic in payload_info
* make prefix checking safe
* fix db existence check
* remove db dir from test
* pass usize by value [ci skip]
* Improve comment on panic removal.
* add common blocks db rlps
* add compression to blockchain db
* add blocks db migration
* fix the migrations
* remove state compression
* add a separate snapshot swapper
* ability to use different swappers and traversal
* update tests to new interface
* clean up code ordering
* update usage
* fix compilation
* remove unnecessary changes
* move methods to functions to reduce interface
* move test to module
* update common rlps to blocks db
* move tests to tests modules
* remove redundant &
2016-07-27 17:11:41 +02:00
|
|
|
assert!(raw.len() > compact_vec.len());
|
2018-02-23 10:12:52 +01:00
|
|
|
let again_raw = decompress(&compact_vec, snapshot_swapper());
|
2017-06-28 14:16:53 +02:00
|
|
|
assert_eq!(raw, again_raw.into_vec());
|
2018-11-25 20:12:59 +01:00
|
|
|
}
|
Blocks and snapshot compression (#1687)
* new Compressible rlp trait
* new Compressible rlp trait
* make compressed rlp iterable
* make compressed rlp iterable
* invalid rlp slice swapper
* switch compress to swapper, add reverse swapper test case
* add basic account compression test
* add new rlp trait
* new Compressible rlp trait
* make compressed rlp iterable
* invalid rlp slice swapper
* invalid rlp slice swapper
* switch compress to swapper, add reverse swapper test case
* switch compress to swapper, add reverse swapper test case
* add account compress/ decompress test
* make compressor cleaner, use hashmaps for swapper
* improve compression tests
* add a DecompressingDecoder, change Decoder to take refernce
* separate rlp compression related stuff
* new Compressible rlp trait
* new Compressible rlp trait
* new Compressible rlp trait
* make compressed rlp iterable
* make compressed rlp iterable
* make compressed rlp iterable
* invalid rlp slice swapper
* invalid rlp slice swapper
* invalid rlp slice swapper
* switch compress to swapper, add reverse swapper test case
* switch compress to swapper, add reverse swapper test case
* switch compress to swapper, add reverse swapper test case
* add basic account compression test
* add new rlp trait
* add account compress/ decompress test
* make compressor cleaner, use hashmaps for swapper
* improve compression tests
* add a DecompressingDecoder, change Decoder to take refernce
* separate rlp compression related stuff
* DecompressingDecoder test
* initial compressing HashDB wrapper
* remove unused test
* change CompressedDB to struct wrapper with overlay
* simplify compressor
* failed RefCell attempt
* use denote to return reference
* compiled compresseddb
* compressdb test, add overlay emplace
* fix overlay reference count handling
* add immutable compresseddb, make account use hashdb
* simplify using trait objects
* enable hashdb for account
* initial state compression attempt
* wrap state db
* add tests for analyzing db
* add account predicate
* try to compress data fields as rlp too
* remove compression for storage trie
* add a compressing migration
* more compression stats tests
* fix migration import
* nested encoding compression test
* fix decompression, move db stats tests to rlpcompression
* added malformed rlp tests, cover a few edge cases
* new CompressingEncoder struct
* extend migrations to state
* first version working on the whole db
* clean up Compressible impl
* tests cleanup
* add a testing migration
* refactor deep compression using option, add simple compression
* put tests in a module
* fix compressed overlay loading
* simple compression for snapshots
* remove unused DecompressingDecoder
* add a general compressing migration
* add more common rlps to compress
* use static slices for swapper
* add precomputed hashes and invalid rlps
* make decoder private again
* cover more cases with tests
* style
* fix weird indentation
* remove possible panic in payload_info
* make prefix checking safe
* fix db existence check
* remove db dir from test
* pass usize by value [ci skip]
* Improve comment on panic removal.
* add common blocks db rlps
* add compression to blockchain db
* add blocks db migration
* fix the migrations
* remove state compression
* add a separate snapshot swapper
* ability to use different swappers and traversal
* update tests to new interface
* clean up code ordering
* update usage
* fix compilation
* remove unnecessary changes
* move methods to functions to reduce interface
* move test to module
* update common rlps to blocks db
* move tests to tests modules
* remove redundant &
2016-07-27 17:11:41 +02:00
|
|
|
|
2016-01-14 16:46:32 +01:00
|
|
|
#[test]
|
|
|
|
fn storage_at() {
|
2019-02-20 19:09:34 +01:00
|
|
|
let mut db = new_memory_db();
|
2019-07-04 15:20:44 +02:00
|
|
|
let mut db = AccountDBMut::from_hash(&mut db, keccak(&Address::zero()));
|
2016-01-14 16:46:32 +01:00
|
|
|
let rlp = {
|
2018-09-07 12:51:08 +02:00
|
|
|
let mut a = Account::new_contract(69.into(), 0.into(), KECCAK_NULL_RLP);
|
2019-06-03 15:36:21 +02:00
|
|
|
a.set_storage(H256::zero(), H256::from_low_u64_be(0x1234));
|
2017-02-26 13:10:50 +01:00
|
|
|
a.commit_storage(&Default::default(), &mut db).unwrap();
|
2016-01-14 16:46:32 +01:00
|
|
|
a.init_code(vec![]);
|
|
|
|
a.commit_code(&mut db);
|
|
|
|
a.rlp()
|
|
|
|
};
|
|
|
|
|
2018-05-08 11:22:12 +02:00
|
|
|
let a = Account::from_rlp(&rlp).expect("decoding db value failed");
|
2019-06-03 15:36:21 +02:00
|
|
|
assert_eq!(a.storage_root().unwrap(), H256::from_str("c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2").unwrap());
|
|
|
|
assert_eq!(a.storage_at(&db.immutable(), &H256::zero()).unwrap(), H256::from_low_u64_be(0x1234));
|
|
|
|
assert_eq!(a.storage_at(&db.immutable(), &H256::from_low_u64_be(0x01)).unwrap(), H256::zero());
|
2016-01-14 16:46:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn note_code() {
|
2019-02-20 19:09:34 +01:00
|
|
|
let mut db = new_memory_db();
|
2019-07-04 15:20:44 +02:00
|
|
|
let mut db = AccountDBMut::from_hash(&mut db, keccak(&Address::zero()));
|
2016-01-14 16:46:32 +01:00
|
|
|
|
|
|
|
let rlp = {
|
2018-09-07 12:51:08 +02:00
|
|
|
let mut a = Account::new_contract(69.into(), 0.into(), KECCAK_NULL_RLP);
|
2016-01-14 16:46:32 +01:00
|
|
|
a.init_code(vec![0x55, 0x44, 0xffu8]);
|
|
|
|
a.commit_code(&mut db);
|
|
|
|
a.rlp()
|
|
|
|
};
|
|
|
|
|
2018-05-08 11:22:12 +02:00
|
|
|
let mut a = Account::from_rlp(&rlp).expect("decoding db value failed");
|
2016-10-28 16:04:44 +02:00
|
|
|
assert!(a.cache_code(&db.immutable()).is_some());
|
2016-01-14 16:46:32 +01:00
|
|
|
|
2018-05-08 11:22:12 +02:00
|
|
|
let mut a = Account::from_rlp(&rlp).expect("decoding db value failed");
|
2016-01-14 16:46:32 +01:00
|
|
|
assert_eq!(a.note_code(vec![0x55, 0x44, 0xffu8]), Ok(()));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn commit_storage() {
|
2018-09-07 12:51:08 +02:00
|
|
|
let mut a = Account::new_contract(69.into(), 0.into(), KECCAK_NULL_RLP);
|
2019-02-20 19:09:34 +01:00
|
|
|
let mut db = new_memory_db();
|
2019-07-04 15:20:44 +02:00
|
|
|
let mut db = AccountDBMut::from_hash(&mut db, keccak(&Address::zero()));
|
2019-06-03 15:36:21 +02:00
|
|
|
a.set_storage(H256::from_low_u64_be(0), H256::from_low_u64_be(0x1234));
|
2016-01-14 16:46:32 +01:00
|
|
|
assert_eq!(a.storage_root(), None);
|
2017-02-26 13:10:50 +01:00
|
|
|
a.commit_storage(&Default::default(), &mut db).unwrap();
|
2019-06-03 15:36:21 +02:00
|
|
|
assert_eq!(a.storage_root().unwrap(), H256::from_str("c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2").unwrap());
|
2016-01-14 16:46:32 +01:00
|
|
|
}
|
2015-12-16 12:46:25 +01:00
|
|
|
|
2016-01-14 23:13:05 +01:00
|
|
|
#[test]
|
|
|
|
fn commit_remove_commit_storage() {
|
2018-09-07 12:51:08 +02:00
|
|
|
let mut a = Account::new_contract(69.into(), 0.into(), KECCAK_NULL_RLP);
|
2019-02-20 19:09:34 +01:00
|
|
|
let mut db = new_memory_db();
|
2019-07-04 15:20:44 +02:00
|
|
|
let mut db = AccountDBMut::from_hash(&mut db, keccak(&Address::zero()));
|
2019-06-03 15:36:21 +02:00
|
|
|
a.set_storage(H256::from_low_u64_be(0), H256::from_low_u64_be(0x1234));
|
2017-02-26 13:10:50 +01:00
|
|
|
a.commit_storage(&Default::default(), &mut db).unwrap();
|
2019-06-03 15:36:21 +02:00
|
|
|
a.set_storage(H256::from_low_u64_be(1), H256::from_low_u64_be(0x1234));
|
2017-02-26 13:10:50 +01:00
|
|
|
a.commit_storage(&Default::default(), &mut db).unwrap();
|
2019-06-03 15:36:21 +02:00
|
|
|
a.set_storage(H256::from_low_u64_be(1), H256::from_low_u64_be(0));
|
2017-02-26 13:10:50 +01:00
|
|
|
a.commit_storage(&Default::default(), &mut db).unwrap();
|
2019-06-03 15:36:21 +02:00
|
|
|
assert_eq!(a.storage_root().unwrap(), H256::from_str("c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2").unwrap());
|
2016-01-14 23:13:05 +01:00
|
|
|
}
|
|
|
|
|
2016-01-14 16:46:32 +01:00
|
|
|
#[test]
|
|
|
|
fn commit_code() {
|
2018-09-07 12:51:08 +02:00
|
|
|
let mut a = Account::new_contract(69.into(), 0.into(), KECCAK_NULL_RLP);
|
2019-02-20 19:09:34 +01:00
|
|
|
let mut db = new_memory_db();
|
2019-07-04 15:20:44 +02:00
|
|
|
let mut db = AccountDBMut::from_hash(&mut db, keccak(&Address::zero()));
|
2016-01-09 12:30:41 +01:00
|
|
|
a.init_code(vec![0x55, 0x44, 0xffu8]);
|
2016-10-02 18:45:36 +02:00
|
|
|
assert_eq!(a.code_filth, Filth::Dirty);
|
2016-09-27 18:02:11 +02:00
|
|
|
assert_eq!(a.code_size(), Some(3));
|
2015-12-16 12:46:25 +01:00
|
|
|
a.commit_code(&mut db);
|
2019-06-03 15:36:21 +02:00
|
|
|
assert_eq!(a.code_hash(), H256::from_str("af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb").unwrap());
|
2016-01-14 16:46:32 +01:00
|
|
|
}
|
2015-12-15 13:17:59 +01:00
|
|
|
|
2016-06-29 16:29:04 +02:00
|
|
|
#[test]
|
|
|
|
fn reset_code() {
|
2018-09-07 12:51:08 +02:00
|
|
|
let mut a = Account::new_contract(69.into(), 0.into(), KECCAK_NULL_RLP);
|
2019-02-20 19:09:34 +01:00
|
|
|
let mut db = new_memory_db();
|
2019-07-04 15:20:44 +02:00
|
|
|
let mut db = AccountDBMut::from_hash(&mut db, keccak(&Address::zero()));
|
2016-06-29 16:29:04 +02:00
|
|
|
a.init_code(vec![0x55, 0x44, 0xffu8]);
|
2016-10-02 18:45:36 +02:00
|
|
|
assert_eq!(a.code_filth, Filth::Dirty);
|
2016-06-29 16:29:04 +02:00
|
|
|
a.commit_code(&mut db);
|
2016-10-02 18:45:36 +02:00
|
|
|
assert_eq!(a.code_filth, Filth::Clean);
|
2019-06-03 15:36:21 +02:00
|
|
|
assert_eq!(a.code_hash(), H256::from_str("af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb").unwrap());
|
2016-06-29 16:29:04 +02:00
|
|
|
a.reset_code(vec![0x55]);
|
2016-10-02 18:45:36 +02:00
|
|
|
assert_eq!(a.code_filth, Filth::Dirty);
|
2016-06-29 16:29:04 +02:00
|
|
|
a.commit_code(&mut db);
|
2019-06-03 15:36:21 +02:00
|
|
|
assert_eq!(a.code_hash(), H256::from_str("37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be").unwrap());
|
2016-06-29 16:29:04 +02:00
|
|
|
}
|
|
|
|
|
2016-01-14 16:46:32 +01:00
|
|
|
#[test]
|
|
|
|
fn rlpio() {
|
2018-02-09 09:32:06 +01:00
|
|
|
let a = Account::new(69u8.into(), 0u8.into(), HashMap::new(), Bytes::new());
|
2018-05-08 11:22:12 +02:00
|
|
|
let b = Account::from_rlp(&a.rlp()).unwrap();
|
2016-01-14 16:46:32 +01:00
|
|
|
assert_eq!(a.balance(), b.balance());
|
|
|
|
assert_eq!(a.nonce(), b.nonce());
|
|
|
|
assert_eq!(a.code_hash(), b.code_hash());
|
|
|
|
assert_eq!(a.storage_root(), b.storage_root());
|
|
|
|
}
|
2015-12-15 13:09:50 +01:00
|
|
|
|
2016-01-14 16:46:32 +01:00
|
|
|
#[test]
|
|
|
|
fn new_account() {
|
2018-02-09 09:32:06 +01:00
|
|
|
let a = Account::new(69u8.into(), 0u8.into(), HashMap::new(), Bytes::new());
|
2016-01-14 16:46:32 +01:00
|
|
|
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
|
2018-02-09 09:32:06 +01:00
|
|
|
assert_eq!(*a.balance(), 69u8.into());
|
|
|
|
assert_eq!(*a.nonce(), 0u8.into());
|
2017-08-30 19:18:28 +02:00
|
|
|
assert_eq!(a.code_hash(), KECCAK_EMPTY);
|
2018-09-07 12:51:08 +02:00
|
|
|
assert_eq!(a.storage_root().unwrap(), KECCAK_NULL_RLP);
|
2016-01-14 16:46:32 +01:00
|
|
|
}
|
2016-01-14 22:41:39 +01:00
|
|
|
}
|