openethereum/src/account.rs

730 lines
22 KiB
Rust
Raw Normal View History

use util::*;
2016-01-13 18:37:09 +01:00
use itertools::Itertools;
2015-12-13 21:36:17 +01:00
2015-12-13 23:12:22 +01:00
pub const SHA3_EMPTY: H256 = H256( [0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70] );
2015-12-13 21:36:17 +01:00
2016-01-13 15:54:17 +01:00
#[derive(Debug,Clone,PartialEq,Eq)]
2016-01-13 22:35:21 +01:00
pub enum Diff<T> where T: Eq {
Same,
Born(T),
Changed(T, T),
Died(T),
2016-01-13 15:54:17 +01:00
}
2016-01-13 22:35:21 +01:00
#[derive(Debug,Clone,PartialEq,Eq)]
pub enum Existance {
Born,
Alive,
Died,
2016-01-13 15:54:17 +01:00
}
2016-01-13 22:35:21 +01:00
impl<T> Diff<T> where T: Eq {
pub fn new(pre: T, post: T) -> Self { if pre == post { Diff::Same } else { Diff::Changed(pre, post) } }
pub fn pre(&self) -> Option<&T> { match self { &Diff::Died(ref x) | &Diff::Changed(ref x, _) => Some(x), _ => None } }
pub fn post(&self) -> Option<&T> { match self { &Diff::Born(ref x) | &Diff::Changed(_, ref x) => Some(x), _ => None } }
pub fn is_same(&self) -> bool { match self { &Diff::Same => true, _ => false }}
2016-01-13 18:37:09 +01:00
}
2016-01-13 15:54:17 +01:00
#[derive(Debug,Clone,PartialEq,Eq)]
/// Genesis account data. Does not have a DB overlay cache.
pub struct PodAccount {
// Balance of the account.
pub balance: U256,
// Nonce of the account.
pub nonce: U256,
pub code: Bytes,
pub storage: BTreeMap<H256, H256>,
}
2016-01-14 12:27:35 +01:00
impl fmt::Display for PodAccount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(bal={}; nonce={}; code={} bytes, #{}; storage={} items)", self.balance, self.nonce, self.code.len(), self.code.sha3(), self.storage.len())
}
}
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct PodState (BTreeMap<Address, PodAccount>);
pub fn map_h256_h256_from_json(json: &Json) -> BTreeMap<H256, H256> {
json.as_object().unwrap().iter().fold(BTreeMap::new(), |mut m, (key, value)| {
m.insert(H256::from(&u256_from_str(key)), H256::from(&u256_from_json(value)));
m
})
}
impl PodState {
/// Contruct a new object from the `m`.
pub fn from(m: BTreeMap<Address, PodAccount>) -> PodState { PodState(m) }
/// Translate the JSON object into a hash map of account information ready for insertion into State.
pub fn from_json(json: &Json) -> PodState {
PodState(json.as_object().unwrap().iter().fold(BTreeMap::new(), |mut state, (address, acc)| {
let balance = acc.find("balance").map(&u256_from_json);
let nonce = acc.find("nonce").map(&u256_from_json);
let storage = acc.find("storage").map(&map_h256_h256_from_json);;
let code = acc.find("code").map(&bytes_from_json);
if balance.is_some() || nonce.is_some() || storage.is_some() || code.is_some() {
state.insert(address_from_hex(address), PodAccount{
balance: balance.unwrap_or(U256::zero()),
nonce: nonce.unwrap_or(U256::zero()),
storage: storage.unwrap_or(BTreeMap::new()),
code: code.unwrap_or(Vec::new())
});
}
state
}))
}
/// Drain object to get the underlying map.
pub fn drain(self) -> BTreeMap<Address, PodAccount> { self.0 }
}
impl fmt::Display for PodState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (add, acc) in &self.0 {
try!(writeln!(f, "{} => {}", add, acc));
}
Ok(())
}
}
2016-01-13 15:54:17 +01:00
#[derive(Debug,Clone,PartialEq,Eq)]
2016-01-13 18:37:09 +01:00
pub struct AccountDiff {
2016-01-13 22:35:21 +01:00
pub balance: Diff<U256>, // Allowed to be Same
pub nonce: Diff<U256>, // Allowed to be Same
pub code: Diff<Bytes>, // Allowed to be Same
pub storage: BTreeMap<H256, Diff<H256>>,// Not allowed to be Same
2016-01-13 15:54:17 +01:00
}
2016-01-13 22:35:21 +01:00
impl AccountDiff {
pub fn existance(&self) -> Existance {
match self.balance {
Diff::Born(_) => Existance::Born,
Diff::Died(_) => Existance::Died,
_ => Existance::Alive,
}
}
}
2016-01-14 01:29:05 +01:00
fn format(u: &H256) -> String {
if u <= &H256::from(0xffffffff) {
format!("{} = 0x{:x}", U256::from(u.as_slice()).low_u32(), U256::from(u.as_slice()).low_u32())
} else if u <= &H256::from(u64::max_value()) {
format!("{} = 0x{:x}", U256::from(u.as_slice()).low_u64(), U256::from(u.as_slice()).low_u64())
// } else if u <= &H256::from("0xffffffffffffffffffffffffffffffffffffffff") {
// format!("@{}", Address::from(u))
} else {
format!("#{}", u)
}
}
2016-01-13 23:53:00 +01:00
#[derive(Debug,Clone,PartialEq,Eq)]
pub struct StateDiff (BTreeMap<Address, AccountDiff>);
impl fmt::Display for AccountDiff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2016-01-14 00:27:36 +01:00
match self.nonce {
2016-01-14 01:29:05 +01:00
Diff::Born(ref x) => try!(write!(f, " non {}", x)),
2016-01-14 00:27:36 +01:00
Diff::Changed(ref pre, ref post) => try!(write!(f, "#{} ({} {} {})", post, pre, if pre > post {"-"} else {"+"}, *max(pre, post) - * min(pre, post))),
_ => {},
}
match self.balance {
2016-01-14 01:29:05 +01:00
Diff::Born(ref x) => try!(write!(f, " bal {}", x)),
2016-01-14 00:27:36 +01:00
Diff::Changed(ref pre, ref post) => try!(write!(f, "${} ({} {} {})", post, pre, if pre > post {"-"} else {"+"}, *max(pre, post) - *min(pre, post))),
_ => {},
}
match self.code {
2016-01-14 01:29:05 +01:00
Diff::Born(ref x) => try!(write!(f, " code {}", x.pretty())),
2016-01-14 00:27:36 +01:00
_ => {},
}
try!(write!(f, "\n"));
for (k, dv) in self.storage.iter() {
match dv {
2016-01-14 01:29:05 +01:00
&Diff::Born(ref v) => try!(write!(f, " + {} => {}\n", format(k), format(v))),
&Diff::Changed(ref pre, ref post) => try!(write!(f, " * {} => {} (was {})\n", format(k), format(post), format(pre))),
&Diff::Died(_) => try!(write!(f, " X {}\n", format(k))),
2016-01-14 00:27:36 +01:00
_ => {},
}
}
Ok(())
2016-01-13 23:53:00 +01:00
}
}
impl fmt::Display for Existance {
2016-01-13 22:35:21 +01:00
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2016-01-13 23:53:00 +01:00
match self {
&Existance::Born => try!(write!(f, "+++")),
&Existance::Alive => try!(write!(f, "***")),
2016-01-14 00:27:36 +01:00
&Existance::Died => try!(write!(f, "XXX")),
2016-01-13 23:53:00 +01:00
}
Ok(())
2016-01-13 22:35:21 +01:00
}
2016-01-13 23:53:00 +01:00
}
2016-01-13 22:35:21 +01:00
2016-01-13 23:53:00 +01:00
impl fmt::Display for StateDiff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (add, acc) in self.0.iter() {
try!(write!(f, "{} {}: {}", acc.existance(), add, acc));
}
Ok(())
}
}
2016-01-13 15:54:17 +01:00
2016-01-13 18:37:09 +01:00
pub fn pod_diff(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<AccountDiff> {
2016-01-13 15:54:17 +01:00
match (pre, post) {
2016-01-13 22:35:21 +01:00
(None, Some(x)) => Some(AccountDiff {
balance: Diff::Born(x.balance.clone()),
nonce: Diff::Born(x.nonce.clone()),
code: Diff::Born(x.code.clone()),
storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Born(v.clone()))).collect(),
}),
(Some(x), None) => Some(AccountDiff {
balance: Diff::Died(x.balance.clone()),
nonce: Diff::Died(x.nonce.clone()),
code: Diff::Died(x.code.clone()),
storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Died(v.clone()))).collect(),
2016-01-13 15:54:17 +01:00
}),
2016-01-13 18:37:09 +01:00
(Some(pre), Some(post)) => {
let storage: Vec<_> = pre.storage.keys().merge(post.storage.keys())
2016-01-13 15:54:17 +01:00
.filter(|k| pre.storage.get(k).unwrap_or(&H256::new()) != post.storage.get(k).unwrap_or(&H256::new()))
.collect();
2016-01-13 22:35:21 +01:00
let r = AccountDiff {
balance: Diff::new(pre.balance.clone(), post.balance.clone()),
nonce: Diff::new(pre.nonce.clone(), post.nonce.clone()),
code: Diff::new(pre.code.clone(), post.code.clone()),
storage: storage.into_iter().map(|k|
(k.clone(), Diff::new(
pre.storage.get(&k).cloned().unwrap_or(H256::new()),
post.storage.get(&k).cloned().unwrap_or(H256::new())
))).collect(),
};
if r.balance.is_same() && r.nonce.is_same() && r.code.is_same() && r.storage.len() == 0 {
2016-01-13 15:54:17 +01:00
None
2016-01-13 22:35:21 +01:00
} else {
Some(r)
2016-01-13 15:54:17 +01:00
}
},
_ => None,
}
}
2016-01-14 12:27:35 +01:00
pub fn pod_state_diff(pre: &PodState, post: &PodState) -> StateDiff {
StateDiff(pre.0.keys().merge(post.0.keys()).filter_map(|acc| pod_diff(pre.0.get(acc), post.0.get(acc)).map(|d|(acc.clone(), d))).collect())
2016-01-13 18:37:09 +01:00
}
#[test]
fn state_diff_create_delete() {
2016-01-14 12:27:35 +01:00
let a = PodState(map![
2016-01-13 18:37:09 +01:00
x!(1) => PodAccount{
balance: x!(69),
nonce: x!(0),
code: vec![],
storage: map![]
}
2016-01-14 12:27:35 +01:00
]);
assert_eq!(pod_state_diff(&a, &PodState(map![])), StateDiff(map![
2016-01-13 18:37:09 +01:00
x!(1) => AccountDiff{
2016-01-13 22:35:21 +01:00
balance: Diff::Died(x!(69)),
nonce: Diff::Died(x!(0)),
code: Diff::Died(vec![]),
2016-01-13 18:37:09 +01:00
storage: map![],
}
2016-01-13 23:53:00 +01:00
]));
2016-01-14 12:27:35 +01:00
assert_eq!(pod_state_diff(&PodState(map![]), &a), StateDiff(map![
2016-01-13 18:37:09 +01:00
x!(1) => AccountDiff{
2016-01-13 22:35:21 +01:00
balance: Diff::Born(x!(69)),
nonce: Diff::Born(x!(0)),
code: Diff::Born(vec![]),
2016-01-13 18:37:09 +01:00
storage: map![],
}
2016-01-13 23:53:00 +01:00
]));
2016-01-13 18:37:09 +01:00
}
#[test]
fn state_diff_cretae_delete_with_unchanged() {
2016-01-14 12:27:35 +01:00
let a = PodState(map![
2016-01-13 18:37:09 +01:00
x!(1) => PodAccount{
balance: x!(69),
nonce: x!(0),
code: vec![],
storage: map![]
}
2016-01-14 12:27:35 +01:00
]);
let b = PodState(map![
2016-01-13 18:37:09 +01:00
x!(1) => PodAccount{
balance: x!(69),
nonce: x!(0),
code: vec![],
storage: map![]
},
x!(2) => PodAccount{
balance: x!(69),
nonce: x!(0),
code: vec![],
storage: map![]
}
2016-01-14 12:27:35 +01:00
]);
assert_eq!(pod_state_diff(&a, &b), StateDiff(map![
2016-01-13 18:37:09 +01:00
x!(2) => AccountDiff{
2016-01-13 22:35:21 +01:00
balance: Diff::Born(x!(69)),
nonce: Diff::Born(x!(0)),
code: Diff::Born(vec![]),
2016-01-13 18:37:09 +01:00
storage: map![],
}
2016-01-13 23:53:00 +01:00
]));
2016-01-14 12:27:35 +01:00
assert_eq!(pod_state_diff(&b, &a), StateDiff(map![
2016-01-13 18:37:09 +01:00
x!(2) => AccountDiff{
2016-01-13 22:35:21 +01:00
balance: Diff::Died(x!(69)),
nonce: Diff::Died(x!(0)),
code: Diff::Died(vec![]),
2016-01-13 18:37:09 +01:00
storage: map![],
}
2016-01-13 23:53:00 +01:00
]));
2016-01-13 18:37:09 +01:00
}
#[test]
fn state_diff_change_with_unchanged() {
2016-01-14 12:27:35 +01:00
let a = PodState(map![
2016-01-13 18:37:09 +01:00
x!(1) => PodAccount{
balance: x!(69),
nonce: x!(0),
code: vec![],
storage: map![]
},
x!(2) => PodAccount{
balance: x!(69),
nonce: x!(0),
code: vec![],
storage: map![]
}
2016-01-14 12:27:35 +01:00
]);
let b = PodState(map![
2016-01-13 18:37:09 +01:00
x!(1) => PodAccount{
balance: x!(69),
nonce: x!(1),
code: vec![],
storage: map![]
},
x!(2) => PodAccount{
balance: x!(69),
nonce: x!(0),
code: vec![],
storage: map![]
}
2016-01-14 12:27:35 +01:00
]);
assert_eq!(pod_state_diff(&a, &b), StateDiff(map![
2016-01-13 18:37:09 +01:00
x!(1) => AccountDiff{
2016-01-13 22:35:21 +01:00
balance: Diff::Same,
nonce: Diff::Changed(x!(0), x!(1)),
code: Diff::Same,
2016-01-13 18:37:09 +01:00
storage: map![],
}
2016-01-13 23:53:00 +01:00
]));
2016-01-13 18:37:09 +01:00
}
2016-01-13 15:54:17 +01:00
#[test]
fn account_diff_existence() {
2016-01-13 18:37:09 +01:00
let a = PodAccount{balance: x!(69), nonce: x!(0), code: vec![], storage: map![]};
assert_eq!(pod_diff(Some(&a), Some(&a)), None);
assert_eq!(pod_diff(None, Some(&a)), Some(AccountDiff{
2016-01-13 22:35:21 +01:00
balance: Diff::Born(x!(69)),
nonce: Diff::Born(x!(0)),
code: Diff::Born(vec![]),
2016-01-13 18:37:09 +01:00
storage: map![],
2016-01-13 15:54:17 +01:00
}));
}
#[test]
fn account_diff_basic() {
2016-01-13 22:45:46 +01:00
let a = PodAccount{balance: x!(69), nonce: x!(0), code: vec![], storage: map![]};
let b = PodAccount{balance: x!(42), nonce: x!(1), code: vec![], storage: map![]};
2016-01-13 18:37:09 +01:00
assert_eq!(pod_diff(Some(&a), Some(&b)), Some(AccountDiff {
2016-01-13 22:45:46 +01:00
balance: Diff::Changed(x!(69), x!(42)),
nonce: Diff::Changed(x!(0), x!(1)),
2016-01-13 22:35:21 +01:00
code: Diff::Same,
2016-01-13 22:45:46 +01:00
storage: map![],
2016-01-13 15:54:17 +01:00
}));
}
#[test]
fn account_diff_code() {
2016-01-13 22:45:46 +01:00
let a = PodAccount{balance: x!(0), nonce: x!(0), code: vec![], storage: map![]};
let b = PodAccount{balance: x!(0), nonce: x!(1), code: vec![0], storage: map![]};
2016-01-13 18:37:09 +01:00
assert_eq!(pod_diff(Some(&a), Some(&b)), Some(AccountDiff {
2016-01-13 22:35:21 +01:00
balance: Diff::Same,
2016-01-13 22:45:46 +01:00
nonce: Diff::Changed(x!(0), x!(1)),
code: Diff::Changed(vec![], vec![0]),
storage: map![],
2016-01-13 15:54:17 +01:00
}));
}
#[test]
fn account_diff_storage() {
2016-01-13 22:45:46 +01:00
let a = PodAccount {
balance: x!(0),
nonce: x!(0),
code: vec![],
storage: mapx![1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 0, 6 => 0, 7 => 0]
};
let b = PodAccount {
balance: x!(0),
nonce: x!(0),
code: vec![],
storage: mapx![1 => 1, 2 => 3, 3 => 0, 5 => 0, 7 => 7, 8 => 0, 9 => 9]
};
2016-01-13 18:37:09 +01:00
assert_eq!(pod_diff(Some(&a), Some(&b)), Some(AccountDiff {
2016-01-13 22:35:21 +01:00
balance: Diff::Same,
nonce: Diff::Same,
code: Diff::Same,
storage: map![
2016-01-13 22:45:46 +01:00
x!(2) => Diff::new(x!(2), x!(3)),
x!(3) => Diff::new(x!(3), x!(0)),
x!(4) => Diff::new(x!(4), x!(0)),
x!(7) => Diff::new(x!(0), x!(7)),
x!(9) => Diff::new(x!(0), x!(9))
2016-01-13 22:35:21 +01:00
],
2016-01-13 15:54:17 +01:00
}));
}
/// Single account in the system.
#[derive(Clone)]
2015-12-13 21:36:17 +01:00
pub struct Account {
2015-12-13 23:12:22 +01:00
// Balance of the account.
2015-12-13 21:36:17 +01:00
balance: U256,
2015-12-13 23:12:22 +01:00
// Nonce of the account.
2015-12-13 21:36:17 +01:00
nonce: U256,
// Trie-backed storage.
storage_root: H256,
// Overlay on trie-backed storage.
storage_overlay: RefCell<HashMap<H256, H256>>,
2015-12-13 23:12:22 +01:00
// Code hash of the account. If None, means that it's a contract whose code has not yet been set.
code_hash: Option<H256>,
// Code cache of the account.
code_cache: Bytes,
2015-12-13 21:36:17 +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 {
balance: acc.balance.clone(),
nonce: acc.nonce.clone(),
storage: acc.storage_overlay.borrow().iter().fold(BTreeMap::new(), |mut m, (k, v)| {m.insert(k.clone(), v.clone()); m}),
code: acc.code_cache.clone()
}
}
pub fn rlp(&self) -> Bytes {
let mut stream = RlpStream::new_list(4);
stream.append(&self.nonce);
stream.append(&self.balance);
// TODO.
stream.append(&SHA3_NULL_RLP);
stream.append(&self.code.sha3());
stream.out()
}
}
2015-12-13 21:36:17 +01:00
impl Account {
2015-12-13 23:12:22 +01:00
/// General constructor.
pub fn new(balance: U256, nonce: U256, storage: HashMap<H256, H256>, code: Bytes) -> Account {
Account {
balance: balance,
nonce: nonce,
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(storage),
code_hash: Some(code.sha3()),
2015-12-13 23:12:22 +01:00
code_cache: code
}
}
/// General constructor.
pub fn from_pod(pod: PodAccount) -> Account {
Account {
balance: pod.balance,
nonce: pod.nonce,
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(pod.storage.into_iter().fold(HashMap::new(), |mut m, (k, v)| {m.insert(k, v); m})),
code_hash: Some(pod.code.sha3()),
code_cache: pod.code
}
}
2015-12-13 23:12:22 +01:00
/// Create a new account with the given balance.
2015-12-19 22:15:22 +01:00
pub fn new_basic(balance: U256, nonce: U256) -> Account {
2015-12-13 23:12:22 +01:00
Account {
balance: balance,
2015-12-19 22:15:22 +01:00
nonce: nonce,
2015-12-13 23:12:22 +01:00
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(HashMap::new()),
2015-12-13 23:12:22 +01:00
code_hash: Some(SHA3_EMPTY),
code_cache: vec![],
}
}
/// Create a new account from RLP.
pub fn from_rlp(rlp: &[u8]) -> Account {
let r: Rlp = Rlp::new(rlp);
2015-12-13 21:36:17 +01:00
Account {
nonce: r.val_at(0),
balance: r.val_at(1),
storage_root: r.val_at(2),
storage_overlay: RefCell::new(HashMap::new()),
code_hash: Some(r.val_at(3)),
2015-12-13 23:12:22 +01:00
code_cache: vec![],
2015-12-13 21:36:17 +01:00
}
}
/// Create a new contract account.
/// NOTE: make sure you use `init_code` on this before `commit`ing.
pub fn new_contract(balance: U256) -> Account {
2015-12-13 21:36:17 +01:00
Account {
balance: balance,
2015-12-13 21:36:17 +01:00
nonce: U256::from(0u8),
storage_root: SHA3_NULL_RLP,
storage_overlay: RefCell::new(HashMap::new()),
code_hash: None,
2015-12-13 23:12:22 +01:00
code_cache: vec![],
2015-12-13 21:36:17 +01:00
}
}
2016-01-09 14:19:35 +01:00
/// Reset this account to the status of a not-yet-initialised contract.
/// NOTE: Account should have `init_code()` called on it later.
pub fn reset_code(&mut self) {
self.code_hash = None;
self.code_cache = vec![];
}
2015-12-13 23:12:22 +01:00
/// Set this account's code to the given code.
2016-01-09 14:19:35 +01:00
/// NOTE: Account should have been created with `new_contract()` or have `reset_code()` called on it.
pub fn init_code(&mut self, code: Bytes) {
2015-12-13 23:12:22 +01:00
assert!(self.code_hash.is_none());
self.code_cache = code;
}
/// Set (and cache) the contents of the trie's storage at `key` to `value`.
pub fn set_storage(&mut self, key: H256, value: H256) {
self.storage_overlay.borrow_mut().insert(key, value);
}
/// Get (and cache) the contents of the trie's storage at `key`.
pub fn storage_at(&self, db: &HashDB, key: &H256) -> H256 {
self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{
2016-01-14 02:09:43 +01:00
H256::from_slice(SecTrieDB::new(db, &self.storage_root).get(key.bytes()).unwrap_or(&[0u8;32][..]))
}).clone()
}
2015-12-13 23:12:22 +01:00
/// return the balance associated with this account.
2015-12-13 21:36:17 +01:00
pub fn balance(&self) -> &U256 { &self.balance }
2015-12-15 13:09:50 +01:00
2015-12-13 23:12:22 +01:00
/// return the nonce associated with this account.
2015-12-13 21:36:17 +01:00
pub fn nonce(&self) -> &U256 { &self.nonce }
2015-12-15 13:09:50 +01:00
2015-12-13 23:12:22 +01:00
/// return the code hash associated with this account.
pub fn code_hash(&self) -> H256 {
self.code_hash.clone().unwrap_or(SHA3_EMPTY)
2015-12-13 21:36:17 +01:00
}
2015-12-15 13:09:50 +01:00
/// returns the account's code. If `None` then the code cache isn't available -
/// get someone who knows to call `note_code`.
pub fn code(&self) -> Option<&[u8]> {
match self.code_hash {
Some(SHA3_EMPTY) | None if self.code_cache.is_empty() => Some(&self.code_cache),
Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache),
None => Some(&self.code_cache),
_ => None,
}
}
/// Provide a byte array which hashes to the `code_hash`. returns the hash as a result.
pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> {
let h = code.sha3();
match self.code_hash {
Some(ref i) if h == *i => {
self.code_cache = code;
Ok(())
},
_ => Err(h)
}
}
/// Is `code_cache` valid; such that code is going to return Some?
pub fn is_cached(&self) -> bool {
!self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == Some(SHA3_EMPTY))
}
/// Provide a database to lookup `code_hash`. Should not be called if it is a contract without code.
pub fn cache_code(&mut self, db: &HashDB) -> bool {
// TODO: fill out self.code_cache;
/* return !self.is_cached() ||
match db.lookup(&self.code_hash.unwrap()) { // why doesn't this work? unwrap causes move?!
Some(x) => { self.code_cache = x.to_vec(); true },
_ => { false }
}*/
if self.is_cached() { return true; }
return if let Some(ref h) = self.code_hash {
match db.lookup(&h) {
Some(x) => { self.code_cache = x.to_vec(); true },
_ => { false }
}
} else { false }
}
2015-12-13 23:12:22 +01:00
/// return the storage root associated with this account.
pub fn base_root(&self) -> &H256 { &self.storage_root }
2015-12-15 13:09:50 +01:00
/// return the storage root associated with this account or None if it has been altered via the overlay.
pub fn storage_root(&self) -> Option<&H256> { if self.storage_overlay.borrow().is_empty() {Some(&self.storage_root)} else {None} }
2015-12-15 13:09:50 +01:00
/// rturn the storage overlay.
pub fn storage_overlay(&self) -> Ref<HashMap<H256, H256>> { self.storage_overlay.borrow() }
/// Increment the nonce of the account by one.
pub fn inc_nonce(&mut self) { self.nonce = self.nonce + U256::from(1u8); }
/// Increment the nonce of the account by one.
pub fn add_balance(&mut self, x: &U256) { self.balance = self.balance + *x; }
/// Increment the nonce of the account by one.
pub fn sub_balance(&mut self, x: &U256) { self.balance = self.balance - *x; }
2015-12-13 21:36:17 +01:00
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, db: &mut HashDB) {
2016-01-14 02:09:43 +01:00
let mut t = SecTrieDBMut::new(db, &mut self.storage_root);
for (k, v) in self.storage_overlay.borrow().iter() {
2015-12-13 21:36:17 +01:00
// cast key and value to trait type,
// so we can call overloaded `to_bytes` method
2016-01-14 02:09:43 +01:00
t.insert(k, &encode(&U256::from(v.as_slice())));
2015-12-13 21:36:17 +01:00
}
2016-01-14 02:09:43 +01:00
// self.storage_overlay.borrow_mut().clear();
2015-12-13 21:36:17 +01:00
}
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
2015-12-13 21:36:17 +01:00
pub fn commit_code(&mut self, db: &mut HashDB) {
2016-01-13 15:54:17 +01:00
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_hash.is_none(), self.code_cache.is_empty());
match (self.code_hash.is_none(), self.code_cache.is_empty()) {
(true, true) => self.code_hash = Some(SHA3_EMPTY),
(true, false) => {
println!("Writing into DB {:?}", self.code_cache);
self.code_hash = Some(db.insert(&self.code_cache));
},
(false, _) => {},
2015-12-13 21:36:17 +01:00
}
2015-12-13 23:12:22 +01:00
}
2015-12-13 21:49:40 +01:00
2015-12-13 23:12:22 +01:00
/// Export to RLP.
pub fn rlp(&self) -> Bytes {
let mut stream = RlpStream::new_list(4);
stream.append(&self.nonce);
stream.append(&self.balance);
stream.append(&self.storage_root);
stream.append(self.code_hash.as_ref().expect("Cannot form RLP of contract account without code."));
stream.out()
2015-12-13 21:36:17 +01:00
}
}
impl fmt::Debug for Account {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", PodAccount::from_account(self))
}
}
2015-12-15 13:09:50 +01:00
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
use util::hash::*;
use util::bytes::*;
use util::rlp::*;
use util::uint::*;
use util::overlaydb::*;
#[test]
fn storage_at() {
let mut db = OverlayDB::new_temp();
let rlp = {
let mut a = Account::new_contract(U256::from(69u8));
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
a.commit_storage(&mut db);
a.init_code(vec![]);
a.commit_code(&mut db);
a.rlp()
};
let a = Account::from_rlp(&rlp);
assert_eq!(a.storage_root().unwrap().hex(), "3541f181d6dad5c504371884684d08c29a8bad04926f8ceddf5e279dbc3cc769");
assert_eq!(a.storage_at(&mut db, &H256::from(&U256::from(0x00u64))), H256::from(&U256::from(0x1234u64)));
assert_eq!(a.storage_at(&mut db, &H256::from(&U256::from(0x01u64))), H256::new());
}
#[test]
fn note_code() {
let mut db = OverlayDB::new_temp();
let rlp = {
let mut a = Account::new_contract(U256::from(69u8));
a.init_code(vec![0x55, 0x44, 0xffu8]);
a.commit_code(&mut db);
a.rlp()
};
let mut a = Account::from_rlp(&rlp);
assert_eq!(a.cache_code(&db), true);
let mut a = Account::from_rlp(&rlp);
assert_eq!(a.note_code(vec![0x55, 0x44, 0xffu8]), Ok(()));
}
2015-12-15 13:09:50 +01:00
#[test]
fn commit_storage() {
let mut a = Account::new_contract(U256::from(69u8));
let mut db = OverlayDB::new_temp();
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
assert_eq!(a.storage_root(), None);
2015-12-15 13:09:50 +01:00
a.commit_storage(&mut db);
assert_eq!(a.storage_root().unwrap().hex(), "3541f181d6dad5c504371884684d08c29a8bad04926f8ceddf5e279dbc3cc769");
}
#[test]
fn commit_code() {
let mut a = Account::new_contract(U256::from(69u8));
let mut db = OverlayDB::new_temp();
a.init_code(vec![0x55, 0x44, 0xffu8]);
assert_eq!(a.code_hash(), SHA3_EMPTY);
a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
}
2015-12-15 13:09:50 +01:00
#[test]
fn rlpio() {
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
let b = Account::from_rlp(&a.rlp());
assert_eq!(a.balance(), b.balance());
assert_eq!(a.nonce(), b.nonce());
assert_eq!(a.code_hash(), b.code_hash());
assert_eq!(a.storage_root(), b.storage_root());
}
#[test]
fn new_account() {
2015-12-14 12:09:32 +01:00
use rustc_serialize::hex::ToHex;
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
assert_eq!(a.balance(), &U256::from(69u8));
assert_eq!(a.nonce(), &U256::from(0u8));
assert_eq!(a.code_hash(), SHA3_EMPTY);
assert_eq!(a.storage_root().unwrap(), &SHA3_NULL_RLP);
}
#[test]
fn create_account() {
2015-12-14 12:09:32 +01:00
use rustc_serialize::hex::ToHex;
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
}
2015-12-15 13:09:50 +01:00
}