openethereum/crates/ethcore/types/src/account_diff.rs

196 lines
5.8 KiB
Rust

// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum is free software: you can redistribute it and/or modify
// 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.
// OpenEthereum is distributed in the hope that it will be useful,
// 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
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Diff between two accounts.
use crate::bytes::Bytes;
use ethereum_types::{H256, U256};
use std::{cmp::*, collections::BTreeMap, fmt};
#[derive(Debug, PartialEq, Eq, Clone)]
/// Diff type for specifying a change (or not).
pub enum Diff<T> {
/// Both sides are the same.
Same,
/// Left (pre, source) side doesn't include value, right side (post, destination) does.
Born(T),
/// Both sides include data; it chaged value between them.
Changed(T, T),
/// Left (pre, source) side does include value, right side (post, destination) does not.
Died(T),
}
impl<T> Diff<T> {
/// Construct new object with given `pre` and `post`.
pub fn new(pre: T, post: T) -> Self
where
T: Eq,
{
if pre == post {
Diff::Same
} else {
Diff::Changed(pre, post)
}
}
/// Get the before value, if there is one.
pub fn pre(&self) -> Option<&T> {
match *self {
Diff::Died(ref x) | Diff::Changed(ref x, _) => Some(x),
_ => None,
}
}
/// Get the after value, if there is one.
pub fn post(&self) -> Option<&T> {
match *self {
Diff::Born(ref x) | Diff::Changed(_, ref x) => Some(x),
_ => None,
}
}
/// Determine whether there was a change or not.
pub fn is_same(&self) -> bool {
match *self {
Diff::Same => true,
_ => false,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
/// Account diff.
pub struct AccountDiff {
/// Change in balance, allowed to be `Diff::Same`.
pub balance: Diff<U256>,
/// Change in nonce, allowed to be `Diff::Same`.
pub nonce: Diff<U256>, // Allowed to be Same
/// Change in code, allowed to be `Diff::Same`.
pub code: Diff<Bytes>, // Allowed to be Same
/// Change in storage, values are not allowed to be `Diff::Same`.
pub storage: BTreeMap<H256, Diff<H256>>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
/// Change in existance type.
// TODO: include other types of change.
pub enum Existance {
/// Item came into existance.
Born,
/// Item stayed in existance.
Alive,
/// Item went out of existance.
Died,
}
impl fmt::Display for Existance {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Existance::Born => write!(f, "+++")?,
Existance::Alive => write!(f, "***")?,
Existance::Died => write!(f, "XXX")?,
}
Ok(())
}
}
impl AccountDiff {
/// Get `Existance` projection.
pub fn existance(&self) -> Existance {
match self.balance {
Diff::Born(_) => Existance::Born,
Diff::Died(_) => Existance::Died,
_ => Existance::Alive,
}
}
}
// TODO: refactor into something nicer.
fn interpreted_hash(u: &H256) -> String {
if u <= &H256::from_low_u64_be(0xffffffff) {
format!(
"{} = 0x{:x}",
U256::from(u.as_bytes()).low_u32(),
U256::from(u.as_bytes()).low_u32()
)
} else if u <= &H256::from_low_u64_be(u64::max_value()) {
format!(
"{} = 0x{:x}",
U256::from(u.as_bytes()).low_u64(),
U256::from(u.as_bytes()).low_u64()
)
// } else if u <= &H256::from("0xffffffffffffffffffffffffffffffffffffffff") {
// format!("@{}", Address::from(u))
} else {
format!("#{}", u)
}
}
impl fmt::Display for AccountDiff {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use crate::bytes::ToPretty;
match self.nonce {
Diff::Born(ref x) => write!(f, " non {}", x)?,
Diff::Changed(ref pre, ref post) => write!(
f,
"#{} ({} {} {})",
post,
pre,
if pre > post { "-" } else { "+" },
*max(pre, post) - *min(pre, post)
)?,
_ => {}
}
match self.balance {
Diff::Born(ref x) => write!(f, " bal {}", x)?,
Diff::Changed(ref pre, ref post) => write!(
f,
"${} ({} {} {})",
post,
pre,
if pre > post { "-" } else { "+" },
*max(pre, post) - *min(pre, post)
)?,
_ => {}
}
if let Diff::Born(ref x) = self.code {
write!(f, " code {}", x.pretty())?;
}
write!(f, "\n")?;
for (k, dv) in &self.storage {
match *dv {
Diff::Born(ref v) => write!(
f,
" + {} => {}\n",
interpreted_hash(k),
interpreted_hash(v)
)?,
Diff::Changed(ref pre, ref post) => write!(
f,
" * {} => {} (was {})\n",
interpreted_hash(k),
interpreted_hash(post),
interpreted_hash(pre)
)?,
Diff::Died(_) => write!(f, " X {}\n", interpreted_hash(k))?,
_ => {}
}
}
Ok(())
}
}