Merge pull request #93 from gavofyork/gav

Utils for consensus test decoding and better layout.
This commit is contained in:
Marek Kotewicz 2016-01-12 16:35:10 +01:00
commit 2b184585e2
5 changed files with 156 additions and 140 deletions

View File

@ -109,6 +109,9 @@ pub mod blockchain;
pub mod extras;
pub mod evm;
#[cfg(test)]
mod tests;
pub mod client;
pub mod sync;
pub mod block;

4
src/tests/mod.rs Normal file
View File

@ -0,0 +1,4 @@
#[macro_use]
mod test_common;
mod transaction;

62
src/tests/test_common.rs Normal file
View File

@ -0,0 +1,62 @@
pub use common::*;
pub fn clean(s: &str) -> &str {
if s.len() >= 2 && &s[0..2] == "0x" {
&s[2..]
} else {
s
}
}
pub fn bytes_from_json(json: &Json) -> Bytes {
let s = json.as_string().unwrap();
if s.len() % 2 == 1 {
FromHex::from_hex(&("0".to_string() + &(clean(s).to_string()))[..]).unwrap_or(vec![])
} else {
FromHex::from_hex(clean(s)).unwrap_or(vec![])
}
}
pub fn address_from_json(json: &Json) -> Address {
let s = json.as_string().unwrap();
if s.len() % 2 == 1 {
address_from_hex(&("0".to_string() + &(clean(s).to_string()))[..])
} else {
address_from_hex(clean(s))
}
}
pub fn u256_from_json(json: &Json) -> U256 {
let s = json.as_string().unwrap();
if s.len() >= 2 && &s[0..2] == "0x" {
// hex
U256::from_str(&s[2..]).unwrap()
}
else {
// dec
U256::from_dec_str(s).unwrap()
}
}
#[macro_export]
macro_rules! declare_test {
($id: ident, $name: expr) => {
#[test]
#[allow(non_snake_case)]
fn $id() {
assert!(do_json_test(include_bytes!(concat!("../../res/ethereum/tests/", $name, ".json"))).len() == 0);
}
};
}
#[macro_export]
macro_rules! declare_test_ignore {
($id: ident, $name: expr) => {
#[test]
#[ignore]
#[allow(non_snake_case)]
fn $id() {
assert!(do_json_test(include_bytes!(concat!("../../res/ethereum/tests/", $name, ".json"))).len() == 0);
}
};
}

75
src/tests/transaction.rs Normal file
View File

