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
2018-09-27 17:17:23 +02:00
//! Account system expressed in Plain Old Data.
2017-07-29 17:12:07 +02:00
use std ::collections ::BTreeMap ;
2017-08-17 16:05:26 +02:00
use itertools ::Itertools ;
2017-08-30 19:18:28 +02:00
use hash ::{ keccak } ;
2019-06-03 15:36:21 +02:00
use ethereum_types ::{ H256 , U256 , BigEndianHash } ;
2019-02-20 19:09:34 +01:00
use hash_db ::HashDB ;
2018-10-09 22:07:25 +02:00
use kvdb ::DBValue ;
2018-07-02 18:50:05 +02:00
use keccak_hasher ::KeccakHasher ;
2017-09-03 09:11:14 +02:00
use triehash ::sec_trie_root ;
2017-09-06 20:47:45 +02:00
use bytes ::Bytes ;
use trie ::TrieFactory ;
2018-07-02 18:50:05 +02:00
use ethtrie ::RlpCodec ;
2016-08-18 15:24:27 +02:00
use state ::Account ;
2016-03-17 15:51:40 +01:00
use ethjson ;
2016-05-31 21:03:44 +02:00
use types ::account_diff ::* ;
2017-03-20 19:14:29 +01:00
use rlp ::{ self , RlpStream } ;
2018-11-25 20:12:59 +01:00
use serde ::Serializer ;
use rustc_hex ::ToHex ;
2016-01-14 16:46:32 +01:00
2018-11-25 20:12:59 +01:00
#[ derive(Debug, Clone, PartialEq, Eq, Serialize) ]
2016-02-03 13:20:32 +01:00
/// An account, expressed as Plain-Old-Data (hence the name).
/// Does not have a DB overlay cache, code hash or anything like that.
2016-01-14 16:46:32 +01:00
pub struct PodAccount {
2016-02-03 13:20:32 +01:00
/// The balance of the account.
2016-01-14 16:46:32 +01:00
pub balance : U256 ,
2016-02-03 13:20:32 +01:00
/// The nonce of the account.
2016-01-14 16:46:32 +01:00
pub nonce : U256 ,
2018-11-25 20:12:59 +01:00
#[ serde(serialize_with= " opt_bytes_to_hex " ) ]
2016-07-26 16:48:50 +02:00
/// The code of the account or `None` in the special case that it is unknown.
pub code : Option < Bytes > ,
2016-02-03 13:20:32 +01:00
/// The storage of the account.
2016-01-14 16:46:32 +01:00
pub storage : BTreeMap < H256 , H256 > ,
}
2018-11-25 20:12:59 +01:00
fn opt_bytes_to_hex < S > ( opt_bytes : & Option < Bytes > , serializer : S ) -> Result < S ::Ok , S ::Error >
where S : Serializer
{
2019-07-03 10:57:50 +02:00
let readable = opt_bytes . as_ref ( ) . map ( | b | b . to_hex ( ) ) . unwrap_or_default ( ) ;
serializer . collect_str ( & format_args! ( " 0x {} " , readable ) )
2018-11-25 20:12:59 +01:00
}
2016-01-14 16:46:32 +01:00
impl PodAccount {
/// Convert Account to a PodAccount.
/// NOTE: This will silently fail unless the account is fully cached.
pub fn from_account ( acc : & Account ) -> PodAccount {
PodAccount {
2016-02-14 12:54:27 +01:00
balance : * acc . balance ( ) ,
nonce : * acc . nonce ( ) ,
2016-09-27 18:02:11 +02:00
storage : acc . storage_changes ( ) . iter ( ) . fold ( BTreeMap ::new ( ) , | mut m , ( k , v ) | { m . insert ( k . clone ( ) , v . clone ( ) ) ; m } ) ,
2016-07-26 16:48:50 +02:00
code : acc . code ( ) . map ( | x | x . to_vec ( ) ) ,
2016-01-14 16:46:32 +01:00
}
}
2016-01-26 15:00:22 +01:00
/// Returns the RLP for this account.
2016-01-14 16:46:32 +01:00
pub fn rlp ( & self ) -> Bytes {
let mut stream = RlpStream ::new_list ( 4 ) ;
stream . append ( & self . nonce ) ;
stream . append ( & self . balance ) ;
2019-06-03 15:36:21 +02:00
stream . append ( & sec_trie_root ( self . storage . iter ( ) . map ( | ( k , v ) | ( k , rlp ::encode ( & v . into_uint ( ) ) ) ) ) ) ;
2017-08-30 19:18:28 +02:00
stream . append ( & keccak ( & self . code . as_ref ( ) . unwrap_or ( & vec! [ ] ) ) ) ;
2016-01-14 16:46:32 +01:00
stream . out ( )
}
2016-01-26 15:00:22 +01:00
/// Place additional data into given hash DB.
2019-06-14 18:48:35 +02:00
pub fn insert_additional ( & self , db : & mut dyn HashDB < KeccakHasher , DBValue > , factory : & TrieFactory < KeccakHasher , RlpCodec > ) {
2016-07-26 16:48:50 +02:00
match self . code {
2019-06-19 13:54:05 +02:00
Some ( ref c ) if ! c . is_empty ( ) = > { db . insert ( hash_db ::EMPTY_PREFIX , c ) ; }
2016-07-26 16:48:50 +02:00
_ = > { }
2016-01-26 15:00:22 +01:00
}
2019-06-03 15:36:21 +02:00
let mut r = H256 ::zero ( ) ;
2016-11-27 11:11:56 +01:00
let mut t = factory . create ( db , & mut r ) ;
2016-01-26 15:00:22 +01:00
for ( k , v ) in & self . storage {
2019-06-03 15:36:21 +02:00
if let Err ( e ) = t . insert ( k . as_bytes ( ) , & rlp ::encode ( & v . into_uint ( ) ) ) {
2016-08-03 18:35:48 +02:00
warn! ( " Encountered potential DB corruption: {} " , e ) ;
}
2016-01-26 15:00:22 +01:00
}
}
2016-01-14 16:46:32 +01:00
}
2016-03-17 15:51:40 +01:00
impl From < ethjson ::blockchain ::Account > for PodAccount {
fn from ( a : ethjson ::blockchain ::Account ) -> Self {
PodAccount {
balance : a . balance . into ( ) ,
nonce : a . nonce . into ( ) ,
2016-07-26 16:48:50 +02:00
code : Some ( a . code . into ( ) ) ,
2016-04-09 19:20:35 +02:00
storage : a . storage . into_iter ( ) . map ( | ( key , value ) | {
2016-03-17 15:51:40 +01:00
let key : U256 = key . into ( ) ;
2016-03-19 11:02:44 +01:00
let value : U256 = value . into ( ) ;
2019-06-03 15:36:21 +02:00
( BigEndianHash ::from_uint ( & key ) , BigEndianHash ::from_uint ( & value ) )
2016-11-13 13:58:42 +01:00
} ) . collect ( ) ,
2016-04-09 19:20:35 +02:00
}
}
}
impl From < ethjson ::spec ::Account > for PodAccount {
fn from ( a : ethjson ::spec ::Account ) -> Self {
PodAccount {
balance : a . balance . map_or_else ( U256 ::zero , Into ::into ) ,
nonce : a . nonce . map_or_else ( U256 ::zero , Into ::into ) ,
2016-11-13 13:58:42 +01:00
code : Some ( a . code . map_or_else ( Vec ::new , Into ::into ) ) ,
storage : a . storage . map_or_else ( BTreeMap ::new , | s | s . into_iter ( ) . map ( | ( key , value ) | {
let key : U256 = key . into ( ) ;
let value : U256 = value . into ( ) ;
2019-06-03 15:36:21 +02:00
( BigEndianHash ::from_uint ( & key ) , BigEndianHash ::from_uint ( & value ) )
2016-11-13 13:58:42 +01:00
} ) . collect ( ) ) ,
2016-03-17 15:51:40 +01:00
}
}
}
2016-05-31 21:03:44 +02:00
/// Determine difference between two optionally existant `Account`s. Returns None
/// if they are the same.
pub fn diff_pod ( pre : Option < & PodAccount > , post : Option < & PodAccount > ) -> Option < AccountDiff > {
match ( pre , post ) {
( None , Some ( x ) ) = > Some ( AccountDiff {
balance : Diff ::Born ( x . balance ) ,
nonce : Diff ::Born ( x . nonce ) ,
2016-07-26 16:48:50 +02:00
code : Diff ::Born ( x . code . as_ref ( ) . expect ( " account is newly created; newly created accounts must be given code; all caches should remain in place; qed " ) . clone ( ) ) ,
2016-05-31 21:03:44 +02:00
storage : x . storage . iter ( ) . map ( | ( k , v ) | ( k . clone ( ) , Diff ::Born ( v . clone ( ) ) ) ) . collect ( ) ,
} ) ,
( Some ( x ) , None ) = > Some ( AccountDiff {
balance : Diff ::Died ( x . balance ) ,
nonce : Diff ::Died ( x . nonce ) ,
2016-07-26 16:48:50 +02:00
code : Diff ::Died ( x . code . as_ref ( ) . expect ( " account is deleted; only way to delete account is running SUICIDE; account must have had own code cached to make operation; all caches should remain in place; qed " ) . clone ( ) ) ,
2016-05-31 21:03:44 +02:00
storage : x . storage . iter ( ) . map ( | ( k , v ) | ( k . clone ( ) , Diff ::Died ( v . clone ( ) ) ) ) . collect ( ) ,
} ) ,
( Some ( pre ) , Some ( post ) ) = > {
let storage : Vec < _ > = pre . storage . keys ( ) . merge ( post . storage . keys ( ) )
2019-06-03 15:36:21 +02:00
. filter ( | k | pre . storage . get ( k ) . unwrap_or ( & H256 ::zero ( ) ) ! = post . storage . get ( k ) . unwrap_or ( & H256 ::zero ( ) ) )
2016-05-31 21:03:44 +02:00
. collect ( ) ;
let r = AccountDiff {
balance : Diff ::new ( pre . balance , post . balance ) ,
nonce : Diff ::new ( pre . nonce , post . nonce ) ,
2016-07-26 16:48:50 +02:00
code : match ( pre . code . clone ( ) , post . code . clone ( ) ) {
( Some ( pre_code ) , Some ( post_code ) ) = > Diff ::new ( pre_code , post_code ) ,
_ = > Diff ::Same ,
} ,
2016-05-31 21:03:44 +02:00
storage : storage . into_iter ( ) . map ( | k |
( k . clone ( ) , Diff ::new (
2019-06-03 15:36:21 +02:00
pre . storage . get ( k ) . cloned ( ) . unwrap_or_else ( H256 ::zero ) ,
post . storage . get ( k ) . cloned ( ) . unwrap_or_else ( H256 ::zero )
2016-05-31 21:03:44 +02:00
) ) ) . collect ( ) ,
} ;
if r . balance . is_same ( ) & & r . nonce . is_same ( ) & & r . code . is_same ( ) & & r . storage . is_empty ( ) {
None
} else {
Some ( r )
}
} ,
_ = > None ,
}
}
2016-01-14 16:46:32 +01:00
#[ cfg(test) ]
mod test {
2017-07-29 17:12:07 +02:00
use std ::collections ::BTreeMap ;
2016-05-31 21:03:44 +02:00
use types ::account_diff ::* ;
2016-06-02 12:28:09 +02:00
use super ::{ PodAccount , diff_pod } ;
2019-06-03 15:36:21 +02:00
use ethereum_types ::H256 ;
2016-01-14 16:46:32 +01:00
#[ test ]
fn existence ( ) {
2016-07-26 16:48:50 +02:00
let a = PodAccount { balance : 69. into ( ) , nonce : 0. into ( ) , code : Some ( vec! [ ] ) , storage : map ! [ ] } ;
2016-05-31 21:03:44 +02:00
assert_eq! ( diff_pod ( Some ( & a ) , Some ( & a ) ) , None ) ;
assert_eq! ( diff_pod ( None , Some ( & a ) ) , Some ( AccountDiff {
2016-05-31 16:59:01 +02:00
balance : Diff ::Born ( 69. into ( ) ) ,
nonce : Diff ::Born ( 0. into ( ) ) ,
2016-01-14 16:46:32 +01:00
code : Diff ::Born ( vec! [ ] ) ,
storage : map ! [ ] ,
} ) ) ;
}
#[ test ]
fn basic ( ) {
2016-07-26 16:48:50 +02:00
let a = PodAccount { balance : 69. into ( ) , nonce : 0. into ( ) , code : Some ( vec! [ ] ) , storage : map ! [ ] } ;
let b = PodAccount { balance : 42. into ( ) , nonce : 1. into ( ) , code : Some ( vec! [ ] ) , storage : map ! [ ] } ;
2016-05-31 21:03:44 +02:00
assert_eq! ( diff_pod ( Some ( & a ) , Some ( & b ) ) , Some ( AccountDiff {
2016-05-31 16:59:01 +02:00
balance : Diff ::Changed ( 69. into ( ) , 42. into ( ) ) ,
nonce : Diff ::Changed ( 0. into ( ) , 1. into ( ) ) ,
2016-01-14 16:46:32 +01:00
code : Diff ::Same ,
storage : map ! [ ] ,
} ) ) ;
}
#[ test ]
fn code ( ) {
2016-07-26 16:48:50 +02:00
let a = PodAccount { balance : 0. into ( ) , nonce : 0. into ( ) , code : Some ( vec! [ ] ) , storage : map ! [ ] } ;
let b = PodAccount { balance : 0. into ( ) , nonce : 1. into ( ) , code : Some ( vec! [ 0 ] ) , storage : map ! [ ] } ;
2016-05-31 21:03:44 +02:00
assert_eq! ( diff_pod ( Some ( & a ) , Some ( & b ) ) , Some ( AccountDiff {
2016-01-14 16:46:32 +01:00
balance : Diff ::Same ,
2016-05-31 16:59:01 +02:00
nonce : Diff ::Changed ( 0. into ( ) , 1. into ( ) ) ,
2016-01-14 16:46:32 +01:00
code : Diff ::Changed ( vec! [ ] , vec! [ 0 ] ) ,
storage : map ! [ ] ,
} ) ) ;
}
#[ test ]
fn storage ( ) {
let a = PodAccount {
2016-05-31 16:59:01 +02:00
balance : 0. into ( ) ,
nonce : 0. into ( ) ,
2016-07-26 16:48:50 +02:00
code : Some ( vec! [ ] ) ,
2019-06-03 15:36:21 +02:00
storage : map ! [
H256 ::from_low_u64_be ( 1 ) = > H256 ::from_low_u64_be ( 1 ) ,
H256 ::from_low_u64_be ( 2 ) = > H256 ::from_low_u64_be ( 2 ) ,
H256 ::from_low_u64_be ( 3 ) = > H256 ::from_low_u64_be ( 3 ) ,
H256 ::from_low_u64_be ( 4 ) = > H256 ::from_low_u64_be ( 4 ) ,
H256 ::from_low_u64_be ( 5 ) = > H256 ::from_low_u64_be ( 0 ) ,
H256 ::from_low_u64_be ( 6 ) = > H256 ::from_low_u64_be ( 0 ) ,
H256 ::from_low_u64_be ( 7 ) = > H256 ::from_low_u64_be ( 0 )
] ,
2016-01-14 16:46:32 +01:00
} ;
let b = PodAccount {
2016-05-31 16:59:01 +02:00
balance : 0. into ( ) ,
nonce : 0. into ( ) ,
2016-07-26 16:48:50 +02:00
code : Some ( vec! [ ] ) ,
2019-06-03 15:36:21 +02:00
storage : map ! [
H256 ::from_low_u64_be ( 1 ) = > H256 ::from_low_u64_be ( 1 ) ,
H256 ::from_low_u64_be ( 2 ) = > H256 ::from_low_u64_be ( 3 ) ,
H256 ::from_low_u64_be ( 3 ) = > H256 ::from_low_u64_be ( 0 ) ,
H256 ::from_low_u64_be ( 5 ) = > H256 ::from_low_u64_be ( 0 ) ,
H256 ::from_low_u64_be ( 7 ) = > H256 ::from_low_u64_be ( 7 ) ,
H256 ::from_low_u64_be ( 8 ) = > H256 ::from_low_u64_be ( 0 ) ,
H256 ::from_low_u64_be ( 9 ) = > H256 ::from_low_u64_be ( 9 )
]
2016-01-14 16:46:32 +01:00
} ;
2016-05-31 21:03:44 +02:00
assert_eq! ( diff_pod ( Some ( & a ) , Some ( & b ) ) , Some ( AccountDiff {
2016-01-14 16:46:32 +01:00
balance : Diff ::Same ,
nonce : Diff ::Same ,
code : Diff ::Same ,
storage : map ! [
2019-06-03 15:36:21 +02:00
H256 ::from_low_u64_be ( 2 ) = > Diff ::new ( H256 ::from_low_u64_be ( 2 ) , H256 ::from_low_u64_be ( 3 ) ) ,
H256 ::from_low_u64_be ( 3 ) = > Diff ::new ( H256 ::from_low_u64_be ( 3 ) , H256 ::from_low_u64_be ( 0 ) ) ,
H256 ::from_low_u64_be ( 4 ) = > Diff ::new ( H256 ::from_low_u64_be ( 4 ) , H256 ::from_low_u64_be ( 0 ) ) ,
H256 ::from_low_u64_be ( 7 ) = > Diff ::new ( H256 ::from_low_u64_be ( 0 ) , H256 ::from_low_u64_be ( 7 ) ) ,
H256 ::from_low_u64_be ( 9 ) = > Diff ::new ( H256 ::from_low_u64_be ( 0 ) , H256 ::from_low_u64_be ( 9 ) )
2016-01-14 16:46:32 +01:00
] ,
} ) ) ;
}
}