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
2017-02-21 12:35:21 +01:00
//! A mutable state representation suitable to execute transactions.
//! Generic over a `Backend`. Deals with `Account`s.
//! Unconfirmed sub-states are managed with `checkpoint`s which may be canonicalized
//! or rolled back.
2016-08-03 18:35:48 +02:00
use std ::cell ::{ RefCell , RefMut } ;
2016-10-06 01:53:23 +02:00
use std ::collections ::hash_map ::Entry ;
2018-05-02 16:47:53 +02:00
use std ::collections ::{ HashMap , BTreeMap , BTreeSet , HashSet } ;
2017-07-29 17:12:07 +02:00
use std ::fmt ;
2017-07-29 21:56:42 +02:00
use std ::sync ::Arc ;
2017-08-30 19:18:28 +02:00
use hash ::{ KECCAK_NULL_RLP , KECCAK_EMPTY } ;
2016-11-15 14:53:30 +01:00
2019-01-04 14:05:46 +01:00
use types ::receipt ::{ Receipt , TransactionOutcome } ;
2017-09-26 14:19:08 +02:00
use machine ::EthereumMachine as Machine ;
2017-08-01 12:37:57 +02:00
use vm ::EnvInfo ;
2016-10-24 18:35:25 +02:00
use error ::Error ;
2016-04-06 13:05:58 +02:00
use executive ::{ Executive , TransactOptions } ;
2016-08-24 16:53:36 +02:00
use factory ::Factories ;
2017-08-28 14:25:16 +02:00
use trace ::{ self , FlatTrace , VMTrace } ;
2016-01-14 16:46:32 +01:00
use pod_account ::* ;
2016-05-31 21:03:44 +02:00
use pod_state ::{ self , PodState } ;
2017-03-23 13:17:05 +01:00
use types ::basic_account ::BasicAccount ;
2017-07-12 13:09:17 +02:00
use executed ::{ Executed , ExecutionError } ;
2016-05-31 21:03:44 +02:00
use types ::state_diff ::StateDiff ;
2019-01-04 14:05:46 +01:00
use types ::transaction ::SignedTransaction ;
2016-09-27 18:02:11 +02:00
use state_db ::StateDB ;
2018-02-19 12:27:42 +01:00
use factory ::VmFactory ;
2015-12-19 22:15:22 +01:00
2018-01-10 13:35:18 +01:00
use ethereum_types ::{ H256 , U256 , Address } ;
2019-02-20 19:09:34 +01:00
use hash_db ::{ HashDB , AsHashDB } ;
2018-07-02 18:50:05 +02:00
use keccak_hasher ::KeccakHasher ;
2018-01-10 13:35:18 +01:00
use kvdb ::DBValue ;
2017-09-06 20:47:45 +02:00
use bytes ::Bytes ;
2018-07-02 18:50:05 +02:00
use trie ::{ Trie , TrieError , Recorder } ;
use ethtrie ::{ TrieDB , Result as TrieResult } ;
2016-12-07 10:50:18 +01:00
2016-08-18 15:24:27 +02:00
mod account ;
mod substate ;
2017-02-21 11:13:02 +01:00
pub mod backend ;
2016-08-18 15:24:27 +02:00
pub use self ::account ::Account ;
2017-02-21 12:35:21 +01:00
pub use self ::backend ::Backend ;
2016-08-18 15:24:27 +02:00
pub use self ::substate ::Substate ;
2016-03-19 12:54:34 +01:00
/// Used to return information about an `State::apply` operation.
2017-10-20 15:40:25 +02:00
pub struct ApplyOutcome < T , V > {
2016-03-19 12:54:34 +01:00
/// The receipt for the applied transaction.
pub receipt : Receipt ,
2017-08-28 14:25:16 +02:00
/// The output of the applied transaction.
pub output : Bytes ,
/// The trace for the applied transaction, empty if tracing was not produced.
2017-10-20 15:40:25 +02:00
pub trace : Vec < T > ,
2017-08-28 14:25:16 +02:00
/// The VM trace for the applied transaction, None if tracing was not produced.
2017-10-20 15:40:25 +02:00
pub vm_trace : Option < V >
2016-03-19 12:54:34 +01:00
}
2016-02-03 13:20:32 +01:00
/// Result type for the execution ("application") of a transaction.
2017-10-20 15:40:25 +02:00
pub type ApplyResult < T , V > = Result < ApplyOutcome < T , V > , Error > ;
2015-12-13 21:36:17 +01:00
2017-03-08 14:39:44 +01:00
/// Return type of proof validity check.
#[ derive(Debug, Clone) ]
pub enum ProvedExecution {
/// Proof wasn't enough to complete execution.
BadProof ,
/// The transaction failed, but not due to a bad proof.
Failed ( ExecutionError ) ,
2019-03-06 15:30:35 +01:00
/// The transaction successfully completed with the given proof.
Complete ( Box < Executed > ) ,
2017-03-08 14:39:44 +01:00
}
2016-10-06 01:53:23 +02:00
#[ derive(Eq, PartialEq, Clone, Copy, Debug) ]
/// Account modification state. Used to check if the account was
/// Modified in between commits and overall.
enum AccountState {
2016-10-07 12:10:12 +02:00
/// Account was loaded from disk and never modified in this state object.
CleanFresh ,
/// Account was loaded from the global cache and never modified.
CleanCached ,
2016-10-06 01:53:23 +02:00
/// Account has been modified and is not committed to the trie yet.
2016-10-07 12:10:12 +02:00
/// This is set if any of the account data is changed, including
2016-10-06 01:53:23 +02:00
/// storage and code.
Dirty ,
/// Account was modified and committed to the trie.
2016-10-07 12:10:12 +02:00
Committed ,
2016-10-06 01:53:23 +02:00
}
2016-09-27 18:02:11 +02:00
#[ derive(Debug) ]
2016-10-06 01:53:23 +02:00
/// In-memory copy of the account data. Holds the optional account
/// and the modification status.
/// Account entry can contain existing (`Some`) or non-existing
/// account (`None`)
struct AccountEntry {
2017-06-28 09:10:57 +02:00
/// Account entry. `None` if account known to be non-existant.
2016-10-06 01:53:23 +02:00
account : Option < Account > ,
2017-06-28 09:10:57 +02:00
/// Unmodified account balance.
old_balance : Option < U256 > ,
/// Entry state.
2016-10-06 01:53:23 +02:00
state : AccountState ,
2016-09-27 18:02:11 +02:00
}
2016-10-06 01:53:23 +02:00
// Account cache item. Contains account data and
// modification state
2016-09-27 18:02:11 +02:00
impl AccountEntry {
fn is_dirty ( & self ) -> bool {
2016-10-06 01:53:23 +02:00
self . state = = AccountState ::Dirty
2016-09-27 18:02:11 +02:00
}
2017-06-28 09:10:57 +02:00
fn exists_and_is_null ( & self ) -> bool {
self . account . as_ref ( ) . map_or ( false , | a | a . is_null ( ) )
}
2016-10-06 01:53:23 +02:00
/// Clone dirty data into new `AccountEntry`. This includes
/// basic account data and modified storage keys.
2016-09-27 18:02:11 +02:00
/// Returns None if clean.
2016-10-06 01:53:23 +02:00
fn clone_if_dirty ( & self ) -> Option < AccountEntry > {
match self . is_dirty ( ) {
true = > Some ( self . clone_dirty ( ) ) ,
false = > None ,
}
}
/// Clone dirty data into new `AccountEntry`. This includes
/// basic account data and modified storage keys.
fn clone_dirty ( & self ) -> AccountEntry {
AccountEntry {
2017-06-28 09:10:57 +02:00
old_balance : self . old_balance ,
2016-10-06 01:53:23 +02:00
account : self . account . as_ref ( ) . map ( Account ::clone_dirty ) ,
state : self . state ,
2016-09-27 18:02:11 +02:00
}
}
2016-10-06 15:54:05 +02:00
// Create a new account entry and mark it as dirty.
2016-10-06 01:53:23 +02:00
fn new_dirty ( account : Option < Account > ) -> AccountEntry {
AccountEntry {
2017-06-28 09:10:57 +02:00
old_balance : account . as_ref ( ) . map ( | a | a . balance ( ) . clone ( ) ) ,
2016-10-06 01:53:23 +02:00
account : account ,
state : AccountState ::Dirty ,
}
}
2016-10-06 15:54:05 +02:00
// Create a new account entry and mark it as clean.
2016-10-06 01:53:23 +02:00
fn new_clean ( account : Option < Account > ) -> AccountEntry {
AccountEntry {
2017-06-28 09:10:57 +02:00
old_balance : account . as_ref ( ) . map ( | a | a . balance ( ) . clone ( ) ) ,
2016-10-06 01:53:23 +02:00
account : account ,
2016-10-07 12:10:12 +02:00
state : AccountState ::CleanFresh ,
}
}
// Create a new account entry and mark it as clean and cached.
fn new_clean_cached ( account : Option < Account > ) -> AccountEntry {
AccountEntry {
2017-06-28 09:10:57 +02:00
old_balance : account . as_ref ( ) . map ( | a | a . balance ( ) . clone ( ) ) ,
2016-10-07 12:10:12 +02:00
account : account ,
state : AccountState ::CleanCached ,
2016-09-27 18:02:11 +02:00
}
}
2016-10-06 15:54:05 +02:00
// Replace data with another entry but preserve storage cache.
fn overwrite_with ( & mut self , other : AccountEntry ) {
self . state = other . state ;
match other . account {
2016-10-27 08:28:12 +02:00
Some ( acc ) = > {
if let Some ( ref mut ours ) = self . account {
2016-10-06 15:54:05 +02:00
ours . overwrite_with ( acc ) ;
2018-09-07 12:51:08 +02:00
} else {
self . account = Some ( acc ) ;
2016-10-27 08:28:12 +02:00
}
2016-10-06 15:54:05 +02:00
} ,
None = > self . account = None ,
}
}
2016-09-27 18:02:11 +02:00
}
2017-03-08 14:39:44 +01:00
/// Check the given proof of execution.
/// `Err(ExecutionError::Internal)` indicates failure, everything else indicates
/// a successful proof (as the transaction itself may be poorly chosen).
pub fn check_proof (
2018-01-10 13:35:18 +01:00
proof : & [ DBValue ] ,
2017-03-08 14:39:44 +01:00
root : H256 ,
transaction : & SignedTransaction ,
2017-09-26 14:19:08 +02:00
machine : & Machine ,
2017-03-08 14:39:44 +01:00
env_info : & EnvInfo ,
) -> ProvedExecution {
let backend = self ::backend ::ProofCheck ::new ( proof ) ;
let mut factories = Factories ::default ( ) ;
factories . accountdb = ::account_db ::Factory ::Plain ;
let res = State ::from_existing (
backend ,
root ,
2017-09-26 14:19:08 +02:00
machine . account_start_nonce ( env_info . number ) ,
2017-03-08 14:39:44 +01:00
factories
) ;
let mut state = match res {
Ok ( state ) = > state ,
Err ( _ ) = > return ProvedExecution ::BadProof ,
} ;
2017-09-05 13:22:19 +02:00
let options = TransactOptions ::with_no_tracing ( ) . save_output_from_contract ( ) ;
2017-09-26 14:19:08 +02:00
match state . execute ( env_info , machine , transaction , options , true ) {
2019-03-06 15:30:35 +01:00
Ok ( executed ) = > ProvedExecution ::Complete ( Box ::new ( executed ) ) ,
2017-03-08 14:39:44 +01:00
Err ( ExecutionError ::Internal ( _ ) ) = > ProvedExecution ::BadProof ,
Err ( e ) = > ProvedExecution ::Failed ( e ) ,
}
}
2018-10-08 21:30:46 +02:00
/// Prove a `virtual` transaction on the given state.
2017-08-15 00:12:40 +02:00
/// Returns `None` when the transacion could not be proved,
/// and a proof otherwise.
2018-10-09 22:07:25 +02:00
pub fn prove_transaction_virtual < H : AsHashDB < KeccakHasher , DBValue > + Send + Sync > (
2017-08-15 00:12:40 +02:00
db : H ,
root : H256 ,
transaction : & SignedTransaction ,
2017-09-26 14:19:08 +02:00
machine : & Machine ,
2017-08-15 00:12:40 +02:00
env_info : & EnvInfo ,
factories : Factories ,
) -> Option < ( Bytes , Vec < DBValue > ) > {
use self ::backend ::Proving ;
let backend = Proving ::new ( db ) ;
let res = State ::from_existing (
backend ,
root ,
2017-09-26 14:19:08 +02:00
machine . account_start_nonce ( env_info . number ) ,
2017-08-15 00:12:40 +02:00
factories ,
) ;
let mut state = match res {
Ok ( state ) = > state ,
Err ( _ ) = > return None ,
} ;
2017-09-05 13:22:19 +02:00
let options = TransactOptions ::with_no_tracing ( ) . dont_check_nonce ( ) . save_output_from_contract ( ) ;
2018-10-08 21:30:46 +02:00
match state . execute ( env_info , machine , transaction , options , true ) {
2017-08-15 00:12:40 +02:00
Err ( ExecutionError ::Internal ( _ ) ) = > None ,
Err ( e ) = > {
trace! ( target : " state " , " Proved call failed: {} " , e ) ;
Some ( ( Vec ::new ( ) , state . drop ( ) . 1. extract_proof ( ) ) )
}
Ok ( res ) = > Some ( ( res . output , state . drop ( ) . 1. extract_proof ( ) ) ) ,
}
}
2015-12-13 23:12:22 +01:00
/// Representation of the entire state of all accounts in the system.
2016-09-27 18:02:11 +02:00
///
/// `State` can work together with `StateDB` to share account cache.
///
/// Local cache contains changes made locally and changes accumulated
/// locally from previous commits. Global cache reflects the database
/// state and never contains any changes.
///
2016-10-06 01:53:23 +02:00
/// Cache items contains account data, or the flag that account does not exist
/// and modification state (see `AccountState`)
///
2016-09-27 18:02:11 +02:00
/// Account data can be in the following cache states:
/// * In global but not local - something that was queried from the database,
/// but never modified
/// * In local but not global - something that was just added (e.g. new account)
/// * In both with the same value - something that was changed to a new value,
/// but changed back to a previous block in the same block (same State instance)
/// * In both with different values - something that was overwritten with a
/// new value.
///
/// All read-only state queries check local cache/modifications first,
/// then global state cache. If data is not found in any of the caches
/// it is loaded from the DB to the local cache.
///
2016-10-06 01:53:23 +02:00
/// **** IMPORTANT *************************************************************
/// All the modifications to the account data must set the `Dirty` state in the
/// `AccountEntry`. This is done in `require` and `require_or_from`. So just
/// use that.
/// ****************************************************************************
///
2016-10-07 13:34:32 +02:00
/// Upon destruction all the local cache data propagated into the global cache.
/// Propagated items might be rejected if current state is non-canonical.
2016-10-06 15:54:05 +02:00
///
2016-10-22 15:22:16 +02:00
/// State checkpointing.
2016-10-06 15:54:05 +02:00
///
2016-10-22 15:22:16 +02:00
/// A new checkpoint can be created with `checkpoint()`. checkpoints can be
2016-10-06 15:54:05 +02:00
/// created in a hierarchy.
2016-10-22 15:22:16 +02:00
/// When a checkpoint is active all changes are applied directly into
/// `cache` and the original value is copied into an active checkpoint.
/// Reverting a checkpoint with `revert_to_checkpoint` involves copying
/// original values from the latest checkpoint back into `cache`. The code
2016-10-06 15:54:05 +02:00
/// takes care not to overwrite cached storage while doing that.
2017-05-07 14:33:52 +02:00
/// checkpoint can be discarded with `discard_checkpoint`. All of the orignal
2016-10-22 15:22:16 +02:00
/// backed-up values are moved into a parent checkpoint (if any).
2016-10-06 15:54:05 +02:00
///
2018-07-09 13:55:27 +02:00
pub struct State < B > {
2017-02-21 12:35:21 +01:00
db : B ,
2015-12-13 21:36:17 +01:00
root : H256 ,
2016-09-27 18:02:11 +02:00
cache : RefCell < HashMap < Address , AccountEntry > > ,
2016-10-06 15:54:05 +02:00
// The original account is preserved in
2016-10-22 15:22:16 +02:00
checkpoints : RefCell < Vec < HashMap < Address , Option < AccountEntry > > > > ,
2015-12-19 22:15:22 +01:00
account_start_nonce : U256 ,
2016-08-24 16:53:36 +02:00
factories : Factories ,
2015-12-13 21:36:17 +01:00
}
2016-09-27 18:02:11 +02:00
#[ derive(Copy, Clone) ]
enum RequireCache {
None ,
CodeSize ,
Code ,
}
2017-02-21 12:35:21 +01:00
/// Mode of dealing with null accounts.
2016-11-03 22:22:25 +01:00
#[ derive(PartialEq) ]
pub enum CleanupMode < ' a > {
2017-02-21 12:35:21 +01:00
/// Create accounts which would be null.
2016-11-03 22:22:25 +01:00
ForceCreate ,
2017-02-21 12:35:21 +01:00
/// Don't delete null accounts upon touching, but also don't create them.
2016-11-03 22:22:25 +01:00
NoEmpty ,
2017-06-28 09:10:57 +02:00
/// Mark all touched accounts.
TrackTouched ( & ' a mut HashSet < Address > ) ,
2016-11-03 22:22:25 +01:00
}
2018-03-03 18:42:13 +01:00
/// Provides subset of `State` methods to query state information
pub trait StateInfo {
/// Get the nonce of account `a`.
2018-07-02 18:50:05 +02:00
fn nonce ( & self , a : & Address ) -> TrieResult < U256 > ;
2018-03-03 18:42:13 +01:00
/// Get the balance of account `a`.
2018-07-02 18:50:05 +02:00
fn balance ( & self , a : & Address ) -> TrieResult < U256 > ;
2018-03-03 18:42:13 +01:00
/// Mutate storage of account `address` so that it is `value` for `key`.
2018-07-02 18:50:05 +02:00
fn storage_at ( & self , address : & Address , key : & H256 ) -> TrieResult < H256 > ;
2018-03-03 18:42:13 +01:00
/// Get accounts' code.
2018-07-02 18:50:05 +02:00
fn code ( & self , a : & Address ) -> TrieResult < Option < Arc < Bytes > > > ;
2018-03-03 18:42:13 +01:00
}
impl < B : Backend > StateInfo for State < B > {
2018-07-02 18:50:05 +02:00
fn nonce ( & self , a : & Address ) -> TrieResult < U256 > { State ::nonce ( self , a ) }
fn balance ( & self , a : & Address ) -> TrieResult < U256 > { State ::balance ( self , a ) }
fn storage_at ( & self , address : & Address , key : & H256 ) -> TrieResult < H256 > { State ::storage_at ( self , address , key ) }
fn code ( & self , address : & Address ) -> TrieResult < Option < Arc < Bytes > > > { State ::code ( self , address ) }
2018-03-03 18:42:13 +01:00
}
2016-06-07 20:44:09 +02:00
const SEC_TRIE_DB_UNWRAP_STR : & 'static str = " A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
Therefore creating a SecTrieDB with this state ' s root will not fail . " ;
2017-02-21 12:35:21 +01:00
impl < B : Backend > State < B > {
2015-12-13 21:36:17 +01:00
/// Creates new state with empty state root
2017-08-28 14:25:16 +02:00
/// Used for tests.
2017-02-21 12:35:21 +01:00
pub fn new ( mut db : B , account_start_nonce : U256 , factories : Factories ) -> State < B > {
2019-06-03 15:36:21 +02:00
let mut root = H256 ::zero ( ) ;
2015-12-13 21:36:17 +01:00
{
2018-03-20 15:46:03 +01:00
// init trie and reset root to null
2019-02-20 19:09:34 +01:00
let _ = factories . trie . create ( db . as_hash_db_mut ( ) , & mut root ) ;
2015-12-13 21:36:17 +01:00
}
State {
db : db ,
root : root ,
2015-12-19 22:15:22 +01:00
cache : RefCell ::new ( HashMap ::new ( ) ) ,
2016-10-22 15:22:16 +02:00
checkpoints : RefCell ::new ( Vec ::new ( ) ) ,
2015-12-19 22:15:22 +01:00
account_start_nonce : account_start_nonce ,
2016-08-24 16:53:36 +02:00
factories : factories ,
2015-12-13 21:36:17 +01:00
}
}
/// Creates new state with existing state root
2018-07-02 18:50:05 +02:00
pub fn from_existing ( db : B , root : H256 , account_start_nonce : U256 , factories : Factories ) -> TrieResult < State < B > > {
2019-02-20 19:09:34 +01:00
if ! db . as_hash_db ( ) . contains ( & root ) {
2018-07-02 18:50:05 +02:00
return Err ( Box ::new ( TrieError ::InvalidStateRoot ( root ) ) ) ;
2015-12-13 21:36:17 +01:00
}
2016-07-01 20:29:56 +02:00
let state = State {
db : db ,
root : root ,
cache : RefCell ::new ( HashMap ::new ( ) ) ,
2016-10-22 15:22:16 +02:00
checkpoints : RefCell ::new ( Vec ::new ( ) ) ,
2016-07-01 20:29:56 +02:00
account_start_nonce : account_start_nonce ,
2016-08-24 16:53:36 +02:00
factories : factories
2016-07-01 20:29:56 +02:00
} ;
Ok ( state )
2015-12-13 21:36:17 +01:00
}
2017-05-30 11:52:33 +02:00
/// Get a VM factory that can execute on this state.
2018-02-19 12:27:42 +01:00
pub fn vm_factory ( & self ) -> VmFactory {
2017-05-30 11:52:33 +02:00
self . factories . vm . clone ( )
}
2018-09-07 12:51:08 +02:00
/// Create a recoverable checkpoint of this state. Return the checkpoint index.
pub fn checkpoint ( & mut self ) -> usize {
let checkpoints = self . checkpoints . get_mut ( ) ;
let index = checkpoints . len ( ) ;
checkpoints . push ( HashMap ::new ( ) ) ;
index
2016-02-03 19:34:51 +01:00
}
2016-10-22 15:22:16 +02:00
/// Merge last checkpoint with previous.
pub fn discard_checkpoint ( & mut self ) {
// merge with previous checkpoint
let last = self . checkpoints . get_mut ( ) . pop ( ) ;
if let Some ( mut checkpoint ) = last {
if let Some ( ref mut prev ) = self . checkpoints . get_mut ( ) . last_mut ( ) {
2016-10-06 15:54:05 +02:00
if prev . is_empty ( ) {
2016-10-22 15:22:16 +02:00
* * prev = checkpoint ;
2016-10-06 15:54:05 +02:00
} else {
2016-10-22 15:22:16 +02:00
for ( k , v ) in checkpoint . drain ( ) {
2018-09-11 10:28:31 +02:00
prev . entry ( k ) . or_insert ( v ) ;
2016-10-06 15:54:05 +02:00
}
2016-02-03 19:34:51 +01:00
}
}
}
}
2016-10-22 15:22:16 +02:00
/// Revert to the last checkpoint and discard it.
pub fn revert_to_checkpoint ( & mut self ) {
if let Some ( mut checkpoint ) = self . checkpoints . get_mut ( ) . pop ( ) {
for ( k , v ) in checkpoint . drain ( ) {
2016-02-03 19:34:51 +01:00
match v {
Some ( v ) = > {
2016-10-13 23:28:56 +02:00
match self . cache . get_mut ( ) . entry ( k ) {
2016-10-06 15:54:05 +02:00
Entry ::Occupied ( mut e ) = > {
2016-10-22 15:22:16 +02:00
// Merge checkpointed changes back into the main account
2016-10-06 15:54:05 +02:00
// storage preserving the cache.
e . get_mut ( ) . overwrite_with ( v ) ;
} ,
Entry ::Vacant ( e ) = > {
e . insert ( v ) ;
}
}
2016-02-03 19:34:51 +01:00
} ,
None = > {
2016-10-27 08:28:12 +02:00
if let Entry ::Occupied ( e ) = self . cache . get_mut ( ) . entry ( k ) {
if e . get ( ) . is_dirty ( ) {
e . remove ( ) ;
}
2016-09-27 18:02:11 +02:00
}
2016-02-03 19:34:51 +01:00
}
}
}
}
}
2016-09-27 18:02:11 +02:00
fn insert_cache ( & self , address : & Address , account : AccountEntry ) {
2016-10-06 01:53:23 +02:00
// Dirty account which is not in the cache means this is a new account.
2016-10-22 15:22:16 +02:00
// It goes directly into the checkpoint as there's nothing to rever to.
2016-10-06 01:53:23 +02:00
//
// In all other cases account is read as clean first, and after that made
2016-10-22 15:22:16 +02:00
// dirty in and added to the checkpoint with `note_cache`.
2017-09-19 11:34:13 +02:00
let is_dirty = account . is_dirty ( ) ;
let old_value = self . cache . borrow_mut ( ) . insert ( * address , account ) ;
if is_dirty {
2016-10-22 15:22:16 +02:00
if let Some ( ref mut checkpoint ) = self . checkpoints . borrow_mut ( ) . last_mut ( ) {
2017-09-19 11:34:13 +02:00
checkpoint . entry ( * address ) . or_insert ( old_value ) ;
2016-02-03 19:34:51 +01:00
}
}
}
fn note_cache ( & self , address : & Address ) {
2016-10-22 15:22:16 +02:00
if let Some ( ref mut checkpoint ) = self . checkpoints . borrow_mut ( ) . last_mut ( ) {
2017-09-19 11:34:13 +02:00
checkpoint . entry ( * address )
. or_insert_with ( | | self . cache . borrow ( ) . get ( address ) . map ( AccountEntry ::clone_dirty ) ) ;
2016-02-03 19:34:51 +01:00
}
}
2015-12-16 20:02:28 +01:00
/// Destroy the current object and return root and database.
2017-02-21 12:35:21 +01:00
pub fn drop ( mut self ) -> ( H256 , B ) {
2016-10-07 13:34:32 +02:00
self . propagate_to_global_cache ( ) ;
2015-12-19 19:03:42 +01:00
( self . root , self . db )
2015-12-16 20:02:28 +01:00
}
2018-04-09 16:14:33 +02:00
/// Destroy the current object and return single account data.
2018-07-02 18:50:05 +02:00
pub fn into_account ( self , account : & Address ) -> TrieResult < ( Option < Arc < Bytes > > , HashMap < H256 , H256 > ) > {
2018-04-09 16:14:33 +02:00
// TODO: deconstruct without cloning.
let account = self . require ( account , true ) ? ;
Ok ( ( account . code ( ) . clone ( ) , account . storage_changes ( ) . clone ( ) ) )
}
2015-12-19 22:15:22 +01:00
/// Return reference to root
pub fn root ( & self ) -> & H256 {
& self . root
}
2016-01-09 14:19:35 +01:00
/// Create a new contract at address `contract`. If there is already an account at the address
/// it will have its code reset, ready for `init_code()`.
2018-09-07 12:51:08 +02:00
pub fn new_contract ( & mut self , contract : & Address , balance : U256 , nonce_offset : U256 ) -> TrieResult < ( ) > {
let original_storage_root = self . original_storage_root ( contract ) ? ;
2019-02-11 23:20:51 +01:00
let ( nonce , overflow ) = self . account_start_nonce . overflowing_add ( nonce_offset ) ;
if overflow {
2019-06-03 15:36:21 +02:00
return Err ( Box ::new ( TrieError ::DecoderError ( H256 ::from ( * contract ) ,
2019-02-11 23:20:51 +01:00
rlp ::DecoderError ::Custom ( " Nonce overflow " . into ( ) ) ) ) ) ;
}
self . insert_cache ( contract , AccountEntry ::new_dirty ( Some ( Account ::new_contract ( balance , nonce , original_storage_root ) ) ) ) ;
2018-09-07 12:51:08 +02:00
Ok ( ( ) )
2016-01-09 14:19:35 +01:00
}
2016-01-09 22:28:31 +01:00
/// Remove an existing account.
pub fn kill_account ( & mut self , account : & Address ) {
2016-10-06 01:53:23 +02:00
self . insert_cache ( account , AccountEntry ::new_dirty ( None ) ) ;
2016-01-09 22:28:31 +01:00
}
2016-01-12 12:34:14 +01:00
/// Determine whether an account exists.
2018-07-02 18:50:05 +02:00
pub fn exists ( & self , a : & Address ) -> TrieResult < bool > {
2016-10-20 16:49:27 +02:00
// Bloom filter does not contain empty accounts, so it is important here to
2016-11-03 22:22:25 +01:00
// check if account exists in the database directly before EIP-161 is in effect.
2016-10-20 16:49:27 +02:00
self . ensure_cached ( a , RequireCache ::None , false , | a | a . is_some ( ) )
2016-01-12 12:34:14 +01:00
}
2016-11-03 22:22:25 +01:00
/// Determine whether an account exists and if not empty.
2018-07-02 18:50:05 +02:00
pub fn exists_and_not_null ( & self , a : & Address ) -> TrieResult < bool > {
2016-11-03 22:22:25 +01:00
self . ensure_cached ( a , RequireCache ::None , false , | a | a . map_or ( false , | a | ! a . is_null ( ) ) )
}
2017-09-15 21:07:54 +02:00
/// Determine whether an account exists and has code or non-zero nonce.
2018-07-02 18:50:05 +02:00
pub fn exists_and_has_code_or_nonce ( & self , a : & Address ) -> TrieResult < bool > {
2017-09-15 21:07:54 +02:00
self . ensure_cached ( a , RequireCache ::CodeSize , false ,
| a | a . map_or ( false , | a | a . code_hash ( ) ! = KECCAK_EMPTY | | * a . nonce ( ) ! = self . account_start_nonce ) )
2017-05-05 16:00:40 +02:00
}
2015-12-16 18:20:23 +01:00
/// Get the balance of account `a`.
2018-07-02 18:50:05 +02:00
pub fn balance ( & self , a : & Address ) -> TrieResult < U256 > {
2016-10-20 16:49:27 +02:00
self . ensure_cached ( a , RequireCache ::None , true ,
2016-07-30 15:45:16 +02:00
| a | a . as_ref ( ) . map_or ( U256 ::zero ( ) , | account | * account . balance ( ) ) )
2015-12-16 18:20:23 +01:00
}
2015-12-19 22:15:22 +01:00
/// Get the nonce of account `a`.
2018-07-02 18:50:05 +02:00
pub fn nonce ( & self , a : & Address ) -> TrieResult < U256 > {
2016-10-20 16:49:27 +02:00
self . ensure_cached ( a , RequireCache ::None , true ,
2016-08-04 18:17:39 +02:00
| a | a . as_ref ( ) . map_or ( self . account_start_nonce , | account | * account . nonce ( ) ) )
2015-12-19 22:15:22 +01:00
}
2019-01-15 10:21:44 +01:00
/// Whether the base storage root of an account remains unchanged.
pub fn is_base_storage_root_unchanged ( & self , a : & Address ) -> TrieResult < bool > {
Ok ( self . ensure_cached ( a , RequireCache ::None , true ,
| a | a . as_ref ( ) . map ( | account | account . is_base_storage_root_unchanged ( ) ) ) ?
. unwrap_or ( true ) )
}
2016-11-27 11:11:56 +01:00
/// Get the storage root of account `a`.
2018-07-02 18:50:05 +02:00
pub fn storage_root ( & self , a : & Address ) -> TrieResult < Option < H256 > > {
2016-11-27 11:11:56 +01:00
self . ensure_cached ( a , RequireCache ::None , true ,
2018-09-07 12:51:08 +02:00
| a | a . as_ref ( ) . and_then ( | account | account . storage_root ( ) ) )
2016-11-27 11:11:56 +01:00
}
2018-09-07 12:51:08 +02:00
/// Get the original storage root since last commit of account `a`.
pub fn original_storage_root ( & self , a : & Address ) -> TrieResult < H256 > {
Ok ( self . ensure_cached ( a , RequireCache ::None , true ,
| a | a . as_ref ( ) . map ( | account | account . original_storage_root ( ) ) ) ?
. unwrap_or ( KECCAK_NULL_RLP ) )
}
/// Get the value of storage at a specific checkpoint.
2018-10-15 16:06:56 +02:00
pub fn checkpoint_storage_at ( & self , start_checkpoint_index : usize , address : & Address , key : & H256 ) -> TrieResult < Option < H256 > > {
#[ must_use ]
2018-09-07 12:51:08 +02:00
enum ReturnKind {
/// Use original storage at value at this address.
OriginalAt ,
2018-10-15 16:06:56 +02:00
/// The checkpoint storage value is the same as the checkpoint storage value at the next checkpoint.
SameAsNext ,
2018-09-07 12:51:08 +02:00
}
2018-10-15 16:06:56 +02:00
let kind = {
2018-09-07 12:51:08 +02:00
let checkpoints = self . checkpoints . borrow ( ) ;
2018-10-15 16:06:56 +02:00
if start_checkpoint_index > = checkpoints . len ( ) {
2018-09-07 12:51:08 +02:00
// The checkpoint was not found. Return None.
2018-10-15 16:06:56 +02:00
return Ok ( None ) ;
}
let mut kind = None ;
for checkpoint in checkpoints . iter ( ) . skip ( start_checkpoint_index ) {
match checkpoint . get ( address ) {
// The account exists at this checkpoint.
Some ( Some ( AccountEntry { account : Some ( ref account ) , .. } ) ) = > {
if let Some ( value ) = account . cached_storage_at ( key ) {
return Ok ( Some ( value ) ) ;
2018-09-07 12:51:08 +02:00
} else {
2018-10-15 16:06:56 +02:00
// This account has checkpoint entry, but the key is not in the entry's cache. We can use
// original_storage_at if current account's original storage root is the same as checkpoint
// account's original storage root. Otherwise, the account must be a newly created contract.
if account . base_storage_root ( ) = = self . original_storage_root ( address ) ? {
kind = Some ( ReturnKind ::OriginalAt ) ;
break
} else {
// If account base storage root is different from the original storage root since last
// commit, then it can only be created from a new contract, where the base storage root
// would always be empty. Note that this branch is actually never called, because
// `cached_storage_at` handled this case.
warn! ( target : " state " , " Trying to get an account's cached storage value, but base storage root does not equal to original storage root! Assuming the value is empty. " ) ;
2019-06-03 15:36:21 +02:00
return Ok ( Some ( H256 ::zero ( ) ) ) ;
2018-10-15 16:06:56 +02:00
}
2018-09-07 12:51:08 +02:00
}
2018-10-15 16:06:56 +02:00
} ,
// The account didn't exist at that point. Return empty value.
2019-06-03 15:36:21 +02:00
Some ( Some ( AccountEntry { account : None , .. } ) ) = > return Ok ( Some ( H256 ::zero ( ) ) ) ,
2018-10-15 16:06:56 +02:00
// The value was not cached at that checkpoint, meaning it was not modified at all.
Some ( None ) = > {
kind = Some ( ReturnKind ::OriginalAt ) ;
break
} ,
// This key does not have a checkpoint entry.
None = > {
kind = Some ( ReturnKind ::SameAsNext ) ;
} ,
}
}
kind . expect ( " start_checkpoint_index is checked to be below checkpoints_len; for loop above must have been executed at least once; it will either early return, or set the kind value to Some; qed " )
2018-09-07 12:51:08 +02:00
} ;
match kind {
2018-10-15 16:06:56 +02:00
ReturnKind ::SameAsNext = > {
// If we reached here, all previous SameAsNext failed to early return. It means that the value we want
// to fetch is the same as current.
Ok ( Some ( self . storage_at ( address , key ) ? ) )
2018-09-07 12:51:08 +02:00
} ,
ReturnKind ::OriginalAt = > Ok ( Some ( self . original_storage_at ( address , key ) ? ) ) ,
}
}
fn storage_at_inner < FCachedStorageAt , FStorageAt > (
& self , address : & Address , key : & H256 , f_cached_at : FCachedStorageAt , f_at : FStorageAt ,
) -> TrieResult < H256 > where
FCachedStorageAt : Fn ( & Account , & H256 ) -> Option < H256 > ,
2018-10-09 22:07:25 +02:00
FStorageAt : Fn ( & Account , & HashDB < KeccakHasher , DBValue > , & H256 ) -> TrieResult < H256 >
2018-09-07 12:51:08 +02:00
{
2016-09-27 18:02:11 +02:00
// Storage key search and update works like this:
// 1. If there's an entry for the account in the local cache check for the key and return it if found.
// 2. If there's an entry for the account in the global cache check for the key or load it into that account.
// 3. If account is missing in the global cache load it into the local cache and cache the key there.
{
2018-03-20 15:46:03 +01:00
// check local cache first without updating
2016-09-27 18:02:11 +02:00
let local_cache = self . cache . borrow_mut ( ) ;
let mut local_account = None ;
if let Some ( maybe_acc ) = local_cache . get ( address ) {
2016-10-06 01:53:23 +02:00
match maybe_acc . account {
Some ( ref account ) = > {
2018-09-07 12:51:08 +02:00
if let Some ( value ) = f_cached_at ( account , key ) {
2017-02-26 13:10:50 +01:00
return Ok ( value ) ;
2016-09-27 18:02:11 +02:00
} else {
local_account = Some ( maybe_acc ) ;
}
} ,
2019-06-03 15:36:21 +02:00
_ = > return Ok ( H256 ::zero ( ) ) ,
2016-09-27 18:02:11 +02:00
}
}
// check the global cache and and cache storage key there if found,
2017-02-26 13:10:50 +01:00
let trie_res = self . db . get_cached ( address , | acc | match acc {
2019-06-03 15:36:21 +02:00
None = > Ok ( H256 ::zero ( ) ) ,
2017-02-26 13:10:50 +01:00
Some ( a ) = > {
2019-02-20 19:09:34 +01:00
let account_db = self . factories . accountdb . readonly ( self . db . as_hash_db ( ) , a . address_hash ( address ) ) ;
f_at ( a , account_db . as_hash_db ( ) , key )
2017-02-26 13:10:50 +01:00
}
} ) ;
2017-09-19 11:34:13 +02:00
if let Some ( res ) = trie_res {
return res ;
2016-09-27 18:02:11 +02:00
}
2017-02-26 13:10:50 +01:00
// otherwise cache the account localy and cache storage key there.
2016-09-27 18:02:11 +02:00
if let Some ( ref mut acc ) = local_account {
2016-10-06 01:53:23 +02:00
if let Some ( ref account ) = acc . account {
2019-02-20 19:09:34 +01:00
let account_db = self . factories . accountdb . readonly ( self . db . as_hash_db ( ) , account . address_hash ( address ) ) ;
return f_at ( account , account_db . as_hash_db ( ) , key )
2016-09-27 18:02:11 +02:00
} else {
2019-06-03 15:36:21 +02:00
return Ok ( H256 ::zero ( ) )
2016-09-27 18:02:11 +02:00
}
}
}
2016-10-03 12:02:43 +02:00
2017-02-21 12:35:21 +01:00
// check if the account could exist before any requests to trie
2017-02-26 13:10:50 +01:00
if self . db . is_known_null ( address ) { return Ok ( H256 ::zero ( ) ) }
2016-10-03 12:02:43 +02:00
2016-09-27 18:02:11 +02:00
// account is not found in the global cache, get from the DB and insert into local
2019-02-20 19:09:34 +01:00
let db = & self . db . as_hash_db ( ) ;
let db = self . factories . trie . readonly ( db , & self . root ) . expect ( SEC_TRIE_DB_UNWRAP_STR ) ;
2018-05-08 11:22:12 +02:00
let from_rlp = | b : & [ u8 ] | Account ::from_rlp ( b ) . expect ( " decoding db value failed " ) ;
2019-06-03 15:36:21 +02:00
let maybe_acc = db . get_with ( address . as_bytes ( ) , from_rlp ) ? ;
let r = maybe_acc . as_ref ( ) . map_or ( Ok ( H256 ::zero ( ) ) , | a | {
2019-02-20 19:09:34 +01:00
let account_db = self . factories . accountdb . readonly ( self . db . as_hash_db ( ) , a . address_hash ( address ) ) ;
f_at ( a , account_db . as_hash_db ( ) , key )
2016-09-27 18:02:11 +02:00
} ) ;
2016-10-06 01:53:23 +02:00
self . insert_cache ( address , AccountEntry ::new_clean ( maybe_acc ) ) ;
2016-09-27 18:02:11 +02:00
r
2015-12-19 22:15:22 +01:00
}
2018-09-07 12:51:08 +02:00
/// Mutate storage of account `address` so that it is `value` for `key`.
pub fn storage_at ( & self , address : & Address , key : & H256 ) -> TrieResult < H256 > {
self . storage_at_inner (
address ,
key ,
| account , key | { account . cached_storage_at ( key ) } ,
| account , db , key | { account . storage_at ( db , key ) } ,
)
}
/// Get the value of storage after last state commitment.
pub fn original_storage_at ( & self , address : & Address , key : & H256 ) -> TrieResult < H256 > {
self . storage_at_inner (
address ,
key ,
| account , key | { account . cached_original_storage_at ( key ) } ,
| account , db , key | { account . original_storage_at ( db , key ) } ,
)
}
2016-09-27 18:02:11 +02:00
/// Get accounts' code.
2018-07-02 18:50:05 +02:00
pub fn code ( & self , a : & Address ) -> TrieResult < Option < Arc < Bytes > > > {
2016-10-20 16:49:27 +02:00
self . ensure_cached ( a , RequireCache ::Code , true ,
2016-10-02 18:45:36 +02:00
| a | a . as_ref ( ) . map_or ( None , | a | a . code ( ) . clone ( ) ) )
}
2017-02-21 12:35:21 +01:00
/// Get an account's code hash.
2018-07-31 07:27:57 +02:00
pub fn code_hash ( & self , a : & Address ) -> TrieResult < Option < H256 > > {
2016-10-20 16:49:27 +02:00
self . ensure_cached ( a , RequireCache ::None , true ,
2018-07-31 07:27:57 +02:00
| a | a . as_ref ( ) . map ( | a | a . code_hash ( ) ) )
2016-09-22 19:58:42 +02:00
}
2016-09-27 18:02:11 +02:00
/// Get accounts' code size.
2018-07-02 18:50:05 +02:00
pub fn code_size ( & self , a : & Address ) -> TrieResult < Option < usize > > {
2016-10-20 16:49:27 +02:00
self . ensure_cached ( a , RequireCache ::CodeSize , true ,
2016-09-27 18:02:11 +02:00
| a | a . as_ref ( ) . and_then ( | a | a . code_size ( ) ) )
2015-12-19 22:15:22 +01:00
}
2015-12-16 18:20:23 +01:00
/// Add `incr` to the balance of account `a`.
2018-07-02 18:50:05 +02:00
pub fn add_balance ( & mut self , a : & Address , incr : & U256 , cleanup_mode : CleanupMode ) -> TrieResult < ( ) > {
2017-02-26 13:10:50 +01:00
trace! ( target : " state " , " add_balance({}, {}): {} " , a , incr , self . balance ( a ) ? ) ;
2016-11-03 22:22:25 +01:00
let is_value_transfer = ! incr . is_zero ( ) ;
2017-02-26 13:10:50 +01:00
if is_value_transfer | | ( cleanup_mode = = CleanupMode ::ForceCreate & & ! self . exists ( a ) ? ) {
self . require ( a , false ) ? . add_balance ( incr ) ;
2017-06-28 09:10:57 +02:00
} else if let CleanupMode ::TrackTouched ( set ) = cleanup_mode {
if self . exists ( a ) ? {
set . insert ( * a ) ;
self . touch ( a ) ? ;
2016-11-03 22:22:25 +01:00
}
2016-10-06 01:53:23 +02:00
}
2017-02-26 13:10:50 +01:00
Ok ( ( ) )
2015-12-16 18:20:23 +01:00
}
/// Subtract `decr` from the balance of account `a`.
2018-07-02 18:50:05 +02:00
pub fn sub_balance ( & mut self , a : & Address , decr : & U256 , cleanup_mode : & mut CleanupMode ) -> TrieResult < ( ) > {
2017-02-26 13:10:50 +01:00
trace! ( target : " state " , " sub_balance({}, {}): {} " , a , decr , self . balance ( a ) ? ) ;
if ! decr . is_zero ( ) | | ! self . exists ( a ) ? {
self . require ( a , false ) ? . sub_balance ( decr ) ;
2016-10-06 01:53:23 +02:00
}
2017-06-28 09:10:57 +02:00
if let CleanupMode ::TrackTouched ( ref mut set ) = * cleanup_mode {
set . insert ( * a ) ;
}
2017-02-26 13:10:50 +01:00
Ok ( ( ) )
2015-12-16 18:20:23 +01:00
}
2015-12-19 22:38:25 +01:00
/// Subtracts `by` from the balance of `from` and adds it to that of `to`.
2018-07-02 18:50:05 +02:00
pub fn transfer_balance ( & mut self , from : & Address , to : & Address , by : & U256 , mut cleanup_mode : CleanupMode ) -> TrieResult < ( ) > {
2017-06-28 09:10:57 +02:00
self . sub_balance ( from , by , & mut cleanup_mode ) ? ;
2017-02-26 13:10:50 +01:00
self . add_balance ( to , by , cleanup_mode ) ? ;
Ok ( ( ) )
2015-12-19 22:38:25 +01:00
}
2015-12-16 18:20:23 +01:00
/// Increment the nonce of account `a` by 1.
2018-07-02 18:50:05 +02:00
pub fn inc_nonce ( & mut self , a : & Address ) -> TrieResult < ( ) > {
2017-02-26 13:10:50 +01:00
self . require ( a , false ) . map ( | mut x | x . inc_nonce ( ) )
2015-12-16 18:20:23 +01:00
}
2015-12-19 19:00:19 +01:00
/// Mutate storage of account `a` so that it is `value` for `key`.
2018-07-02 18:50:05 +02:00
pub fn set_storage ( & mut self , a : & Address , key : H256 , value : H256 ) -> TrieResult < ( ) > {
2018-02-09 09:32:06 +01:00
trace! ( target : " state " , " set_storage({}:{:x} to {:x}) " , a , key , value ) ;
2017-02-26 13:10:50 +01:00
if self . storage_at ( a , & key ) ? ! = value {
self . require ( a , false ) ? . set_storage ( key , value )
2016-10-06 01:53:23 +02:00
}
2017-02-26 13:10:50 +01:00
Ok ( ( ) )
2015-12-19 19:00:19 +01:00
}
2016-06-29 16:29:04 +02:00
/// Initialise the code of account `a` so that it is `code`.
2016-01-09 12:30:41 +01:00
/// NOTE: Account should have been created with `new_contract`.
2018-07-02 18:50:05 +02:00
pub fn init_code ( & mut self , a : & Address , code : Bytes ) -> TrieResult < ( ) > {
2018-09-07 12:51:08 +02:00
self . require_or_from ( a , true , | | Account ::new_contract ( 0. into ( ) , self . account_start_nonce , KECCAK_NULL_RLP ) , | _ | { } ) ? . init_code ( code ) ;
2017-02-26 13:10:50 +01:00
Ok ( ( ) )
2015-12-19 19:00:19 +01:00
}
2016-06-29 16:29:04 +02:00
/// Reset the code of account `a` so that it is `code`.
2018-07-02 18:50:05 +02:00
pub fn reset_code ( & mut self , a : & Address , code : Bytes ) -> TrieResult < ( ) > {
2018-09-07 12:51:08 +02:00
self . require_or_from ( a , true , | | Account ::new_contract ( 0. into ( ) , self . account_start_nonce , KECCAK_NULL_RLP ) , | _ | { } ) ? . reset_code ( code ) ;
2017-02-26 13:10:50 +01:00
Ok ( ( ) )
2016-07-22 14:47:23 +02:00
}
2016-06-29 16:29:04 +02:00
2017-03-08 14:39:44 +01:00
/// Execute a given transaction, producing a receipt and an optional trace.
2015-12-19 22:38:25 +01:00
/// This will change the state accordingly.
2017-10-20 15:40:25 +02:00
pub fn apply ( & mut self , env_info : & EnvInfo , machine : & Machine , t : & SignedTransaction , tracing : bool ) -> ApplyResult < FlatTrace , VMTrace > {
2017-08-28 14:25:16 +02:00
if tracing {
let options = TransactOptions ::with_tracing ( ) ;
2017-09-26 14:19:08 +02:00
self . apply_with_tracing ( env_info , machine , t , options . tracer , options . vm_tracer )
2017-08-28 14:25:16 +02:00
} else {
let options = TransactOptions ::with_no_tracing ( ) ;
2017-09-26 14:19:08 +02:00
self . apply_with_tracing ( env_info , machine , t , options . tracer , options . vm_tracer )
2017-08-28 14:25:16 +02:00
}
}
/// Execute a given transaction with given tracer and VM tracer producing a receipt and an optional trace.
/// This will change the state accordingly.
pub fn apply_with_tracing < V , T > (
& mut self ,
env_info : & EnvInfo ,
2017-09-26 14:19:08 +02:00
machine : & Machine ,
2017-08-28 14:25:16 +02:00
t : & SignedTransaction ,
tracer : T ,
vm_tracer : V ,
2017-10-20 15:40:25 +02:00
) -> ApplyResult < T ::Output , V ::Output > where
2017-08-28 14:25:16 +02:00
T : trace ::Tracer ,
V : trace ::VMTracer ,
{
let options = TransactOptions ::new ( tracer , vm_tracer ) ;
2017-09-26 14:19:08 +02:00
let e = self . execute ( env_info , machine , t , options , false ) ? ;
let params = machine . params ( ) ;
2016-01-15 18:56:28 +01:00
2017-09-26 14:19:08 +02:00
let eip658 = env_info . number > = params . eip658_transition ;
2017-09-15 21:07:54 +02:00
let no_intermediate_commits =
eip658 | |
2017-09-26 14:19:08 +02:00
( env_info . number > = params . eip98_transition & & env_info . number > = params . validate_receipts_transition ) ;
2017-09-15 21:07:54 +02:00
2017-09-21 10:11:53 +02:00
let outcome = if no_intermediate_commits {
if eip658 {
TransactionOutcome ::StatusCode ( if e . exception . is_some ( ) { 0 } else { 1 } )
} else {
TransactionOutcome ::Unknown
}
2017-09-15 21:07:54 +02:00
} else {
2017-01-25 20:22:48 +01:00
self . commit ( ) ? ;
2017-09-21 10:11:53 +02:00
TransactionOutcome ::StateRoot ( self . root ( ) . clone ( ) )
2017-01-25 20:22:48 +01:00
} ;
2017-08-28 14:25:16 +02:00
let output = e . output ;
2017-09-21 10:11:53 +02:00
let receipt = Receipt ::new ( outcome , e . cumulative_gas_used , e . logs ) ;
2016-08-17 19:25:02 +02:00
trace! ( target : " state " , " Transaction receipt: {:?} " , receipt ) ;
2017-08-28 14:25:16 +02:00
Ok ( ApplyOutcome {
receipt ,
output ,
trace : e . trace ,
vm_trace : e . vm_trace ,
} )
2015-12-20 13:16:12 +01:00
}
2015-12-19 22:38:25 +01:00
2017-05-17 12:41:33 +02:00
// Execute a given transaction without committing changes.
//
// `virt` signals that we are executing outside of a block set and restrictions like
// gas limits and gas costs should be lifted.
2017-09-26 14:19:08 +02:00
fn execute < T , V > ( & mut self , env_info : & EnvInfo , machine : & Machine , t : & SignedTransaction , options : TransactOptions < T , V > , virt : bool )
2017-10-20 15:40:25 +02:00
-> Result < Executed < T ::Output , V ::Output > , ExecutionError > where T : trace ::Tracer , V : trace ::VMTracer ,
2017-05-17 12:41:33 +02:00
{
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( env_info . number ) ;
let mut e = Executive ::new ( self , env_info , machine , & schedule ) ;
2017-05-17 12:41:33 +02:00
match virt {
true = > e . transact_virtual ( t , options ) ,
false = > e . transact ( t , options ) ,
}
2017-03-08 14:39:44 +01:00
}
2018-07-02 18:50:05 +02:00
fn touch ( & mut self , a : & Address ) -> TrieResult < ( ) > {
2017-06-28 09:10:57 +02:00
self . require ( a , false ) ? ;
Ok ( ( ) )
}
/// Commits our cached account changes into the trie.
pub fn commit ( & mut self ) -> Result < ( ) , Error > {
2018-09-07 12:51:08 +02:00
assert! ( self . checkpoints . borrow ( ) . is_empty ( ) ) ;
2015-12-13 21:36:17 +01:00
// first, commit the sub trees.
2017-06-28 09:10:57 +02:00
let mut accounts = self . cache . borrow_mut ( ) ;
2016-10-06 01:53:23 +02:00
for ( address , ref mut a ) in accounts . iter_mut ( ) . filter ( | & ( _ , ref a ) | a . is_dirty ( ) ) {
2016-10-27 08:28:12 +02:00
if let Some ( ref mut account ) = a . account {
2016-11-03 22:22:25 +01:00
let addr_hash = account . address_hash ( address ) ;
{
2019-02-20 19:09:34 +01:00
let mut account_db = self . factories . accountdb . create ( self . db . as_hash_db_mut ( ) , addr_hash ) ;
account . commit_storage ( & self . factories . trie , account_db . as_hash_db_mut ( ) ) ? ;
account . commit_code ( account_db . as_hash_db_mut ( ) ) ;
2016-11-03 22:22:25 +01:00
}
2016-10-27 08:28:12 +02:00
if ! account . is_empty ( ) {
2017-06-28 09:10:57 +02:00
self . db . note_non_null_account ( address ) ;
2015-12-13 23:12:22 +01:00
}
}
2015-12-13 21:36:17 +01:00
}
{
2019-02-20 19:09:34 +01:00
let mut trie = self . factories . trie . from_existing ( self . db . as_hash_db_mut ( ) , & mut self . root ) ? ;
2016-10-06 01:53:23 +02:00
for ( address , ref mut a ) in accounts . iter_mut ( ) . filter ( | & ( _ , ref a ) | a . is_dirty ( ) ) {
2016-10-07 12:10:12 +02:00
a . state = AccountState ::Committed ;
2016-10-06 01:53:23 +02:00
match a . account {
Some ( ref mut account ) = > {
2019-06-03 15:36:21 +02:00
trie . insert ( address . as_bytes ( ) , & account . rlp ( ) ) ? ;
2016-09-27 18:02:11 +02:00
} ,
2016-10-06 01:53:23 +02:00
None = > {
2019-06-03 15:36:21 +02:00
trie . remove ( address . as_bytes ( ) ) ? ;
2016-08-03 22:03:40 +02:00
} ,
2017-06-28 09:10:57 +02:00
} ;
2015-12-13 21:36:17 +01:00
}
}
2016-08-03 18:35:48 +02:00
Ok ( ( ) )
2015-12-13 21:36:17 +01:00
}
2016-10-07 13:34:32 +02:00
/// Propagate local cache into shared canonical state cache.
fn propagate_to_global_cache ( & mut self ) {
2016-09-27 18:02:11 +02:00
let mut addresses = self . cache . borrow_mut ( ) ;
2016-10-06 01:53:23 +02:00
trace! ( " Committing cache {:?} entries " , addresses . len ( ) ) ;
2016-10-07 12:10:12 +02:00
for ( address , a ) in addresses . drain ( ) . filter ( | & ( _ , ref a ) | a . state = = AccountState ::Committed | | a . state = = AccountState ::CleanFresh ) {
2016-10-07 13:34:32 +02:00
self . db . add_to_account_cache ( address , a . account , a . state = = AccountState ::Committed ) ;
2016-09-27 18:02:11 +02:00
}
}
2016-07-17 09:18:15 +02:00
/// Clear state cache
pub fn clear ( & mut self ) {
2018-09-07 12:51:08 +02:00
assert! ( self . checkpoints . borrow ( ) . is_empty ( ) ) ;
2016-07-17 09:18:15 +02:00
self . cache . borrow_mut ( ) . clear ( ) ;
}
2017-06-28 09:10:57 +02:00
/// Remove any touched empty or dust accounts.
2018-07-02 18:50:05 +02:00
pub fn kill_garbage ( & mut self , touched : & HashSet < Address > , remove_empty_touched : bool , min_balance : & Option < U256 > , kill_contracts : bool ) -> TrieResult < ( ) > {
2017-06-28 09:10:57 +02:00
let to_kill : HashSet < _ > = {
self . cache . borrow ( ) . iter ( ) . filter_map ( | ( address , ref entry ) |
if touched . contains ( address ) & & // Check all touched accounts
( ( remove_empty_touched & & entry . exists_and_is_null ( ) ) // Remove all empty touched accounts.
| | min_balance . map_or ( false , | ref balance | entry . account . as_ref ( ) . map_or ( false , | account |
( account . is_basic ( ) | | kill_contracts ) // Remove all basic and optionally contract accounts where balance has been decreased.
& & account . balance ( ) < balance & & entry . old_balance . as_ref ( ) . map_or ( false , | b | account . balance ( ) < b ) ) ) ) {
Some ( address . clone ( ) )
} else { None } ) . collect ( )
} ;
for address in to_kill {
self . kill_account ( & address ) ;
}
Ok ( ( ) )
}
2016-02-03 15:33:58 +01:00
/// Populate the state from `accounts`.
2017-08-28 14:25:16 +02:00
/// Used for tests.
2016-01-14 12:27:35 +01:00
pub fn populate_from ( & mut self , accounts : PodState ) {
2016-10-22 15:22:16 +02:00
assert! ( self . checkpoints . borrow ( ) . is_empty ( ) ) ;
2016-01-14 12:27:35 +01:00
for ( add , acc ) in accounts . drain ( ) . into_iter ( ) {
2016-10-06 01:53:23 +02:00
self . cache . borrow_mut ( ) . insert ( add , AccountEntry ::new_dirty ( Some ( Account ::from_pod ( acc ) ) ) ) ;
2016-01-13 01:19:05 +01:00
}
2015-12-19 22:38:25 +01:00
}
2016-01-13 12:14:11 +01:00
/// Populate a PodAccount map from this state.
2018-11-25 20:12:59 +01:00
fn to_pod_cache ( & self ) -> PodState {
2016-10-22 15:22:16 +02:00
assert! ( self . checkpoints . borrow ( ) . is_empty ( ) ) ;
2016-01-25 18:56:36 +01:00
PodState ::from ( self . cache . borrow ( ) . iter ( ) . fold ( BTreeMap ::new ( ) , | mut m , ( add , opt ) | {
2016-10-06 01:53:23 +02:00
if let Some ( ref acc ) = opt . account {
2018-11-25 20:12:59 +01:00
m . insert ( * add , PodAccount ::from_account ( acc ) ) ;
2016-01-13 12:14:11 +01:00
}
m
2016-01-14 12:27:35 +01:00
} ) )
2016-01-13 12:14:11 +01:00
}
2018-11-25 20:12:59 +01:00
#[ cfg(feature= " to-pod-full " ) ]
/// Populate a PodAccount map from this state.
/// Warning this is not for real time use.
2018-12-03 16:26:39 +01:00
/// Use of this method requires FatDB mode to be able
2018-11-25 20:12:59 +01:00
/// to iterate on accounts.
pub fn to_pod_full ( & self ) -> Result < PodState , Error > {
assert! ( self . checkpoints . borrow ( ) . is_empty ( ) ) ;
assert! ( self . factories . trie . is_fat ( ) ) ;
let mut result = BTreeMap ::new ( ) ;
2019-02-20 19:09:34 +01:00
let db = & self . db . as_hash_db ( ) ;
let trie = self . factories . trie . readonly ( db , & self . root ) ? ;
2018-11-25 20:12:59 +01:00
2018-12-03 16:26:39 +01:00
// put trie in cache
2018-11-25 20:12:59 +01:00
for item in trie . iter ( ) ? {
if let Ok ( ( addr , _dbval ) ) = item {
let address = Address ::from_slice ( & addr ) ;
let _ = self . require ( & address , true ) ;
}
}
// Resolve missing part
for ( add , opt ) in self . cache . borrow ( ) . iter ( ) {
if let Some ( ref acc ) = opt . account {
let pod_account = self . account_to_pod_account ( acc , add ) ? ;
result . insert ( add . clone ( ) , pod_account ) ;
}
}
Ok ( PodState ::from ( result ) )
}
/// Create a PodAccount from an account.
/// Differs from existing method by including all storage
/// values of the account to the PodAccount.
/// This function is only intended for use in small tests or with fresh accounts.
/// It requires FatDB.
#[ cfg(feature= " to-pod-full " ) ]
fn account_to_pod_account ( & self , account : & Account , address : & Address ) -> Result < PodAccount , Error > {
2019-06-03 15:36:21 +02:00
use ethereum_types ::BigEndianHash ;
2018-11-25 20:12:59 +01:00
let mut pod_storage = BTreeMap ::new ( ) ;
let addr_hash = account . address_hash ( address ) ;
2019-02-20 19:09:34 +01:00
let accountdb = self . factories . accountdb . readonly ( self . db . as_hash_db ( ) , addr_hash ) ;
2018-11-25 20:12:59 +01:00
let root = account . base_storage_root ( ) ;
2019-02-20 19:09:34 +01:00
let accountdb = & accountdb . as_hash_db ( ) ;
let trie = self . factories . trie . readonly ( accountdb , & root ) ? ;
2018-11-25 20:12:59 +01:00
for o_kv in trie . iter ( ) ? {
if let Ok ( ( key , val ) ) = o_kv {
2019-06-03 15:36:21 +02:00
pod_storage . insert (
H256 ::from_slice ( & key [ .. ] ) ,
BigEndianHash ::from_uint (
& rlp ::decode ::< U256 > ( & val [ .. ] ) . expect ( " Decoded from trie which was encoded from the same type; qed " )
) ,
) ;
2018-11-25 20:12:59 +01:00
}
}
let mut pod_account = PodAccount ::from_account ( & account ) ;
// cached one first
pod_storage . append ( & mut pod_account . storage ) ;
pod_account . storage = pod_storage ;
Ok ( pod_account )
}
2018-05-02 16:47:53 +02:00
/// Populate a PodAccount map from this state, with another state as the account and storage query.
2018-11-25 20:12:59 +01:00
fn to_pod_diff < X : Backend > ( & mut self , query : & State < X > ) -> TrieResult < PodState > {
2018-04-04 11:49:43 +02:00
assert! ( self . checkpoints . borrow ( ) . is_empty ( ) ) ;
2018-05-02 16:47:53 +02:00
// Merge PodAccount::to_pod for cache of self and `query`.
let all_addresses = self . cache . borrow ( ) . keys ( ) . cloned ( )
. chain ( query . cache . borrow ( ) . keys ( ) . cloned ( ) )
. collect ::< BTreeSet < _ > > ( ) ;
2018-07-02 18:50:05 +02:00
Ok ( PodState ::from ( all_addresses . into_iter ( ) . fold ( Ok ( BTreeMap ::new ( ) ) , | m : TrieResult < _ > , address | {
2018-05-02 16:47:53 +02:00
let mut m = m ? ;
let account = self . ensure_cached ( & address , RequireCache ::Code , true , | acc | {
acc . map ( | acc | {
// Merge all modified storage keys.
let all_keys = {
let self_keys = acc . storage_changes ( ) . keys ( ) . cloned ( )
. collect ::< BTreeSet < _ > > ( ) ;
if let Some ( ref query_storage ) = query . cache . borrow ( ) . get ( & address )
. and_then ( | opt | {
Some ( opt . account . as_ref ( ) ? . storage_changes ( ) . keys ( ) . cloned ( )
. collect ::< BTreeSet < _ > > ( ) )
} )
{
self_keys . union ( & query_storage ) . cloned ( ) . collect ::< Vec < _ > > ( )
} else {
self_keys . into_iter ( ) . collect ::< Vec < _ > > ( )
}
} ;
2018-04-04 11:49:43 +02:00
2018-05-02 16:47:53 +02:00
// Storage must be fetched after ensure_cached to avoid borrow problem.
( * acc . balance ( ) , * acc . nonce ( ) , all_keys , acc . code ( ) . map ( | x | x . to_vec ( ) ) )
} )
} ) ? ;
2017-02-26 13:10:50 +01:00
2018-05-02 16:47:53 +02:00
if let Some ( ( balance , nonce , storage_keys , code ) ) = account {
2018-07-02 18:50:05 +02:00
let storage = storage_keys . into_iter ( ) . fold ( Ok ( BTreeMap ::new ( ) ) , | s : TrieResult < _ > , key | {
2018-05-02 16:47:53 +02:00
let mut s = s ? ;
s . insert ( key , self . storage_at ( & address , & key ) ? ) ;
Ok ( s )
} ) ? ;
m . insert ( address , PodAccount {
balance , nonce , storage , code
} ) ;
2016-10-13 23:28:56 +02:00
}
2017-02-26 13:10:50 +01:00
2018-05-02 16:47:53 +02:00
Ok ( m )
} ) ? ) )
2016-05-31 21:03:44 +02:00
}
/// Returns a `StateDiff` describing the difference from `orig` to `self`.
/// Consumes self.
2018-07-02 18:50:05 +02:00
pub fn diff_from < X : Backend > ( & self , mut orig : State < X > ) -> TrieResult < StateDiff > {
2018-11-25 20:12:59 +01:00
let pod_state_post = self . to_pod_cache ( ) ;
2018-05-02 16:47:53 +02:00
let pod_state_pre = orig . to_pod_diff ( self ) ? ;
Ok ( pod_state ::diff_pod ( & pod_state_pre , & pod_state_post ) )
2016-05-31 21:03:44 +02:00
}
2018-07-31 07:27:57 +02:00
/// Load required account data from the databases. Returns whether the cache succeeds.
#[ must_use ]
2018-10-09 22:07:25 +02:00
fn update_account_cache ( require : RequireCache , account : & mut Account , state_db : & B , db : & HashDB < KeccakHasher , DBValue > ) -> bool {
2017-09-19 11:34:13 +02:00
if let RequireCache ::None = require {
2018-07-31 07:27:57 +02:00
return true ;
2017-09-19 11:34:13 +02:00
}
if account . is_cached ( ) {
2018-07-31 07:27:57 +02:00
return true ;
2017-09-19 11:34:13 +02:00
}
// if there's already code in the global cache, always cache it localy
let hash = account . code_hash ( ) ;
match state_db . get_cached_code ( & hash ) {
2018-07-31 07:27:57 +02:00
Some ( code ) = > {
account . cache_given_code ( code ) ;
true
} ,
2017-09-19 11:34:13 +02:00
None = > match require {
2018-07-31 07:27:57 +02:00
RequireCache ::None = > true ,
2017-09-19 11:34:13 +02:00
RequireCache ::Code = > {
if let Some ( code ) = account . cache_code ( db ) {
// propagate code loaded from the database to
// the global code cache.
2018-07-31 07:27:57 +02:00
state_db . cache_code ( hash , code ) ;
true
} else {
false
2016-10-28 16:04:44 +02:00
}
2017-09-19 11:34:13 +02:00
} ,
RequireCache ::CodeSize = > {
2018-07-31 07:27:57 +02:00
account . cache_code_size ( db )
2016-10-28 16:04:44 +02:00
}
2015-12-16 18:20:23 +01:00
}
2015-12-19 19:00:19 +01:00
}
2016-09-27 18:02:11 +02:00
}
2016-07-30 15:45:16 +02:00
2016-09-27 18:02:11 +02:00
/// Check caches for required data
/// First searches for account in the local, then the shared cache.
/// Populates local cache if nothing found.
2018-07-02 18:50:05 +02:00
fn ensure_cached < F , U > ( & self , a : & Address , require : RequireCache , check_null : bool , f : F ) -> TrieResult < U >
2016-09-27 18:02:11 +02:00
where F : Fn ( Option < & Account > ) -> U {
// check local cache first
if let Some ( ref mut maybe_acc ) = self . cache . borrow_mut ( ) . get_mut ( a ) {
2016-10-06 01:53:23 +02:00
if let Some ( ref mut account ) = maybe_acc . account {
2019-02-20 19:09:34 +01:00
let accountdb = self . factories . accountdb . readonly ( self . db . as_hash_db ( ) , account . address_hash ( a ) ) ;
if Self ::update_account_cache ( require , account , & self . db , accountdb . as_hash_db ( ) ) {
2018-07-31 07:27:57 +02:00
return Ok ( f ( Some ( account ) ) ) ;
} else {
2019-06-03 15:36:21 +02:00
return Err ( Box ::new ( TrieError ::IncompleteDatabase ( H256 ::from ( * a ) ) ) ) ;
2018-07-31 07:27:57 +02:00
}
2016-09-27 18:02:11 +02:00
}
2017-02-26 13:10:50 +01:00
return Ok ( f ( None ) ) ;
2016-09-27 18:02:11 +02:00
}
// check global cache
let result = self . db . get_cached ( a , | mut acc | {
if let Some ( ref mut account ) = acc {
2019-02-20 19:09:34 +01:00
let accountdb = self . factories . accountdb . readonly ( self . db . as_hash_db ( ) , account . address_hash ( a ) ) ;
if ! Self ::update_account_cache ( require , account , & self . db , accountdb . as_hash_db ( ) ) {
2019-06-03 15:36:21 +02:00
return Err ( Box ::new ( TrieError ::IncompleteDatabase ( H256 ::from ( * a ) ) ) ) ;
2018-07-31 07:27:57 +02:00
}
2016-09-27 18:02:11 +02:00
}
2018-07-31 07:27:57 +02:00
Ok ( f ( acc . map ( | a | & * a ) ) )
2016-09-27 18:02:11 +02:00
} ) ;
match result {
2018-07-31 07:27:57 +02:00
Some ( r ) = > Ok ( r ? ) ,
2016-09-27 18:02:11 +02:00
None = > {
2017-02-21 12:35:21 +01:00
// first check if it is not in database for sure
2017-02-26 13:10:50 +01:00
if check_null & & self . db . is_known_null ( a ) { return Ok ( f ( None ) ) ; }
2016-10-03 12:02:43 +02:00
2016-09-27 18:02:11 +02:00
// not found in the global cache, get from the DB and insert into local
2019-02-20 19:09:34 +01:00
let db = & self . db . as_hash_db ( ) ;
let db = self . factories . trie . readonly ( db , & self . root ) ? ;
2018-05-08 11:22:12 +02:00
let from_rlp = | b : & [ u8 ] | Account ::from_rlp ( b ) . expect ( " decoding db value failed " ) ;
2019-06-03 15:36:21 +02:00
let mut maybe_acc = db . get_with ( a . as_bytes ( ) , from_rlp ) ? ;
2016-09-27 18:02:11 +02:00
if let Some ( ref mut account ) = maybe_acc . as_mut ( ) {
2019-02-20 19:09:34 +01:00
let accountdb = self . factories . accountdb . readonly ( self . db . as_hash_db ( ) , account . address_hash ( a ) ) ;
if ! Self ::update_account_cache ( require , account , & self . db , accountdb . as_hash_db ( ) ) {
2019-06-03 15:36:21 +02:00
return Err ( Box ::new ( TrieError ::IncompleteDatabase ( H256 ::from ( * a ) ) ) ) ;
2018-07-31 07:27:57 +02:00
}
2016-09-27 18:02:11 +02:00
}
let r = f ( maybe_acc . as_ref ( ) ) ;
2016-10-07 12:10:12 +02:00
self . insert_cache ( a , AccountEntry ::new_clean ( maybe_acc ) ) ;
2017-02-26 13:10:50 +01:00
Ok ( r )
2016-09-27 18:02:11 +02:00
}
}
2015-12-16 18:20:23 +01:00
}
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
2018-07-02 18:50:05 +02:00
fn require < ' a > ( & ' a self , a : & Address , require_code : bool ) -> TrieResult < RefMut < ' a , Account > > {
2018-09-07 12:51:08 +02:00
self . require_or_from ( a , require_code , | | Account ::new_basic ( 0 u8 . into ( ) , self . account_start_nonce ) , | _ | { } )
2015-12-19 19:00:19 +01:00
}
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
2016-01-09 14:19:35 +01:00
/// If it doesn't exist, make account equal the evaluation of `default`.
2018-07-02 18:50:05 +02:00
fn require_or_from < ' a , F , G > ( & ' a self , a : & Address , require_code : bool , default : F , not_default : G ) -> TrieResult < RefMut < ' a , Account > >
2017-02-26 13:10:50 +01:00
where F : FnOnce ( ) -> Account , G : FnOnce ( & mut Account ) ,
2016-08-03 18:35:48 +02:00
{
let contains_key = self . cache . borrow ( ) . contains_key ( a ) ;
if ! contains_key {
2016-09-27 18:02:11 +02:00
match self . db . get_cached_account ( a ) {
2016-10-07 12:10:12 +02:00
Some ( acc ) = > self . insert_cache ( a , AccountEntry ::new_clean_cached ( acc ) ) ,
2016-09-27 18:02:11 +02:00
None = > {
2017-02-21 12:35:21 +01:00
let maybe_acc = if ! self . db . is_known_null ( a ) {
2019-02-20 19:09:34 +01:00
let db = & self . db . as_hash_db ( ) ;
let db = self . factories . trie . readonly ( db , & self . root ) ? ;
2018-05-08 11:22:12 +02:00
let from_rlp = | b :& [ u8 ] | { Account ::from_rlp ( b ) . expect ( " decoding db value failed " ) } ;
2019-06-03 15:36:21 +02:00
AccountEntry ::new_clean ( db . get_with ( a . as_bytes ( ) , from_rlp ) ? )
2016-10-27 08:28:12 +02:00
} else {
2016-10-06 01:53:23 +02:00
AccountEntry ::new_clean ( None )
2016-09-27 18:02:11 +02:00
} ;
self . insert_cache ( a , maybe_acc ) ;
}
}
2016-02-03 19:34:51 +01:00
}
2016-10-06 01:53:23 +02:00
self . note_cache ( a ) ;
2016-08-03 18:35:48 +02:00
2016-10-20 23:41:15 +02:00
// at this point the entry is guaranteed to be in the cache.
2018-12-03 16:26:39 +01:00
let mut account = RefMut ::map ( self . cache . borrow_mut ( ) , | c | {
2017-10-15 15:10:20 +02:00
let entry = c . get_mut ( a ) . expect ( " entry known to exist in the cache; qed " ) ;
2016-10-20 23:41:15 +02:00
match & mut entry . account {
& mut Some ( ref mut acc ) = > not_default ( acc ) ,
slot = > * slot = Some ( default ( ) ) ,
}
2016-10-06 01:53:23 +02:00
// set the dirty flag after changing account data.
entry . state = AccountState ::Dirty ;
2018-12-03 16:26:39 +01:00
entry . account . as_mut ( ) . expect ( " Required account must always exist; qed " )
} ) ;
if require_code {
let addr_hash = account . address_hash ( a ) ;
2019-02-20 19:09:34 +01:00
let accountdb = self . factories . accountdb . readonly ( self . db . as_hash_db ( ) , addr_hash ) ;
2018-12-03 16:26:39 +01:00
2019-02-20 19:09:34 +01:00
if ! Self ::update_account_cache ( RequireCache ::Code , & mut account , & self . db , accountdb . as_hash_db ( ) ) {
2019-06-03 15:36:21 +02:00
return Err ( Box ::new ( TrieError ::IncompleteDatabase ( H256 ::from ( * a ) ) ) )
2015-12-16 16:39:49 +01:00
}
2018-12-03 16:26:39 +01:00
}
Ok ( account )
2015-12-16 16:39:49 +01:00
}
2018-04-09 16:14:33 +02:00
/// Replace account code and storage. Creates account if it does not exist.
2018-07-02 18:50:05 +02:00
pub fn patch_account ( & self , a : & Address , code : Arc < Bytes > , storage : HashMap < H256 , H256 > ) -> TrieResult < ( ) > {
2018-04-09 16:14:33 +02:00
Ok ( self . require ( a , false ) ? . reset_code_and_storage ( code , storage ) )
}
2015-12-16 16:39:49 +01:00
}
2017-02-26 13:10:50 +01:00
// State proof implementations; useful for light client protocols.
2017-02-21 12:35:21 +01:00
impl < B : Backend > State < B > {
2016-11-15 14:53:30 +01:00
/// Prove an account's existence or nonexistence in the state trie.
2017-03-23 13:17:05 +01:00
/// Returns a merkle proof of the account's trie node omitted or an encountered trie error.
/// If the account doesn't exist in the trie, prove that and return defaults.
2016-11-15 14:53:30 +01:00
/// Requires a secure trie to be used for accurate results.
2017-08-30 19:18:28 +02:00
/// `account_key` == keccak(address)
2018-07-02 18:50:05 +02:00
pub fn prove_account ( & self , account_key : H256 ) -> TrieResult < ( Vec < Bytes > , BasicAccount ) > {
2017-03-23 13:17:05 +01:00
let mut recorder = Recorder ::new ( ) ;
2019-02-20 19:09:34 +01:00
let db = & self . db . as_hash_db ( ) ;
let trie = TrieDB ::new ( db , & self . root ) ? ;
2017-03-23 13:17:05 +01:00
let maybe_account : Option < BasicAccount > = {
2018-05-08 11:22:12 +02:00
let panicky_decoder = | bytes : & [ u8 ] | {
2019-03-06 15:30:35 +01:00
::rlp ::decode ( bytes ) . unwrap_or_else ( | _ | panic! ( " prove_account, could not query trie for account key= {} " , & account_key ) )
2018-05-08 11:22:12 +02:00
} ;
let query = ( & mut recorder , panicky_decoder ) ;
2019-06-03 15:36:21 +02:00
trie . get_with ( account_key . as_bytes ( ) , query ) ?
2017-03-23 13:17:05 +01:00
} ;
let account = maybe_account . unwrap_or_else ( | | BasicAccount {
balance : 0. into ( ) ,
nonce : self . account_start_nonce ,
2017-08-30 19:18:28 +02:00
code_hash : KECCAK_EMPTY ,
storage_root : KECCAK_NULL_RLP ,
2017-03-23 13:17:05 +01:00
} ) ;
2016-11-15 14:53:30 +01:00
2017-03-23 13:17:05 +01:00
Ok ( ( recorder . drain ( ) . into_iter ( ) . map ( | r | r . data ) . collect ( ) , account ) )
2016-11-15 14:53:30 +01:00
}
/// Prove an account's storage key's existence or nonexistence in the state.
2017-03-23 13:17:05 +01:00
/// Returns a merkle proof of the account's storage trie.
/// Requires a secure trie to be used for correctness.
2017-08-30 19:18:28 +02:00
/// `account_key` == keccak(address)
/// `storage_key` == keccak(key)
2018-07-02 18:50:05 +02:00
pub fn prove_storage ( & self , account_key : H256 , storage_key : H256 ) -> TrieResult < ( Vec < Bytes > , H256 ) > {
2016-11-15 14:53:30 +01:00
// TODO: probably could look into cache somehow but it's keyed by
2017-08-30 19:18:28 +02:00
// address, not keccak(address).
2019-02-20 19:09:34 +01:00
let db = & self . db . as_hash_db ( ) ;
let trie = TrieDB ::new ( db , & self . root ) ? ;
2018-05-08 11:22:12 +02:00
let from_rlp = | b : & [ u8 ] | Account ::from_rlp ( b ) . expect ( " decoding db value failed " ) ;
2019-06-03 15:36:21 +02:00
let acc = match trie . get_with ( account_key . as_bytes ( ) , from_rlp ) ? {
2017-01-06 16:18:45 +01:00
Some ( acc ) = > acc ,
2019-06-03 15:36:21 +02:00
None = > return Ok ( ( Vec ::new ( ) , H256 ::zero ( ) ) ) ,
2016-11-15 14:53:30 +01:00
} ;
2019-02-20 19:09:34 +01:00
let account_db = self . factories . accountdb . readonly ( self . db . as_hash_db ( ) , account_key ) ;
acc . prove_storage ( account_db . as_hash_db ( ) , storage_key )
2016-11-15 14:53:30 +01:00
}
}
2017-02-25 14:28:26 +01:00
impl < B : Backend > fmt ::Debug for State < B > {
2016-01-13 01:19:05 +01:00
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
write! ( f , " {:?} " , self . cache . borrow ( ) )
2016-01-11 14:47:50 +01:00
}
}
2019-02-07 14:34:07 +01:00
impl State < StateDB > {
/// Get a reference to the underlying state DB.
pub fn db ( & self ) -> & StateDB {
& self . db
}
}
2017-02-21 12:35:21 +01:00
// TODO: cloning for `State` shouldn't be possible in general; Remove this and use
// checkpoints where possible.
impl Clone for State < StateDB > {
fn clone ( & self ) -> State < StateDB > {
2016-09-21 12:49:11 +02:00
let cache = {
2016-09-27 18:02:11 +02:00
let mut cache : HashMap < Address , AccountEntry > = HashMap ::new ( ) ;
2016-09-21 12:49:11 +02:00
for ( key , val ) in self . cache . borrow ( ) . iter ( ) {
2016-10-06 01:53:23 +02:00
if let Some ( entry ) = val . clone_if_dirty ( ) {
2016-09-27 18:02:11 +02:00
cache . insert ( key . clone ( ) , entry ) ;
2016-09-21 12:49:11 +02:00
}
}
cache
} ;
2016-03-22 13:05:18 +01:00
State {
2016-03-28 10:12:15 +02:00
db : self . db . boxed_clone ( ) ,
2016-03-22 13:05:18 +01:00
root : self . root . clone ( ) ,
2016-09-21 12:49:11 +02:00
cache : RefCell ::new ( cache ) ,
2016-10-22 15:22:16 +02:00
checkpoints : RefCell ::new ( Vec ::new ( ) ) ,
2016-03-22 13:05:18 +01:00
account_start_nonce : self . account_start_nonce . clone ( ) ,
2016-08-24 16:53:36 +02:00
factories : self . factories . clone ( ) ,
2016-03-22 13:05:18 +01:00
}
}
}
2015-12-16 16:39:49 +01:00
#[ cfg(test) ]
mod tests {
2016-11-14 17:47:56 +01:00
use std ::sync ::Arc ;
use std ::str ::FromStr ;
2017-07-06 11:26:14 +02:00
use rustc_hex ::FromHex ;
2018-09-07 12:51:08 +02:00
use hash ::{ keccak , KECCAK_NULL_RLP } ;
2016-11-14 17:47:56 +01:00
use super ::* ;
2017-01-11 12:16:47 +01:00
use ethkey ::Secret ;
2019-06-03 15:36:21 +02:00
use ethereum_types ::{ H256 , U256 , Address , BigEndianHash } ;
2018-04-09 16:14:33 +02:00
use test_helpers ::{ get_temp_state , get_temp_state_db } ;
2017-09-26 14:19:08 +02:00
use machine ::EthereumMachine ;
2017-08-01 12:37:57 +02:00
use vm ::EnvInfo ;
2016-11-14 17:47:56 +01:00
use spec ::* ;
2019-01-04 14:05:46 +01:00
use types ::transaction ::* ;
2016-11-14 17:47:56 +01:00
use trace ::{ FlatTrace , TraceError , trace } ;
2017-07-12 13:09:17 +02:00
use evm ::CallType ;
2016-11-14 17:47:56 +01:00
2017-01-11 12:16:47 +01:00
fn secret ( ) -> Secret {
2017-08-30 19:18:28 +02:00
keccak ( " " ) . into ( )
2017-01-11 12:16:47 +01:00
}
2017-09-26 14:19:08 +02:00
fn make_frontier_machine ( max_depth : usize ) -> EthereumMachine {
let mut machine = ::ethereum ::new_frontier_test_machine ( ) ;
machine . set_schedule_creation_rules ( Box ::new ( move | s , _ | s . max_depth = max_depth ) ) ;
machine
}
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_apply_create_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-11-14 17:47:56 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
action : Action ::Create ,
2016-05-31 16:59:01 +02:00
value : 100. into ( ) ,
2016-11-14 17:47:56 +01:00
data : FromHex ::from_hex ( " 601080600c6000396000f3006000355415600957005b60203560003555 " ) . unwrap ( ) ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 0 ,
action : trace ::Action ::Create ( trace ::Create {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 77412. into ( ) ,
init : vec ! [ 96 , 16 , 128 , 96 , 12 , 96 , 0 , 57 , 96 , 0 , 243 , 0 , 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 , 85 ] ,
} ) ,
result : trace ::Res ::Create ( trace ::CreateResult {
gas_used : U256 ::from ( 3224 ) ,
address : Address ::from_str ( " 8988167e088c87cd314df6d3c2b83da5acb93ace " ) . unwrap ( ) ,
code : vec ! [ 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 ]
} ) ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
2015-12-19 19:00:19 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_work_when_cloned ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-03-27 14:35:27 +02:00
2016-11-14 17:47:56 +01:00
let a = Address ::zero ( ) ;
let mut state = {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . exists ( & a ) . unwrap ( ) , false ) ;
state . inc_nonce ( & a ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
state . clone ( )
} ;
2016-03-27 14:35:27 +02:00
2017-02-26 13:10:50 +01:00
state . inc_nonce ( & a ) . unwrap ( ) ;
2016-08-03 18:35:48 +02:00
state . commit ( ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
}
2016-03-27 14:35:27 +02:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_trace_failed_create_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-03-27 14:35:27 +02:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2016-03-27 14:35:27 +02:00
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
action : Action ::Create ,
2016-05-31 16:59:01 +02:00
value : 100. into ( ) ,
2016-11-14 17:47:56 +01:00
data : FromHex ::from_hex ( " 5b600056 " ) . unwrap ( ) ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
action : trace ::Action ::Create ( trace ::Create {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 78792. into ( ) ,
init : vec ! [ 91 , 96 , 0 , 86 ] ,
} ) ,
result : trace ::Res ::FailedCreate ( TraceError ::OutOfGas ) ,
subtraces : 0
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
2016-03-20 12:04:31 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_trace_call_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-11-14 17:47:56 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2016-03-20 12:04:31 +01:00
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-05-31 16:59:01 +02:00
value : 100. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 6000 " ) . unwrap ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 3 ) ,
output : vec ! [ ]
} ) ,
subtraces : 0 ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
2016-03-20 16:24:19 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_trace_basic_call_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-11-14 17:47:56 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2016-03-20 16:24:19 +01:00
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-05-31 16:59:01 +02:00
value : 100. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-03-21 11:24:03 +01:00
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 0 ) ,
output : vec ! [ ]
} ) ,
subtraces : 0 ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
2016-03-20 17:51:22 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_trace_call_transaction_to_builtin ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-03-20 16:24:19 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = Spec ::new_test_machine ( ) ;
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0x1 ) ) ,
2016-07-28 20:31:29 +02:00
value : 0. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-03-20 19:20:37 +01:00
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_str ( " 0000000000000000000000000000000000000001 " ) . unwrap ( ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 79_000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 3000 ) ,
output : vec ! [ ]
} ) ,
subtraces : 0 ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
#[ test ]
fn should_not_trace_subcall_transaction_to_builtin ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-11-14 17:47:56 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-03-20 19:20:37 +01:00
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = Spec ::new_test_machine ( ) ;
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-05-31 16:59:01 +02:00
value : 0. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 600060006000600060006001610be0f1 " ) . unwrap ( ) ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
2017-09-26 14:19:08 +02:00
gas_used : U256 ::from ( 3_721 ) , // in post-eip150
2016-11-14 17:47:56 +01:00
output : vec ! [ ]
} ) ,
subtraces : 0 ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
#[ test ]
2018-11-26 12:21:55 +01:00
fn should_trace_callcode_properly ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-11-14 17:47:56 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = Spec ::new_test_machine ( ) ;
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-07-28 20:31:29 +02:00
value : 0. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-03-20 19:20:37 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 60006000600060006000600b611000f2 " ) . unwrap ( ) ) . unwrap ( ) ;
state . init_code ( & Address ::from_low_u64_be ( 0xb ) , FromHex ::from_hex ( " 6000 " ) . unwrap ( ) ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-03-20 19:20:37 +01:00
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
2017-09-26 14:19:08 +02:00
gas_used : 724. into ( ) , // in post-eip150
2016-11-14 17:47:56 +01:00
output : vec ! [ ]
} ) ,
} , FlatTrace {
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 0 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_low_u64_be ( 0xa ) ,
to : Address ::from_low_u64_be ( 0xb ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 4096. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::CallCode ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : 3. into ( ) ,
output : vec ! [ ] ,
} ) ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
#[ test ]
2018-01-17 10:44:11 +01:00
fn should_trace_delegatecall_properly ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-11-14 17:47:56 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
info . number = 0x789b0 ;
2017-09-26 14:19:08 +02:00
let machine = Spec ::new_test_machine ( ) ;
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-07-28 20:31:29 +02:00
value : 0. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-03-20 16:24:19 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 6000600060006000600b618000f4 " ) . unwrap ( ) ) . unwrap ( ) ;
state . init_code ( & Address ::from_low_u64_be ( 0xb ) , FromHex ::from_hex ( " 60056000526001601ff3 " ) . unwrap ( ) ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
2018-01-17 10:44:11 +01:00
gas_used : U256 ::from ( 736 ) , // in post-eip150
2016-11-14 17:47:56 +01:00
output : vec ! [ ]
} ) ,
} , FlatTrace {
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 0 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_low_u64_be ( 0xa ) ,
to : Address ::from_low_u64_be ( 0xb ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 32768. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::DelegateCall ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
2018-01-17 10:44:11 +01:00
gas_used : 18. into ( ) ,
output : vec ! [ 5 ] ,
2016-11-14 17:47:56 +01:00
} ) ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
2016-03-21 11:24:03 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_trace_failed_call_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-11-14 17:47:56 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2016-03-21 11:24:03 +01:00
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-05-31 16:59:01 +02:00
value : 100. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 5b600056 " ) . unwrap ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::FailedCall ( TraceError ::OutOfGas ) ,
subtraces : 0 ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
2016-03-21 11:24:03 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_trace_call_with_subcall_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-03-21 11:24:03 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-05-31 16:59:01 +02:00
value : 100. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 60006000600060006000600b602b5a03f1 " ) . unwrap ( ) ) . unwrap ( ) ;
state . init_code ( & Address ::from_low_u64_be ( 0xb ) , FromHex ::from_hex ( " 6000 " ) . unwrap ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 69 ) ,
output : vec ! [ ]
} ) ,
} , FlatTrace {
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 0 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_low_u64_be ( 0xa ) ,
to : Address ::from_low_u64_be ( 0xb ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 78934. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 3 ) ,
output : vec ! [ ]
} ) ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
2016-03-20 16:24:19 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_trace_call_with_basic_subcall_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-11-14 17:47:56 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2016-03-20 16:24:19 +01:00
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-05-31 16:59:01 +02:00
value : 100. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 60006000600060006045600b6000f1 " ) . unwrap ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 31761 ) ,
output : vec ! [ ]
} ) ,
} , FlatTrace {
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 0 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_low_u64_be ( 0xa ) ,
to : Address ::from_low_u64_be ( 0xb ) ,
2016-11-14 17:47:56 +01:00
value : 69. into ( ) ,
gas : 2300. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult ::default ( ) ) ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
#[ test ]
fn should_not_trace_call_with_invalid_basic_subcall_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-03-20 16:24:19 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2016-03-20 16:24:19 +01:00
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-05-31 16:59:01 +02:00
value : 100. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 600060006000600060ff600b6000f1 " ) . unwrap ( ) ) . unwrap ( ) ; // not enough funds.
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 0 ,
2016-04-30 17:41:24 +02:00
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 31761 ) ,
output : vec ! [ ]
} ) ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
2016-03-20 12:04:31 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_trace_failed_subcall_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-11-14 17:47:56 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-03-20 12:04:31 +01:00
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-07-22 14:47:23 +02:00
value : 100. into ( ) ,
2016-11-14 17:47:56 +01:00
data : vec ! [ ] , //600480600b6000396000f35b600056
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 60006000600060006000600b602b5a03f1 " ) . unwrap ( ) ) . unwrap ( ) ;
state . init_code ( & Address ::from_low_u64_be ( 0xb ) , FromHex ::from_hex ( " 5b600056 " ) . unwrap ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 79_000 ) ,
output : vec ! [ ]
} ) ,
} , FlatTrace {
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 0 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_low_u64_be ( 0xa ) ,
to : Address ::from_low_u64_be ( 0xb ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 78934. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::FailedCall ( TraceError ::OutOfGas ) ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
2016-07-22 14:47:23 +02:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_trace_call_with_subcall_with_subcall_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-07-22 14:47:23 +02:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2015-12-19 19:00:19 +01:00
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2015-12-19 19:00:19 +01:00
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 60006000600060006000600b602b5a03f1 " ) . unwrap ( ) ) . unwrap ( ) ;
state . init_code ( & Address ::from_low_u64_be ( 0xb ) , FromHex ::from_hex ( " 60006000600060006000600c602b5a03f1 " ) . unwrap ( ) ) . unwrap ( ) ;
state . init_code ( & Address ::from_low_u64_be ( 0xc ) , FromHex ::from_hex ( " 6000 " ) . unwrap ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 135 ) ,
output : vec ! [ ]
} ) ,
} , FlatTrace {
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_low_u64_be ( 0xa ) ,
to : Address ::from_low_u64_be ( 0xb ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 78934. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 69 ) ,
output : vec ! [ ]
} ) ,
} , FlatTrace {
trace_address : vec ! [ 0 , 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 0 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_low_u64_be ( 0xb ) ,
to : Address ::from_low_u64_be ( 0xc ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 78868. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 3 ) ,
output : vec ! [ ]
} ) ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
#[ test ]
fn should_trace_failed_subcall_with_subcall_transaction ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2016-11-14 17:47:56 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2015-12-19 19:00:19 +01:00
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2015-12-16 16:39:49 +01:00
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
data : vec ! [ ] , //600480600b6000396000f35b600056
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 60006000600060006000600b602b5a03f1 " ) . unwrap ( ) ) . unwrap ( ) ;
state . init_code ( & Address ::from_low_u64_be ( 0xb ) , FromHex ::from_hex ( " 60006000600060006000600c602b5a03f1505b601256 " ) . unwrap ( ) ) . unwrap ( ) ;
state . init_code ( & Address ::from_low_u64_be ( 0xc ) , FromHex ::from_hex ( " 6000 " ) . unwrap ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & ( 100. into ( ) ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 79_000 ) ,
output : vec ! [ ]
} )
} , FlatTrace {
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_low_u64_be ( 0xa ) ,
to : Address ::from_low_u64_be ( 0xb ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 78934. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::FailedCall ( TraceError ::OutOfGas ) ,
} , FlatTrace {
trace_address : vec ! [ 0 , 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 0 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_low_u64_be ( 0xb ) ,
to : Address ::from_low_u64_be ( 0xc ) ,
2016-11-14 17:47:56 +01:00
value : 0. into ( ) ,
gas : 78868. into ( ) ,
call_type : CallType ::Call ,
input : vec ! [ ] ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 3 ) ,
output : vec ! [ ]
} ) ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
#[ test ]
fn should_trace_suicide ( ) {
2019-01-08 15:07:20 +01:00
let _ = env_logger ::try_init ( ) ;
2015-12-16 16:39:49 +01:00
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2015-12-16 20:02:28 +01:00
2016-11-14 17:47:56 +01:00
let mut info = EnvInfo ::default ( ) ;
info . gas_limit = 1_000_000. into ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2015-12-16 18:20:23 +01:00
2016-11-14 17:47:56 +01:00
let t = Transaction {
nonce : 0. into ( ) ,
gas_price : 0. into ( ) ,
gas : 100_000. into ( ) ,
2019-06-03 15:36:21 +02:00
action : Action ::Call ( Address ::from_low_u64_be ( 0xa ) ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
data : vec ! [ ] ,
2017-01-11 12:16:47 +01:00
} . sign ( & secret ( ) , None ) ;
2016-11-14 17:47:56 +01:00
2019-06-03 15:36:21 +02:00
state . init_code ( & Address ::from_low_u64_be ( 0xa ) , FromHex ::from_hex ( " 73000000000000000000000000000000000000000bff " ) . unwrap ( ) ) . unwrap ( ) ;
state . add_balance ( & Address ::from_low_u64_be ( 0xa ) , & 50. into ( ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & t . sender ( ) , & 100. into ( ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-09-26 14:19:08 +02:00
let result = state . apply ( & info , & machine , & t , true ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
2019-06-03 15:36:21 +02:00
from : Address ::from_str ( " 9cce34f7ab185c7aba1b7c8140d620b4bda941d6 " ) . unwrap ( ) ,
to : Address ::from_low_u64_be ( 0xa ) ,
2016-11-14 17:47:56 +01:00
value : 100. into ( ) ,
gas : 79000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : 3. into ( ) ,
output : vec ! [ ]
} ) ,
} , FlatTrace {
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 0 ,
action : trace ::Action ::Suicide ( trace ::Suicide {
2019-06-03 15:36:21 +02:00
address : Address ::from_low_u64_be ( 0xa ) ,
refund_address : Address ::from_low_u64_be ( 0xb ) ,
2016-11-14 17:47:56 +01:00
balance : 150. into ( ) ,
} ) ,
result : trace ::Res ::None ,
} ] ;
assert_eq! ( result . trace , expected_trace ) ;
}
2016-01-09 22:28:31 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn code_from_database ( ) {
let a = Address ::zero ( ) ;
let ( root , db ) = {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2018-09-07 12:51:08 +02:00
state . require_or_from ( & a , false , | | Account ::new_contract ( 42. into ( ) , 0. into ( ) , KECCAK_NULL_RLP ) , | _ | { } ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
state . init_code ( & a , vec! [ 1 , 2 , 3 ] ) . unwrap ( ) ;
2017-06-28 16:41:08 +02:00
assert_eq! ( state . code ( & a ) . unwrap ( ) , Some ( Arc ::new ( vec! [ 1 u8 , 2 , 3 ] ) ) ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2017-06-28 16:41:08 +02:00
assert_eq! ( state . code ( & a ) . unwrap ( ) , Some ( Arc ::new ( vec! [ 1 u8 , 2 , 3 ] ) ) ) ;
2016-11-14 17:47:56 +01:00
state . drop ( )
} ;
2016-11-03 22:22:25 +01:00
2016-11-14 17:47:56 +01:00
let state = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , Default ::default ( ) ) . unwrap ( ) ;
2017-06-28 16:41:08 +02:00
assert_eq! ( state . code ( & a ) . unwrap ( ) , Some ( Arc ::new ( vec! [ 1 u8 , 2 , 3 ] ) ) ) ;
2016-11-14 17:47:56 +01:00
}
2016-10-21 20:36:40 +02:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn storage_at_from_database ( ) {
let a = Address ::zero ( ) ;
let ( root , db ) = {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , BigEndianHash ::from_uint ( & U256 ::from ( 1 u64 ) ) , BigEndianHash ::from_uint ( & U256 ::from ( 69 u64 ) ) ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
state . drop ( )
} ;
let s = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , Default ::default ( ) ) . unwrap ( ) ;
2019-06-03 15:36:21 +02:00
let h1 = BigEndianHash ::from_uint ( & U256 ::from ( 1 u64 ) ) ;
let h2 = BigEndianHash ::from_uint ( & U256 ::from ( 69 u64 ) ) ;
assert_eq! ( s . storage_at ( & a , & h1 ) . unwrap ( ) , h2 ) ;
2016-11-14 17:47:56 +01:00
}
#[ test ]
fn get_from_database ( ) {
let a = Address ::zero ( ) ;
let ( root , db ) = {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2017-02-26 13:10:50 +01:00
state . inc_nonce ( & a ) . unwrap ( ) ;
state . add_balance ( & a , & U256 ::from ( 69 u64 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 69 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . drop ( )
} ;
let state = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , Default ::default ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 69 u64 ) ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 1 u64 ) ) ;
2016-11-14 17:47:56 +01:00
}
2016-01-09 22:28:31 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn remove ( ) {
let a = Address ::zero ( ) ;
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . exists ( & a ) . unwrap ( ) , false ) ;
assert_eq! ( state . exists_and_not_null ( & a ) . unwrap ( ) , false ) ;
state . inc_nonce ( & a ) . unwrap ( ) ;
assert_eq! ( state . exists ( & a ) . unwrap ( ) , true ) ;
assert_eq! ( state . exists_and_not_null ( & a ) . unwrap ( ) , true ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 1 u64 ) ) ;
2016-01-31 10:52:07 +01:00
state . kill_account ( & a ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . exists ( & a ) . unwrap ( ) , false ) ;
assert_eq! ( state . exists_and_not_null ( & a ) . unwrap ( ) , false ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 0 u64 ) ) ;
2016-11-14 17:47:56 +01:00
}
2016-01-09 22:28:31 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn empty_account_is_not_created ( ) {
let a = Address ::zero ( ) ;
2017-04-06 19:26:17 +02:00
let db = get_temp_state_db ( ) ;
2016-11-14 17:47:56 +01:00
let ( root , db ) = {
let mut state = State ::new ( db , U256 ::from ( 0 ) , Default ::default ( ) ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & a , & U256 ::default ( ) , CleanupMode ::NoEmpty ) . unwrap ( ) ; // create an empty account
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
state . drop ( )
} ;
let state = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , Default ::default ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert! ( ! state . exists ( & a ) . unwrap ( ) ) ;
assert! ( ! state . exists_and_not_null ( & a ) . unwrap ( ) ) ;
2016-11-14 17:47:56 +01:00
}
2016-01-09 22:28:31 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn empty_account_exists_when_creation_forced ( ) {
let a = Address ::zero ( ) ;
2017-04-06 19:26:17 +02:00
let db = get_temp_state_db ( ) ;
2016-11-14 17:47:56 +01:00
let ( root , db ) = {
let mut state = State ::new ( db , U256 ::from ( 0 ) , Default ::default ( ) ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & a , & U256 ::default ( ) , CleanupMode ::ForceCreate ) . unwrap ( ) ; // create an empty account
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
state . drop ( )
} ;
let state = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , Default ::default ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert! ( state . exists ( & a ) . unwrap ( ) ) ;
assert! ( ! state . exists_and_not_null ( & a ) . unwrap ( ) ) ;
2016-11-14 17:47:56 +01:00
}
2015-12-16 18:28:04 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn remove_from_database ( ) {
let a = Address ::zero ( ) ;
let ( root , db ) = {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2017-02-26 13:10:50 +01:00
state . inc_nonce ( & a ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . exists ( & a ) . unwrap ( ) , true ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 1 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . drop ( )
} ;
2015-12-16 18:20:23 +01:00
2016-11-14 17:47:56 +01:00
let ( root , db ) = {
let mut state = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , Default ::default ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . exists ( & a ) . unwrap ( ) , true ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 1 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . kill_account ( & a ) ;
state . commit ( ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . exists ( & a ) . unwrap ( ) , false ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 0 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . drop ( )
} ;
2015-12-16 16:39:49 +01:00
2016-11-14 17:47:56 +01:00
let state = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , Default ::default ( ) ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . exists ( & a ) . unwrap ( ) , false ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 0 u64 ) ) ;
2016-11-14 17:47:56 +01:00
}
2015-12-16 16:39:49 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn alter_balance ( ) {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let a = Address ::zero ( ) ;
2019-06-03 15:36:21 +02:00
let b = Address ::from_low_u64_be ( 1 u64 ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & a , & U256 ::from ( 69 u64 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 69 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 69 u64 ) ) ;
2017-06-28 09:10:57 +02:00
state . sub_balance ( & a , & U256 ::from ( 42 u64 ) , & mut CleanupMode ::NoEmpty ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 27 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 27 u64 ) ) ;
state . transfer_balance ( & a , & b , & U256 ::from ( 18 u64 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 9 u64 ) ) ;
assert_eq! ( state . balance ( & b ) . unwrap ( ) , U256 ::from ( 18 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 9 u64 ) ) ;
assert_eq! ( state . balance ( & b ) . unwrap ( ) , U256 ::from ( 18 u64 ) ) ;
2016-11-14 17:47:56 +01:00
}
2016-02-05 12:58:18 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn alter_nonce ( ) {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let a = Address ::zero ( ) ;
2017-02-26 13:10:50 +01:00
state . inc_nonce ( & a ) . unwrap ( ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 1 u64 ) ) ;
state . inc_nonce ( & a ) . unwrap ( ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 2 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 2 u64 ) ) ;
state . inc_nonce ( & a ) . unwrap ( ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 3 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 3 u64 ) ) ;
2016-11-14 17:47:56 +01:00
}
2016-02-05 12:58:18 +01:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn balance_nonce ( ) {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let a = Address ::zero ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 0 u64 ) ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 0 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 0 u64 ) ) ;
assert_eq! ( state . nonce ( & a ) . unwrap ( ) , U256 ::from ( 0 u64 ) ) ;
2016-11-14 17:47:56 +01:00
}
#[ test ]
fn ensure_cached ( ) {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let a = Address ::zero ( ) ;
2017-02-26 13:10:50 +01:00
state . require ( & a , false ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( * state . root ( ) , H256 ::from_str ( " 0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785 " ) . unwrap ( ) ) ;
2016-11-14 17:47:56 +01:00
}
#[ test ]
fn checkpoint_basic ( ) {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let a = Address ::zero ( ) ;
state . checkpoint ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & a , & U256 ::from ( 69 u64 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 69 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . discard_checkpoint ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 69 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . checkpoint ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & a , & U256 ::from ( 1 u64 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 70 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . revert_to_checkpoint ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 69 u64 ) ) ;
2016-11-14 17:47:56 +01:00
}
#[ test ]
fn checkpoint_nested ( ) {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
let a = Address ::zero ( ) ;
state . checkpoint ( ) ;
state . checkpoint ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & a , & U256 ::from ( 69 u64 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 69 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . discard_checkpoint ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 69 u64 ) ) ;
2016-11-14 17:47:56 +01:00
state . revert_to_checkpoint ( ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & a ) . unwrap ( ) , U256 ::from ( 0 ) ) ;
2016-11-14 17:47:56 +01:00
}
2015-12-16 16:39:49 +01:00
2018-09-07 12:51:08 +02:00
#[ test ]
fn checkpoint_revert_to_get_storage_at ( ) {
let mut state = get_temp_state ( ) ;
let a = Address ::zero ( ) ;
2019-06-03 15:36:21 +02:00
let k = BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ;
2018-09-07 12:51:08 +02:00
let c0 = state . checkpoint ( ) ;
let c1 = state . checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) . unwrap ( ) ;
2018-09-07 12:51:08 +02:00
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . storage_at ( & a , & k ) . unwrap ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ;
2018-09-07 12:51:08 +02:00
state . revert_to_checkpoint ( ) ; // Revert to c1.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . storage_at ( & a , & k ) . unwrap ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ;
2018-09-07 12:51:08 +02:00
}
#[ test ]
fn checkpoint_from_empty_get_storage_at ( ) {
let mut state = get_temp_state ( ) ;
let a = Address ::zero ( ) ;
2019-06-03 15:36:21 +02:00
let k = BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ;
let k2 = BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ;
2018-09-07 12:51:08 +02:00
2019-06-03 15:36:21 +02:00
assert_eq! ( state . storage_at ( & a , & k ) . unwrap ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ;
2018-09-07 12:51:08 +02:00
state . clear ( ) ;
let c0 = state . checkpoint ( ) ;
state . new_contract ( & a , U256 ::zero ( ) , U256 ::zero ( ) ) . unwrap ( ) ;
let c1 = state . checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) . unwrap ( ) ;
2018-09-07 12:51:08 +02:00
let c2 = state . checkpoint ( ) ;
let c3 = state . checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k2 , BigEndianHash ::from_uint ( & U256 ::from ( 3 ) ) ) . unwrap ( ) ;
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 3 ) ) ) . unwrap ( ) ;
2018-09-07 12:51:08 +02:00
let c4 = state . checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 4 ) ) ) . unwrap ( ) ;
2018-09-07 12:51:08 +02:00
let c5 = state . checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c2 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c3 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c4 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 3 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c5 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 4 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
state . discard_checkpoint ( ) ; // Commit/discard c5.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c2 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c3 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c4 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 3 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
state . revert_to_checkpoint ( ) ; // Revert to c4.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c2 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c3 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
state . discard_checkpoint ( ) ; // Commit/discard c3.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c2 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
state . revert_to_checkpoint ( ) ; // Revert to c2.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
state . discard_checkpoint ( ) ; // Commit/discard c1.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
}
#[ test ]
fn checkpoint_get_storage_at ( ) {
let mut state = get_temp_state ( ) ;
let a = Address ::zero ( ) ;
2019-06-03 15:36:21 +02:00
let k = BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ;
let k2 = BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ;
2018-09-07 12:51:08 +02:00
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) . unwrap ( ) ;
2018-09-07 12:51:08 +02:00
state . commit ( ) . unwrap ( ) ;
state . clear ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( state . storage_at ( & a , & k ) . unwrap ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ;
2018-09-07 12:51:08 +02:00
state . clear ( ) ;
let cm1 = state . checkpoint ( ) ;
let c0 = state . checkpoint ( ) ;
state . new_contract ( & a , U256 ::zero ( ) , U256 ::zero ( ) ) . unwrap ( ) ;
let c1 = state . checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) . unwrap ( ) ;
2018-09-07 12:51:08 +02:00
let c2 = state . checkpoint ( ) ;
let c3 = state . checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k2 , BigEndianHash ::from_uint ( & U256 ::from ( 3 ) ) ) . unwrap ( ) ;
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 3 ) ) ) . unwrap ( ) ;
2018-09-07 12:51:08 +02:00
let c4 = state . checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 4 ) ) ) . unwrap ( ) ;
2018-09-07 12:51:08 +02:00
let c5 = state . checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( cm1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c2 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c3 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c4 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 3 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c5 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 4 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
state . discard_checkpoint ( ) ; // Commit/discard c5.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( cm1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c2 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c3 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c4 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 3 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
state . revert_to_checkpoint ( ) ; // Revert to c4.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( cm1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c2 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c3 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
state . discard_checkpoint ( ) ; // Commit/discard c3.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( cm1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c2 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
state . revert_to_checkpoint ( ) ; // Revert to c2.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( cm1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ) ;
2018-09-07 12:51:08 +02:00
state . discard_checkpoint ( ) ; // Commit/discard c1.
2019-06-03 15:36:21 +02:00
assert_eq! ( state . checkpoint_storage_at ( cm1 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
assert_eq! ( state . checkpoint_storage_at ( c0 , & a , & k ) . unwrap ( ) , Some ( BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ) ;
2018-09-07 12:51:08 +02:00
}
#[ test ]
fn kill_account_with_checkpoints ( ) {
let mut state = get_temp_state ( ) ;
let a = Address ::zero ( ) ;
2019-06-03 15:36:21 +02:00
let k = BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ;
2018-09-07 12:51:08 +02:00
state . checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) . unwrap ( ) ;
2018-09-07 12:51:08 +02:00
state . checkpoint ( ) ;
state . kill_account ( & a ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( state . storage_at ( & a , & k ) . unwrap ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ;
2018-09-07 12:51:08 +02:00
state . revert_to_checkpoint ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( state . storage_at ( & a , & k ) . unwrap ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 1 ) ) ) ;
2018-09-07 12:51:08 +02:00
}
2018-09-11 10:28:31 +02:00
#[ test ]
fn create_contract_fail ( ) {
let mut state = get_temp_state ( ) ;
let orig_root = state . root ( ) . clone ( ) ;
2019-06-03 15:36:21 +02:00
let a = Address ::from_low_u64_be ( 1000 ) ;
2018-09-11 10:28:31 +02:00
state . checkpoint ( ) ; // c1
state . new_contract ( & a , U256 ::zero ( ) , U256 ::zero ( ) ) . unwrap ( ) ;
state . add_balance ( & a , & U256 ::from ( 1 ) , CleanupMode ::ForceCreate ) . unwrap ( ) ;
state . checkpoint ( ) ; // c2
state . add_balance ( & a , & U256 ::from ( 1 ) , CleanupMode ::ForceCreate ) . unwrap ( ) ;
state . discard_checkpoint ( ) ; // discard c2
state . revert_to_checkpoint ( ) ; // revert to c1
assert_eq! ( state . exists ( & a ) . unwrap ( ) , false ) ;
state . commit ( ) . unwrap ( ) ;
assert_eq! ( orig_root , state . root ( ) . clone ( ) ) ;
}
2018-09-12 12:42:09 +02:00
#[ test ]
fn create_contract_fail_previous_storage ( ) {
let mut state = get_temp_state ( ) ;
2019-06-03 15:36:21 +02:00
let a = Address ::from_low_u64_be ( 1000 ) ;
let k = BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ;
2018-09-12 12:42:09 +02:00
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) . unwrap ( ) ;
2018-09-12 12:42:09 +02:00
state . commit ( ) . unwrap ( ) ;
state . clear ( ) ;
let orig_root = state . root ( ) . clone ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( state . storage_at ( & a , & k ) . unwrap ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ;
2018-09-12 12:42:09 +02:00
state . clear ( ) ;
state . checkpoint ( ) ; // c1
state . new_contract ( & a , U256 ::zero ( ) , U256 ::zero ( ) ) . unwrap ( ) ;
state . checkpoint ( ) ; // c2
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , k , BigEndianHash ::from_uint ( & U256 ::from ( 2 ) ) ) . unwrap ( ) ;
2018-09-12 12:42:09 +02:00
state . revert_to_checkpoint ( ) ; // revert to c2
2019-06-03 15:36:21 +02:00
assert_eq! ( state . storage_at ( & a , & k ) . unwrap ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 0 ) ) ) ;
2018-09-12 12:42:09 +02:00
state . revert_to_checkpoint ( ) ; // revert to c1
2019-06-03 15:36:21 +02:00
assert_eq! ( state . storage_at ( & a , & k ) . unwrap ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 0xffff ) ) ) ;
2018-09-12 12:42:09 +02:00
state . commit ( ) . unwrap ( ) ;
assert_eq! ( orig_root , state . root ( ) . clone ( ) ) ;
}
2016-11-14 17:47:56 +01:00
#[ test ]
fn create_empty ( ) {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2016-11-14 17:47:56 +01:00
state . commit ( ) . unwrap ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( * state . root ( ) , H256 ::from_str ( " 56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421 " ) . unwrap ( ) ) ;
2016-11-14 17:47:56 +01:00
}
2016-10-13 23:28:56 +02:00
2016-11-14 17:47:56 +01:00
#[ test ]
fn should_not_panic_on_state_diff_with_storage ( ) {
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2019-06-03 15:36:21 +02:00
let a = Address ::from_low_u64_be ( 0xa ) ;
2017-06-28 16:41:08 +02:00
state . init_code ( & a , b " abcdefg " . to_vec ( ) ) . unwrap ( ) ; ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & a , & 256. into ( ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , H256 ::from_low_u64_be ( 0xb ) , H256 ::from_low_u64_be ( 0xc ) . into ( ) ) . unwrap ( ) ;
2016-10-13 23:28:56 +02:00
2016-11-14 17:47:56 +01:00
let mut new_state = state . clone ( ) ;
2019-06-03 15:36:21 +02:00
new_state . set_storage ( & a , H256 ::from_low_u64_be ( 0xb ) , H256 ::from_low_u64_be ( 0xd ) . into ( ) ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
2017-02-26 13:10:50 +01:00
new_state . diff_from ( state ) . unwrap ( ) ;
2016-11-14 17:47:56 +01:00
}
2016-10-13 23:28:56 +02:00
2017-06-28 09:10:57 +02:00
#[ test ]
fn should_kill_garbage ( ) {
2019-06-03 15:36:21 +02:00
let a = Address ::from_low_u64_be ( 10 ) ;
let b = Address ::from_low_u64_be ( 20 ) ;
let c = Address ::from_low_u64_be ( 30 ) ;
let d = Address ::from_low_u64_be ( 40 ) ;
let e = Address ::from_low_u64_be ( 50 ) ;
let x = Address ::from_low_u64_be ( 0 ) ;
2017-06-28 09:10:57 +02:00
let db = get_temp_state_db ( ) ;
let ( root , db ) = {
let mut state = State ::new ( db , U256 ::from ( 0 ) , Default ::default ( ) ) ;
state . add_balance ( & a , & U256 ::default ( ) , CleanupMode ::ForceCreate ) . unwrap ( ) ; // create an empty account
state . add_balance ( & b , & 100. into ( ) , CleanupMode ::ForceCreate ) . unwrap ( ) ; // create a dust account
state . add_balance ( & c , & 101. into ( ) , CleanupMode ::ForceCreate ) . unwrap ( ) ; // create a normal account
state . add_balance ( & d , & 99. into ( ) , CleanupMode ::ForceCreate ) . unwrap ( ) ; // create another dust account
2018-09-07 12:51:08 +02:00
state . new_contract ( & e , 100. into ( ) , 1. into ( ) ) . unwrap ( ) ; // create a contract account
2017-06-28 09:10:57 +02:00
state . init_code ( & e , vec! [ 0x00 ] ) . unwrap ( ) ;
state . commit ( ) . unwrap ( ) ;
state . drop ( )
} ;
let mut state = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , Default ::default ( ) ) . unwrap ( ) ;
let mut touched = HashSet ::new ( ) ;
state . add_balance ( & a , & U256 ::default ( ) , CleanupMode ::TrackTouched ( & mut touched ) ) . unwrap ( ) ; // touch an account
state . transfer_balance ( & b , & x , & 1. into ( ) , CleanupMode ::TrackTouched ( & mut touched ) ) . unwrap ( ) ; // touch an account decreasing its balance
state . transfer_balance ( & c , & x , & 1. into ( ) , CleanupMode ::TrackTouched ( & mut touched ) ) . unwrap ( ) ; // touch an account decreasing its balance
state . transfer_balance ( & e , & x , & 1. into ( ) , CleanupMode ::TrackTouched ( & mut touched ) ) . unwrap ( ) ; // touch an account decreasing its balance
state . kill_garbage ( & touched , true , & None , false ) . unwrap ( ) ;
assert! ( ! state . exists ( & a ) . unwrap ( ) ) ;
assert! ( state . exists ( & b ) . unwrap ( ) ) ;
state . kill_garbage ( & touched , true , & Some ( 100. into ( ) ) , false ) . unwrap ( ) ;
assert! ( ! state . exists ( & b ) . unwrap ( ) ) ;
assert! ( state . exists ( & c ) . unwrap ( ) ) ;
assert! ( state . exists ( & d ) . unwrap ( ) ) ;
assert! ( state . exists ( & e ) . unwrap ( ) ) ;
state . kill_garbage ( & touched , true , & Some ( 100. into ( ) ) , true ) . unwrap ( ) ;
assert! ( state . exists ( & c ) . unwrap ( ) ) ;
assert! ( state . exists ( & d ) . unwrap ( ) ) ;
assert! ( ! state . exists ( & e ) . unwrap ( ) ) ;
}
2018-04-04 11:49:43 +02:00
#[ test ]
fn should_trace_diff_suicided_accounts ( ) {
use pod_account ;
2019-06-03 15:36:21 +02:00
let a = Address ::from_low_u64_be ( 10 ) ;
2018-04-04 11:49:43 +02:00
let db = get_temp_state_db ( ) ;
let ( root , db ) = {
let mut state = State ::new ( db , U256 ::from ( 0 ) , Default ::default ( ) ) ;
state . add_balance ( & a , & 100. into ( ) , CleanupMode ::ForceCreate ) . unwrap ( ) ;
state . commit ( ) . unwrap ( ) ;
state . drop ( )
} ;
let mut state = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , Default ::default ( ) ) . unwrap ( ) ;
let original = state . clone ( ) ;
state . kill_account ( & a ) ;
let diff = state . diff_from ( original ) . unwrap ( ) ;
let diff_map = diff . get ( ) ;
assert_eq! ( diff_map . len ( ) , 1 ) ;
assert! ( diff_map . get ( & a ) . is_some ( ) ) ;
assert_eq! ( diff_map . get ( & a ) ,
2018-11-25 20:12:59 +01:00
pod_account ::diff_pod ( Some ( & PodAccount {
balance : U256 ::from ( 100 ) ,
nonce : U256 ::zero ( ) ,
code : Some ( Default ::default ( ) ) ,
storage : Default ::default ( )
} ) , None ) . as_ref ( ) ) ;
2018-04-04 11:49:43 +02:00
}
2018-05-02 16:47:53 +02:00
#[ test ]
fn should_trace_diff_unmodified_storage ( ) {
use pod_account ;
2019-06-03 15:36:21 +02:00
let a = Address ::from_low_u64_be ( 10 ) ;
2018-05-02 16:47:53 +02:00
let db = get_temp_state_db ( ) ;
let ( root , db ) = {
let mut state = State ::new ( db , U256 ::from ( 0 ) , Default ::default ( ) ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , BigEndianHash ::from_uint ( & U256 ::from ( 1 u64 ) ) , BigEndianHash ::from_uint ( & U256 ::from ( 20 u64 ) ) ) . unwrap ( ) ;
2018-05-02 16:47:53 +02:00
state . commit ( ) . unwrap ( ) ;
state . drop ( )
} ;
let mut state = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , Default ::default ( ) ) . unwrap ( ) ;
let original = state . clone ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , BigEndianHash ::from_uint ( & U256 ::from ( 1 u64 ) ) , BigEndianHash ::from_uint ( & U256 ::from ( 100 u64 ) ) ) . unwrap ( ) ;
2018-05-02 16:47:53 +02:00
let diff = state . diff_from ( original ) . unwrap ( ) ;
let diff_map = diff . get ( ) ;
assert_eq! ( diff_map . len ( ) , 1 ) ;
assert! ( diff_map . get ( & a ) . is_some ( ) ) ;
assert_eq! ( diff_map . get ( & a ) ,
2018-11-25 20:12:59 +01:00
pod_account ::diff_pod ( Some ( & PodAccount {
balance : U256 ::zero ( ) ,
nonce : U256 ::zero ( ) ,
code : Some ( Default ::default ( ) ) ,
2019-06-03 15:36:21 +02:00
storage : vec ! [ ( BigEndianHash ::from_uint ( & U256 ::from ( 1 u64 ) ) , BigEndianHash ::from_uint ( & U256 ::from ( 20 u64 ) ) ) ]
2018-11-25 20:12:59 +01:00
. into_iter ( ) . collect ( ) ,
} ) , Some ( & PodAccount {
balance : U256 ::zero ( ) ,
nonce : U256 ::zero ( ) ,
code : Some ( Default ::default ( ) ) ,
2019-06-03 15:36:21 +02:00
storage : vec ! [ ( BigEndianHash ::from_uint ( & U256 ::from ( 1 u64 ) ) , BigEndianHash ::from_uint ( & U256 ::from ( 100 u64 ) ) ) ]
2018-11-25 20:12:59 +01:00
. into_iter ( ) . collect ( ) ,
} ) ) . as_ref ( ) ) ;
}
#[ cfg(feature= " to-pod-full " ) ]
#[ test ]
fn should_get_full_pod_storage_values ( ) {
use trie ::{ TrieFactory , TrieSpec } ;
2019-06-03 15:36:21 +02:00
let a = Address ::from_low_u64_be ( 10 ) ;
2018-11-25 20:12:59 +01:00
let db = get_temp_state_db ( ) ;
let factories = Factories {
vm : Default ::default ( ) ,
trie : TrieFactory ::new ( TrieSpec ::Fat ) ,
accountdb : Default ::default ( ) ,
} ;
let get_pod_state_val = | pod_state : & PodState , ak , k | {
pod_state . get ( ) . get ( ak ) . unwrap ( ) . storage . get ( & k ) . unwrap ( ) . clone ( )
} ;
2019-06-03 15:36:21 +02:00
let storage_address : H256 = BigEndianHash ::from_uint ( & U256 ::from ( 1 u64 ) ) ;
2018-11-25 20:12:59 +01:00
let ( root , db ) = {
let mut state = State ::new ( db , U256 ::from ( 0 ) , factories . clone ( ) ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , storage_address . clone ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 20 u64 ) ) ) . unwrap ( ) ;
2018-11-25 20:12:59 +01:00
let dump = state . to_pod_full ( ) . unwrap ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( get_pod_state_val ( & dump , & a , storage_address . clone ( ) ) , BigEndianHash ::from_uint ( & U256 ::from ( 20 u64 ) ) ) ;
2018-11-25 20:12:59 +01:00
state . commit ( ) . unwrap ( ) ;
let dump = state . to_pod_full ( ) . unwrap ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( get_pod_state_val ( & dump , & a , storage_address . clone ( ) ) , BigEndianHash ::from_uint ( & U256 ::from ( 20 u64 ) ) ) ;
2018-11-25 20:12:59 +01:00
state . drop ( )
} ;
let mut state = State ::from_existing ( db , root , U256 ::from ( 0 u8 ) , factories ) . unwrap ( ) ;
let dump = state . to_pod_full ( ) . unwrap ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( get_pod_state_val ( & dump , & a , storage_address . clone ( ) ) , BigEndianHash ::from_uint ( & U256 ::from ( 20 u64 ) ) ) ;
state . set_storage ( & a , storage_address . clone ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 21 u64 ) ) ) . unwrap ( ) ;
2018-11-25 20:12:59 +01:00
let dump = state . to_pod_full ( ) . unwrap ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( get_pod_state_val ( & dump , & a , storage_address . clone ( ) ) , BigEndianHash ::from_uint ( & U256 ::from ( 21 u64 ) ) ) ;
2018-11-25 20:12:59 +01:00
state . commit ( ) . unwrap ( ) ;
2019-06-03 15:36:21 +02:00
state . set_storage ( & a , storage_address . clone ( ) , BigEndianHash ::from_uint ( & U256 ::from ( 0 u64 ) ) ) . unwrap ( ) ;
2018-11-25 20:12:59 +01:00
let dump = state . to_pod_full ( ) . unwrap ( ) ;
2019-06-03 15:36:21 +02:00
assert_eq! ( get_pod_state_val ( & dump , & a , storage_address . clone ( ) ) , BigEndianHash ::from_uint ( & U256 ::from ( 0 u64 ) ) ) ;
2018-11-25 20:12:59 +01:00
2018-05-02 16:47:53 +02:00
}
2018-11-25 20:12:59 +01:00
2016-08-10 16:29:40 +02:00
}