@ -0,0 +1,75 @@
use super::test_common::*;
use evm;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
let mut failed = Vec::new();
let old_schedule = evm::Schedule::new_frontier();
let new_schedule = evm::Schedule::new_homestead();
for (name, test) in json.as_object().unwrap() {
let mut fail = false;
let mut fail_unless = |cond: bool| if !cond && fail { failed.push(name.to_string()); fail = true };
let schedule = match test.find("blocknumber")
.and_then(|j| j.as_string())
.and_then(|s| BlockNumber::from_str(s).ok())
.unwrap_or(0) { x if x < 900000 => &old_schedule, _ => &new_schedule };
let rlp = bytes_from_json(&test["rlp"]);
let res = UntrustedRlp::new(&rlp).as_val().map_err(|e| From::from(e)).and_then(|t: Transaction| t.validate(schedule));
fail_unless(test.find("transaction").is_none() == res.is_err());
if let (Some(&Json::Object(ref tx)), Some(&Json::String(ref expect_sender))) = (test.find("transaction"), test.find("sender")) {
let t = res.unwrap();
fail_unless(t.sender().unwrap() == address_from_hex(clean(expect_sender)));
fail_unless(t.data == bytes_from_json(&tx["data"]));
fail_unless(t.gas == u256_from_json(&tx["gasLimit"]));
fail_unless(t.gas_price == u256_from_json(&tx["gasPrice"]));
fail_unless(t.nonce == u256_from_json(&tx["nonce"]));
fail_unless(t.value == u256_from_json(&tx["value"]));
if let Action::Call(ref to) = t.action {
fail_unless(to == &address_from_json(&tx["to"]));
} else {
fail_unless(bytes_from_json(&tx["to"]).len() == 0);
}
}
}
for f in failed.iter() {
println!("FAILED: {:?}", f);
}
failed
}
// Once we have interpolate idents.
/*macro_rules! declare_test {
($test_set_name: ident / $name: ident) => {
#[test]
#[allow(non_snake_case)]
fn $name() {
assert!(do_json_test(include_bytes!(concat!("../res/ethereum/tests/", stringify!($test_set_name), "/", stringify!($name), ".json"))).len() == 0);
}
};
($test_set_name: ident / $prename: ident / $name: ident) => {
#[test]
#[allow(non_snake_case)]
interpolate_idents! { fn [$prename _ $name]()
{
let json = include_bytes!(concat!("../res/ethereum/tests/", stringify!($test_set_name), "/", stringify!($prename), "/", stringify!($name), ".json"));
assert!(do_json_test(json).len() == 0);
}
}
};
}
declare_test!{TransactionTests/ttTransactionTest}
declare_test!{TransactionTests/tt10mbDataField}
declare_test!{TransactionTests/ttWrongRLPTransaction}
declare_test!{TransactionTests/Homestead/ttTransactionTest}
declare_test!{TransactionTests/Homestead/tt10mbDataField}
declare_test!{TransactionTests/Homestead/ttWrongRLPTransaction}
declare_test!{TransactionTests/RandomTests/tr201506052141PYTHON}*/
declare_test!{TransactionTests_ttTransactionTest, "TransactionTests/ttTransactionTest"}
declare_test_ignore!{TransactionTests_tt10mbDataField, "TransactionTests/tt10mbDataField"}
declare_test!{TransactionTests_ttWrongRLPTransaction, "TransactionTests/ttWrongRLPTransaction"}
declare_test!{TransactionTests_Homestead_ttTransactionTest, "TransactionTests/Homestead/ttTransactionTest"}
declare_test_ignore!{TransactionTests_Homestead_tt10mbDataField, "TransactionTests/Homestead/tt10mbDataField"}
declare_test!{TransactionTests_Homestead_ttWrongRLPTransaction, "TransactionTests/Homestead/ttWrongRLPTransaction"}
declare_test!{TransactionTests_RandomTests_tr201506052141PYTHON, "TransactionTests/RandomTests/tr201506052141PYTHON"}

View File

