Merge pull request #98 from gavofyork/gav
State conensus tests now print mismatching diff on fail.
This commit is contained in:
commit
b87e0fce64
@ -18,6 +18,7 @@ rust-crypto = "0.2.34"
|
|||||||
time = "0.1"
|
time = "0.1"
|
||||||
#interpolate_idents = { git = "https://github.com/SkylerLipthay/interpolate_idents" }
|
#interpolate_idents = { git = "https://github.com/SkylerLipthay/interpolate_idents" }
|
||||||
evmjit = { path = "rust-evmjit", optional = true }
|
evmjit = { path = "rust-evmjit", optional = true }
|
||||||
|
itertools = "0.4"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["jit"]
|
default = ["jit"]
|
||||||
|
276
src/account.rs
276
src/account.rs
@ -1,8 +1,32 @@
|
|||||||
use util::*;
|
use util::*;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
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] );
|
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] );
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug,Clone,PartialEq,Eq)]
|
||||||
|
pub struct Diff<T> where T: Eq {
|
||||||
|
pub pre: T,
|
||||||
|
pub post_opt: Option<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Diff<T> where T: Eq {
|
||||||
|
pub fn new_opt(pre: T, post: T) -> Option<Self> { if pre == post { None } else { Some(Self::new(pre, post)) } }
|
||||||
|
pub fn one_opt(t: T) -> Option<Self> { Some(Self::one(t)) }
|
||||||
|
|
||||||
|
pub fn new(pre: T, post: T) -> Self { Diff { pre: pre, post_opt: Some(post) }}
|
||||||
|
pub fn one(t: T) -> Self { Diff { pre: t, post_opt: None }}
|
||||||
|
|
||||||
|
pub fn pre(&self) -> &T { &self.pre }
|
||||||
|
pub fn post(&self) -> &T { match self.post_opt { Some(ref x) => x, None => &self.pre } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for Diff<T> where T: Eq {
|
||||||
|
fn from(t: T) -> Diff<T> {
|
||||||
|
Diff::one(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,Clone,PartialEq,Eq)]
|
||||||
/// Genesis account data. Does not have a DB overlay cache.
|
/// Genesis account data. Does not have a DB overlay cache.
|
||||||
pub struct PodAccount {
|
pub struct PodAccount {
|
||||||
// Balance of the account.
|
// Balance of the account.
|
||||||
@ -13,6 +37,254 @@ pub struct PodAccount {
|
|||||||
pub storage: BTreeMap<H256, H256>,
|
pub storage: BTreeMap<H256, H256>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug,Clone,PartialEq,Eq)]
|
||||||
|
pub struct AccountDiff {
|
||||||
|
pub exists: Diff<bool>,
|
||||||
|
pub balance: Option<Diff<U256>>,
|
||||||
|
pub nonce: Option<Diff<U256>>,
|
||||||
|
pub code: Option<Diff<Bytes>>,
|
||||||
|
pub storage: BTreeMap<H256, Diff<H256>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type StateDiff = BTreeMap<Address, AccountDiff>;
|
||||||
|
|
||||||
|
pub fn pod_diff(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<AccountDiff> {
|
||||||
|
match (pre, post) {
|
||||||
|
(Some(x), None) | (None, Some(x)) => Some(AccountDiff {
|
||||||
|
exists: Diff::new(pre.is_some(), post.is_some()),
|
||||||
|
balance: Diff::one_opt(x.balance.clone()),
|
||||||
|
nonce: Diff::one_opt(x.nonce.clone()),
|
||||||
|
code: Diff::one_opt(x.code.clone()),
|
||||||
|
storage: x.storage.iter().fold(BTreeMap::new(), |mut m, (k, v)| {m.insert(k.clone(), Diff::one(v.clone())); m})
|
||||||
|
}),
|
||||||
|
(Some(pre), Some(post)) => {
|
||||||
|
let storage: Vec<_> = pre.storage.keys().merge(post.storage.keys())
|
||||||
|
.filter(|k| pre.storage.get(k).unwrap_or(&H256::new()) != post.storage.get(k).unwrap_or(&H256::new()))
|
||||||
|
.collect();
|
||||||
|
if pre.balance != post.balance || pre.nonce != post.nonce || pre.code != post.code || storage.len() > 0 {
|
||||||
|
Some(AccountDiff {
|
||||||
|
exists: Diff::one(true),
|
||||||
|
balance: Diff::new_opt(pre.balance.clone(), post.balance.clone()),
|
||||||
|
nonce: Diff::new_opt(pre.nonce.clone(), post.nonce.clone()),
|
||||||
|
code: Diff::new_opt(pre.code.clone(), post.code.clone()),
|
||||||
|
storage: storage.into_iter().fold(BTreeMap::new(), |mut m, k| {
|
||||||
|
let v = Diff::new(pre.storage.get(&k).cloned().unwrap_or(H256::new()), post.storage.get(&k).cloned().unwrap_or(H256::new()));
|
||||||
|
m.insert((*k).clone(), v);
|
||||||
|
m
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pod_map_diff(pre: &BTreeMap<Address, PodAccount>, post: &BTreeMap<Address, PodAccount>) -> StateDiff {
|
||||||
|
pre.keys()
|
||||||
|
.merge(post.keys())
|
||||||
|
.filter_map(|acc| pod_diff(pre.get(acc), post.get(acc)).map(|d|(acc.clone(), d)))
|
||||||
|
.collect::<BTreeMap<_, _>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! map {
|
||||||
|
( $( $x:expr => $y:expr ),* ) => {
|
||||||
|
vec![ $( ($x, $y) ),* ].into_iter().collect::<BTreeMap<_, _>>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! x {
|
||||||
|
( $x:expr ) => {
|
||||||
|
From::from($x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! xx {
|
||||||
|
( $x:expr ) => {
|
||||||
|
From::from(From::from($x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn state_diff_create_delete() {
|
||||||
|
let a = map![
|
||||||
|
x!(1) => PodAccount{
|
||||||
|
balance: x!(69),
|
||||||
|
nonce: x!(0),
|
||||||
|
code: vec![],
|
||||||
|
storage: map![]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
assert_eq!(pod_map_diff(&a, &map![]), map![
|
||||||
|
x!(1) => AccountDiff{
|
||||||
|
exists: Diff::new(true, false),
|
||||||
|
balance: Diff::one_opt(x!(69)),
|
||||||
|
nonce: Diff::one_opt(x!(0)),
|
||||||
|
code: Diff::one_opt(vec![]),
|
||||||
|
storage: map![],
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
assert_eq!(pod_map_diff(&map![], &a), map![
|
||||||
|
x!(1) => AccountDiff{
|
||||||
|
exists: Diff::new(false, true),
|
||||||
|
balance: Diff::one_opt(x!(69)),
|
||||||
|
nonce: Diff::one_opt(x!(0)),
|
||||||
|
code: Diff::one_opt(vec![]),
|
||||||
|
storage: map![],
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn state_diff_cretae_delete_with_unchanged() {
|
||||||
|
let a = map![
|
||||||
|
x!(1) => PodAccount{
|
||||||
|
balance: x!(69),
|
||||||
|
nonce: x!(0),
|
||||||
|
code: vec![],
|
||||||
|
storage: map![]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
let b = map![
|
||||||
|
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![]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
assert_eq!(pod_map_diff(&a, &b), map![
|
||||||
|
x!(2) => AccountDiff{
|
||||||
|
exists: Diff::new(false, true),
|
||||||
|
balance: Diff::one_opt(x!(69)),
|
||||||
|
nonce: Diff::one_opt(x!(0)),
|
||||||
|
code: Diff::one_opt(vec![]),
|
||||||
|
storage: map![],
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
assert_eq!(pod_map_diff(&b, &a), map![
|
||||||
|
x!(2) => AccountDiff{
|
||||||
|
exists: Diff::new(true, false),
|
||||||
|
balance: Diff::one_opt(x!(69)),
|
||||||
|
nonce: Diff::one_opt(x!(0)),
|
||||||
|
code: Diff::one_opt(vec![]),
|
||||||
|
storage: map![],
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn state_diff_change_with_unchanged() {
|
||||||
|
let a = map![
|
||||||
|
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![]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
let b = map![
|
||||||
|
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![]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
assert_eq!(pod_map_diff(&a, &b), map![
|
||||||
|
x!(1) => AccountDiff{
|
||||||
|
exists: Diff::one(true),
|
||||||
|
balance: None,
|
||||||
|
nonce: Diff::new_opt(x!(0), x!(1)),
|
||||||
|
code: None,
|
||||||
|
storage: map![],
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn account_diff_existence() {
|
||||||
|
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{
|
||||||
|
exists: Diff::new(false, true),
|
||||||
|
balance: Diff::one_opt(x!(69)),
|
||||||
|
nonce: Diff::one_opt(x!(0)),
|
||||||
|
code: Diff::one_opt(vec![]),
|
||||||
|
storage: map![],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn account_diff_basic() {
|
||||||
|
let a = PodAccount{balance: U256::from(69u64), nonce: U256::zero(), code: vec![], storage: BTreeMap::new()};
|
||||||
|
let b = PodAccount{balance: U256::from(42u64), nonce: U256::from(1u64), code: vec![], storage: BTreeMap::new()};
|
||||||
|
assert_eq!(pod_diff(Some(&a), Some(&b)), Some(AccountDiff {
|
||||||
|
exists: Diff::one(true),
|
||||||
|
balance: Diff::new_opt(U256::from(69u64), U256::from(42u64)),
|
||||||
|
nonce: Diff::new_opt(U256::zero(), U256::from(1u64)),
|
||||||
|
code: None,
|
||||||
|
storage: BTreeMap::new(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn account_diff_code() {
|
||||||
|
let a = PodAccount{balance: U256::zero(), nonce: U256::zero(), code: vec![], storage: BTreeMap::new()};
|
||||||
|
let b = PodAccount{balance: U256::zero(), nonce: U256::from(1u64), code: vec![0x00u8], storage: BTreeMap::new()};
|
||||||
|
assert_eq!(pod_diff(Some(&a), Some(&b)), Some(AccountDiff {
|
||||||
|
exists: Diff::one(true),
|
||||||
|
balance: None,
|
||||||
|
nonce: Diff::new_opt(U256::zero(), U256::from(1u64)),
|
||||||
|
code: Diff::new_opt(vec![], vec![0x00u8]),
|
||||||
|
storage: BTreeMap::new(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn h256_from_u8(v: u8) -> H256 {
|
||||||
|
let mut r = H256::new();
|
||||||
|
r[31] = v;
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn account_diff_storage() {
|
||||||
|
let a = PodAccount{balance: U256::zero(), nonce: U256::zero(), code: vec![], storage: vec![(1u8, 1u8), (2, 2), (3, 3), (4, 4), (5, 0), (6, 0), (7, 0)].into_iter().fold(BTreeMap::new(), |mut m, (k, v)|{m.insert(h256_from_u8(k), h256_from_u8(v)); m})};
|
||||||
|
let b = PodAccount{balance: U256::zero(), nonce: U256::zero(), code: vec![], storage: vec![(1u8, 1u8), (2, 3), (3, 0), (5, 0), (7, 7), (8, 0), (9, 9)].into_iter().fold(BTreeMap::new(), |mut m, (k, v)|{m.insert(h256_from_u8(k), h256_from_u8(v)); m})};
|
||||||
|
assert_eq!(pod_diff(Some(&a), Some(&b)), Some(AccountDiff {
|
||||||
|
exists: Diff::one(true),
|
||||||
|
balance: None,
|
||||||
|
nonce: None,
|
||||||
|
code: None,
|
||||||
|
storage: vec![
|
||||||
|
(2u8, Diff::new(h256_from_u8(2), h256_from_u8(3))),
|
||||||
|
(3, Diff::new(h256_from_u8(3), H256::new())),
|
||||||
|
(4, Diff::new(h256_from_u8(4), H256::new())),
|
||||||
|
(7, Diff::new(H256::new(), h256_from_u8(7))),
|
||||||
|
(9, Diff::new(H256::new(), h256_from_u8(9))),
|
||||||
|
].into_iter().fold(BTreeMap::new(), |mut m, (k, v)|{m.insert(h256_from_u8(k), v); m})
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
/// Single account in the system.
|
/// Single account in the system.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
@ -229,7 +501,7 @@ impl Account {
|
|||||||
|
|
||||||
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
|
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
|
||||||
pub fn commit_code(&mut self, db: &mut HashDB) {
|
pub fn commit_code(&mut self, db: &mut HashDB) {
|
||||||
println!("Commiting code of {:?} - {:?}, {:?}", self, self.code_hash.is_none(), self.code_cache.is_empty());
|
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()) {
|
match (self.code_hash.is_none(), self.code_cache.is_empty()) {
|
||||||
(true, true) => self.code_hash = Some(SHA3_EMPTY),
|
(true, true) => self.code_hash = Some(SHA3_EMPTY),
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
|
@ -73,18 +73,16 @@
|
|||||||
//! sudo ldconfig
|
//! sudo ldconfig
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use] extern crate log;
|
||||||
extern crate log;
|
|
||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
|
#[macro_use] extern crate itertools;
|
||||||
extern crate flate2;
|
extern crate flate2;
|
||||||
extern crate rocksdb;
|
extern crate rocksdb;
|
||||||
extern crate heapsize;
|
extern crate heapsize;
|
||||||
extern crate crypto;
|
extern crate crypto;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
#[cfg(feature = "jit" )]
|
#[cfg(feature = "jit" )] extern crate evmjit;
|
||||||
extern crate evmjit;
|
|
||||||
|
|
||||||
extern crate ethcore_util as util;
|
extern crate ethcore_util as util;
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
|||||||
|
|
||||||
let t = Transaction::from_json(&test["transaction"]);
|
let t = Transaction::from_json(&test["transaction"]);
|
||||||
let env = EnvInfo::from_json(&test["env"]);
|
let env = EnvInfo::from_json(&test["env"]);
|
||||||
let out = bytes_from_json(&test["out"]);
|
let _out = bytes_from_json(&test["out"]);
|
||||||
let post_state_root = h256_from_json(&test["postStateRoot"]);
|
let post_state_root = h256_from_json(&test["postStateRoot"]);
|
||||||
let pre = pod_map_from_json(&test["pre"]);
|
let pre = pod_map_from_json(&test["pre"]);
|
||||||
let post = pod_map_from_json(&test["post"]);
|
let post = pod_map_from_json(&test["post"]);
|
||||||
@ -55,18 +55,15 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
|||||||
|
|
||||||
println!("Transaction: {:?}", t);
|
println!("Transaction: {:?}", t);
|
||||||
println!("Env: {:?}", env);
|
println!("Env: {:?}", env);
|
||||||
println!("Out: {:?}", out);
|
|
||||||
println!("Pre: {:?}", pre);
|
|
||||||
println!("Post: {:?}", post);
|
|
||||||
|
|
||||||
let mut s = State::new_temp();
|
let mut s = State::new_temp();
|
||||||
s.populate_from(pre);
|
s.populate_from(pre);
|
||||||
|
|
||||||
s.apply(&env, engine.deref(), &t).unwrap();
|
s.apply(&env, engine.deref(), &t).unwrap();
|
||||||
let our_post = s.to_pod_map();
|
let our_post = s.to_pod_map();
|
||||||
|
|
||||||
if fail_unless(s.root() == &post_state_root) {
|
if fail_unless(s.root() == &post_state_root) {
|
||||||
println!("EXPECTED:\n{:?}", post);
|
println!("DIFF:\n{:?}", pod_map_diff(&post, &our_post));
|
||||||
println!("GOT:\n{:?}", our_post);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Compare logs.
|
// TODO: Compare logs.
|
||||||
|
Loading…
Reference in New Issue
Block a user