@ -147,144 +147,16 @@ impl Decodable for Transaction {
}
}
pub fn clean(s: &str) -> &str {
if s.len() >= 2 && &s[0..2] == "0x" {
&s[2..]
} else {
s
}
#[test]
fn sender_test() {
let t: Transaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
assert_eq!(t.data, b"");
assert_eq!(t.gas, U256::from(0x5208u64));
assert_eq!(t.gas_price, U256::from(0x01u64));
assert_eq!(t.nonce, U256::from(0x00u64));
if let Action::Call(ref to) = t.action {
assert_eq!(*to, address_from_hex("095e7baea6a6c7c4c2dfeb977efac326af552d87"));
} else { panic!(); }
assert_eq!(t.value, U256::from(0x0au64));
assert_eq!(t.sender().unwrap(), address_from_hex("0f65fe9276bc9a24ae7083ae28e2660ef72df99e"));
}
pub fn bytes_from_json(json: &Json) -> Bytes {
let s = json.as_string().unwrap();
if s.len() % 2 == 1 {
FromHex::from_hex(&("0".to_string() + &(clean(s).to_string()))[..]).unwrap_or(vec![])
} else {
FromHex::from_hex(clean(s)).unwrap_or(vec![])
}
}
pub fn address_from_json(json: &Json) -> Address {
let s = json.as_string().unwrap();
if s.len() % 2 == 1 {
address_from_hex(&("0".to_string() + &(clean(s).to_string()))[..])
} else {
address_from_hex(clean(s))
}
}
pub fn u256_from_json(json: &Json) -> U256 {
let s = json.as_string().unwrap();
if s.len() >= 2 && &s[0..2] == "0x" {
// hex
U256::from_str(&s[2..]).unwrap()
}
else {
// dec
U256::from_dec_str(s).unwrap()
}
}
#[cfg(test)]
mod tests {
use util::*;
use evm::Schedule;
use header::BlockNumber;
use super::*;
#[test]
fn sender_test() {
let t: Transaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
assert_eq!(t.data, b"");
assert_eq!(t.gas, U256::from(0x5208u64));
assert_eq!(t.gas_price, U256::from(0x01u64));
assert_eq!(t.nonce, U256::from(0x00u64));
if let Action::Call(ref to) = t.action {
assert_eq!(*to, address_from_hex("095e7baea6a6c7c4c2dfeb977efac326af552d87"));
} else { panic!(); }
assert_eq!(t.value, U256::from(0x0au64));
assert_eq!(t.sender().unwrap(), address_from_hex("0f65fe9276bc9a24ae7083ae28e2660ef72df99e"));
}
fn do_json_test(json_data: &[u8]) -> Vec<String> {
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
let mut failed = Vec::new();
let old_schedule = Schedule::new_frontier();
let new_schedule = Schedule::new_homestead();
for (name, test) in json.as_object().unwrap() {
let mut fail = false;
let mut fail_unless = |cond: bool| if !cond && fail { failed.push(name.to_string()); fail = true };
let schedule = match test.find("blocknumber")
.and_then(|j| j.as_string())
.and_then(|s| BlockNumber::from_str(s).ok())
.unwrap_or(0) { x if x < 900000 => &old_schedule, _ => &new_schedule };
let rlp = bytes_from_json(&test["rlp"]);
let res = UntrustedRlp::new(&rlp).as_val().map_err(|e| From::from(e)).and_then(|t: Transaction| t.validate(schedule));
fail_unless(test.find("transaction").is_none() == res.is_err());
if let (Some(&Json::Object(ref tx)), Some(&Json::String(ref expect_sender))) = (test.find("transaction"), test.find("sender")) {
let t = res.unwrap();
fail_unless(t.sender().unwrap() == address_from_hex(clean(expect_sender)));
fail_unless(t.data == bytes_from_json(&tx["data"]));
fail_unless(t.gas == u256_from_json(&tx["gasLimit"]));
fail_unless(t.gas_price == u256_from_json(&tx["gasPrice"]));
fail_unless(t.nonce == u256_from_json(&tx["nonce"]));
fail_unless(t.value == u256_from_json(&tx["value"]));
if let Action::Call(ref to) = t.action {
fail_unless(to == &address_from_json(&tx["to"]));
} else {
fail_unless(bytes_from_json(&tx["to"]).len() == 0);
}
}
}
for f in failed.iter() {
println!("FAILED: {:?}", f);
}
failed
}
// Once we have interpolate idents.
/*macro_rules! declare_test {
($test_set_name: ident / $name: ident) => {
#[test]
#[allow(non_snake_case)]
fn $name() {
assert!(do_json_test(include_bytes!(concat!("../res/ethereum/tests/", stringify!($test_set_name), "/", stringify!($name), ".json"))).len() == 0);
}
};
($test_set_name: ident / $prename: ident / $name: ident) => {
#[test]
#[allow(non_snake_case)]
interpolate_idents! { fn [$prename _ $name]()
{
let json = include_bytes!(concat!("../res/ethereum/tests/", stringify!($test_set_name), "/", stringify!($prename), "/", stringify!($name), ".json"));
assert!(do_json_test(json).len() == 0);
}
}
};
}
declare_test!{TransactionTests/ttTransactionTest}
declare_test!{TransactionTests/tt10mbDataField}
declare_test!{TransactionTests/ttWrongRLPTransaction}
declare_test!{TransactionTests/Homestead/ttTransactionTest}
declare_test!{TransactionTests/Homestead/tt10mbDataField}
declare_test!{TransactionTests/Homestead/ttWrongRLPTransaction}
declare_test!{TransactionTests/RandomTests/tr201506052141PYTHON}*/
macro_rules! declare_test {
($id: ident, $name: expr) => {
#[test]
#[allow(non_snake_case)]
fn $id() {
assert!(do_json_test(include_bytes!(concat!("../res/ethereum/tests/", $name, ".json"))).len() == 0);
}
};
}
declare_test!{TransactionTests_ttTransactionTest, "TransactionTests/ttTransactionTest"}
declare_test!{TransactionTests_tt10mbDataField, "TransactionTests/tt10mbDataField"}
declare_test!{TransactionTests_ttWrongRLPTransaction, "TransactionTests/ttWrongRLPTransaction"}
declare_test!{TransactionTests_Homestead_ttTransactionTest, "TransactionTests/Homestead/ttTransactionTest"}
declare_test!{TransactionTests_Homestead_tt10mbDataField, "TransactionTests/Homestead/tt10mbDataField"}
declare_test!{TransactionTests_Homestead_ttWrongRLPTransaction, "TransactionTests/Homestead/ttWrongRLPTransaction"}
declare_test!{TransactionTests_RandomTests_tr201506052141PYTHON, "TransactionTests/RandomTests/tr201506052141PYTHON"}
}