Byzantium updates (#5855)

* EIP-211 updates

* benchmarks

* blockhash instruction gas cost updated

* More benches

* EIP-684

* EIP-649

* EIP-658

* Updated some tests

* Modexp fixes

* STATICCALL fixes

* Pairing fixes

* More STATICALL fixes

* Use paritytech/bn

* Fixed REVERTing of contract creation

* Fixed more tests

* Fixed more tests

* Blockchain tests

* Enable previously broken tests

* Transition test

* Updated tests

* Fixed modexp reading huge numbers

* Enabled max_code_size test

* Review fixes

* Updated pairing pricing

* missing commas (style)

* Update test.rs

* Small improvements

* eip161abc
This commit is contained in:
Arkadiy Paronyan
2017-09-15 21:07:54 +02:00
committed by Gav Wood
parent b602fb4a5e
commit 25b35ebddd
47 changed files with 800 additions and 570 deletions

View File

@@ -2049,6 +2049,7 @@ mod tests {
let bc = new_chain(&genesis, db.clone());
insert_block(&db, &bc, &b1, vec![Receipt {
state_root: Some(H256::default()),
status_code: None,
gas_used: 10_000.into(),
log_bloom: Default::default(),
logs: vec![
@@ -2058,6 +2059,7 @@ mod tests {
},
Receipt {
state_root: Some(H256::default()),
status_code: None,
gas_used: 10_000.into(),
log_bloom: Default::default(),
logs: vec![
@@ -2067,6 +2069,7 @@ mod tests {
insert_block(&db, &bc, &b2, vec![
Receipt {
state_root: Some(H256::default()),
status_code: None,
gas_used: 10_000.into(),
log_bloom: Default::default(),
logs: vec![

View File

@@ -64,7 +64,7 @@ struct Linear {
}
/// A special pricing model for modular exponentiation.
struct Modexp {
struct ModexpPricer {
divisor: usize,
}
@@ -74,7 +74,20 @@ impl Pricer for Linear {
}
}
impl Pricer for Modexp {
/// A alt_bn128_parinig pricing model. This computes a price using a base cost and a cost per pair.
struct AltBn128PairingPricer {
base: usize,
pair: usize,
}
impl Pricer for AltBn128PairingPricer {
fn cost(&self, input: &[u8]) -> U256 {
let cost = U256::from(self.base) + U256::from(self.pair) * U256::from(input.len() / 192);
cost
}
}
impl Pricer for ModexpPricer {
fn cost(&self, input: &[u8]) -> U256 {
let mut reader = input.chain(io::repeat(0));
let mut buf = [0; 32];
@@ -88,17 +101,49 @@ impl Pricer for Modexp {
let exp_len = read_len();
let mod_len = read_len();
// floor(max(length_of_MODULUS, length_of_BASE) ** 2 * max(length_of_EXPONENT, 1) / GQUADDIVISOR)
// TODO: is saturating the best behavior here?
let max_len = U256::from(u32::max_value() / 2);
if base_len > max_len || mod_len > max_len {
return U256::max_value();
}
let base_len = base_len.low_u64();
let exp_len = exp_len.low_u64();
let mod_len = mod_len.low_u64();
let m = max(mod_len, base_len);
match m.overflowing_mul(m) {
(_, true) => U256::max_value(),
(val, _) => {
match val.overflowing_mul(max(exp_len, U256::one())) {
(_, true) => U256::max_value(),
(val, _) => val / (self.divisor as u64).into()
}
}
if m == 0 {
return U256::zero();
}
// read fist 32-byte word of the exponent.
let exp_low = if base_len + 96 >= input.len() as u64 { U256::zero() } else {
let mut buf = [0; 32];
let mut reader = input[(96 + base_len as usize)..].chain(io::repeat(0));
let len = min(exp_len, 32) as usize;
reader.read_exact(&mut buf[(32 - len)..]).expect("reading from zero-extended memory cannot fail; qed");
U256::from(H256::from_slice(&buf[..]))
};
let adjusted_exp_len = Self::adjusted_exp_len(exp_len, exp_low);
(Self::mult_complexity(m) * max(adjusted_exp_len, 1) / self.divisor as u64).into()
}
}
impl ModexpPricer {
fn adjusted_exp_len(len: u64, exp_low: U256) -> u64 {
let bit_index = if exp_low.is_zero() { 0 } else { (255 - exp_low.leading_zeros()) as u64 };
if len <= 32 {
bit_index
}
else {
8 * (len - 32) + bit_index
}
}
fn mult_complexity(x: u64) -> u64 {
match x {
x if x <= 64 => x * x,
x if x <= 1024 => (x * x) / 4 + 96 * x - 3072,
x => (x * x) / 16 + 480 * x - 199680,
}
}
}
@@ -138,7 +183,7 @@ impl From<ethjson::spec::Builtin> for Builtin {
})
}
ethjson::spec::Pricing::Modexp(exp) => {
Box::new(Modexp {
Box::new(ModexpPricer {
divisor: if exp.divisor == 0 {
warn!("Zero modexp divisor specified. Falling back to default.");
10
@@ -147,6 +192,12 @@ impl From<ethjson::spec::Builtin> for Builtin {
}
})
}
ethjson::spec::Pricing::AltBn128Pairing(pricer) => {
Box::new(AltBn128PairingPricer {
base: pricer.base,
pair: pricer.pair,
})
}
};
Builtin {
@@ -165,9 +216,9 @@ fn ethereum_builtin(name: &str) -> Box<Impl> {
"sha256" => Box::new(Sha256) as Box<Impl>,
"ripemd160" => Box::new(Ripemd160) as Box<Impl>,
"modexp" => Box::new(ModexpImpl) as Box<Impl>,
"bn128_add" => Box::new(Bn128AddImpl) as Box<Impl>,
"bn128_mul" => Box::new(Bn128MulImpl) as Box<Impl>,
"bn128_pairing" => Box::new(Bn128PairingImpl) as Box<Impl>,
"alt_bn128_add" => Box::new(Bn128AddImpl) as Box<Impl>,
"alt_bn128_mul" => Box::new(Bn128MulImpl) as Box<Impl>,
"alt_bn128_pairing" => Box::new(Bn128PairingImpl) as Box<Impl>,
_ => panic!("invalid builtin name: {}", name),
}
}
@@ -273,11 +324,16 @@ impl Impl for Ripemd160 {
fn modexp(mut base: BigUint, mut exp: BigUint, modulus: BigUint) -> BigUint {
use num::Integer;
match (base.is_zero(), exp.is_zero()) {
(_, true) => return BigUint::one(), // n^0 % m
(true, false) => return BigUint::zero(), // 0^n % m, n>0
(false, false) if modulus <= BigUint::one() => return BigUint::zero(), // a^b % 1 = 0.
_ => {}
if modulus <= BigUint::one() { // n^m % 0 || n^m % 1
return BigUint::zero();
}
if exp.is_zero() { // n^0 % m
return BigUint::one();
}
if base.is_zero() { // 0^n % m, n>0
return BigUint::zero();
}
let mut result = BigUint::one();
@@ -293,7 +349,6 @@ fn modexp(mut base: BigUint, mut exp: BigUint, modulus: BigUint) -> BigUint {
exp = exp >> 1;
base = (base.clone() * base) % &modulus;
}
result
}
@@ -314,19 +369,25 @@ impl Impl for ModexpImpl {
let exp_len = read_len(&mut reader);
let mod_len = read_len(&mut reader);
// read the numbers themselves.
let mut buf = vec![0; max(mod_len, max(base_len, exp_len))];
let mut read_num = |len| {
reader.read_exact(&mut buf[..len]).expect("reading from zero-extended memory cannot fail; qed");
BigUint::from_bytes_be(&buf[..len])
// Gas formula allows arbitrary large exp_len when base and modulus are empty, so we need to handle empty base first.
let r = if base_len == 0 && mod_len == 0 {
BigUint::zero()
} else {
// read the numbers themselves.
let mut buf = vec![0; max(mod_len, max(base_len, exp_len))];
let mut read_num = |len| {
reader.read_exact(&mut buf[..len]).expect("reading from zero-extended memory cannot fail; qed");
BigUint::from_bytes_be(&buf[..len])
};
let base = read_num(base_len);
let exp = read_num(exp_len);
let modulus = read_num(mod_len);
modexp(base, exp, modulus)
};
let base = read_num(base_len);
let exp = read_num(exp_len);
let modulus = read_num(mod_len);
// write output to given memory, left padded and same length as the modulus.
let bytes = modexp(base, exp, modulus).to_bytes_be();
let bytes = r.to_bytes_be();
// always true except in the case of zero-length modulus, which leads to
// output of length and value 1.
@@ -356,7 +417,6 @@ fn read_point(reader: &mut io::Chain<&[u8], io::Repeat>) -> Result<::bn::G1, Err
reader.read_exact(&mut buf[..]).expect("reading from zero-extended memory cannot fail; qed");
let py = Fq::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid point y coordinate"))?;
Ok(
if px == Fq::zero() && py == Fq::zero() {
G1::zero()
@@ -407,50 +467,29 @@ impl Impl for Bn128MulImpl {
}
}
mod bn128_gen {
use bn::{AffineG1, AffineG2, Fq, Fq2, G1, G2, Gt, pairing};
lazy_static! {
pub static ref P1: G1 = G1::from(AffineG1::new(
Fq::from_str("1").expect("1 is a valid field element"),
Fq::from_str("2").expect("2 is a valid field element"),
).expect("Generator P1(1, 2) is a valid curve point"));
}
lazy_static! {
pub static ref P2: G2 = G2::from(AffineG2::new(
Fq2::new(
Fq::from_str("10857046999023057135944570762232829481370756359578518086990519993285655852781")
.expect("a valid field element"),
Fq::from_str("11559732032986387107991004021392285783925812861821192530917403151452391805634")
.expect("a valid field element"),
),
Fq2::new(
Fq::from_str("8495653923123431417604973247489272438418190587263600148770280649306958101930")
.expect("a valid field element"),
Fq::from_str("4082367875863433681332203403145435568316851327593401208105741076214120093531")
.expect("a valid field element"),
),
).expect("the generator P2(10857046999023057135944570762232829481370756359578518086990519993285655852781 + 11559732032986387107991004021392285783925812861821192530917403151452391805634i, 8495653923123431417604973247489272438418190587263600148770280649306958101930 + 4082367875863433681332203403145435568316851327593401208105741076214120093531i) is a valid curve point"));
}
lazy_static! {
pub static ref P1_P2_PAIRING: Gt = pairing(P1.clone(), P2.clone());
}
}
impl Impl for Bn128PairingImpl {
/// Can fail if:
/// - input length is not a multiple of 192
/// - any of odd points does not belong to bn128 curve
/// - any of even points does not belong to the twisted bn128 curve over the field F_p^2 = F_p[i] / (i^2 + 1)
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> {
use bn::{AffineG1, AffineG2, Fq, Fq2, pairing, G1, G2, Gt};
let elements = input.len() / 192; // (a, b_a, b_b - each 64-byte affine coordinates)
if input.len() % 192 != 0 {
return Err("Invalid input length, must be multiple of 192 (3 * (32*2))".into())
}
if let Err(err) = self.execute_with_error(input, output) {
trace!("Pairining error: {:?}", err);
return Err(err)
}
Ok(())
}
}
impl Bn128PairingImpl {
fn execute_with_error(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> {
use bn::{AffineG1, AffineG2, Fq, Fq2, pairing, G1, G2, Gt, Group};
let elements = input.len() / 192; // (a, b_a, b_b - each 64-byte affine coordinates)
let ret_val = if input.len() == 0 {
U256::one()
} else {
@@ -462,34 +501,36 @@ impl Impl for Bn128PairingImpl {
let a_y = Fq::from_slice(&input[idx*192+32..idx*192+64])
.map_err(|_| Error::from("Invalid a argument y coordinate"))?;
let b_b_x = Fq::from_slice(&input[idx*192+64..idx*192+96])
let b_a_y = Fq::from_slice(&input[idx*192+64..idx*192+96])
.map_err(|_| Error::from("Invalid b argument imaginary coeff x coordinate"))?;
let b_b_y = Fq::from_slice(&input[idx*192+96..idx*192+128])
let b_a_x = Fq::from_slice(&input[idx*192+96..idx*192+128])
.map_err(|_| Error::from("Invalid b argument imaginary coeff y coordinate"))?;
let b_a_x = Fq::from_slice(&input[idx*192+128..idx*192+160])
let b_b_y = Fq::from_slice(&input[idx*192+128..idx*192+160])
.map_err(|_| Error::from("Invalid b argument real coeff x coordinate"))?;
let b_a_y = Fq::from_slice(&input[idx*192+160..idx*192+192])
let b_b_x = Fq::from_slice(&input[idx*192+160..idx*192+192])
.map_err(|_| Error::from("Invalid b argument real coeff y coordinate"))?;
vals.push((
G1::from(
AffineG1::new(a_x, a_y).map_err(|_| Error::from("Invalid a argument - not on curve"))?
),
G2::from(
AffineG2::new(
Fq2::new(b_a_x, b_a_y),
Fq2::new(b_b_x, b_b_y),
).map_err(|_| Error::from("Invalid b argument - not on curve"))?
),
));
let b_a = Fq2::new(b_a_x, b_a_y);
let b_b = Fq2::new(b_b_x, b_b_y);
let b = if b_a.is_zero() && b_b.is_zero() {
G2::zero()
} else {
G2::from(AffineG2::new(b_a, b_b).map_err(|_| Error::from("Invalid b argument - not on curve"))?)
};
let a = if a_x.is_zero() && a_y.is_zero() {
G1::zero()
} else {
G1::from(AffineG1::new(a_x, a_y).map_err(|_| Error::from("Invalid a argument - not on curve"))?)
};
vals.push((a, b));
};
let mul = vals.into_iter().fold(Gt::one(), |s, (a, b)| s * pairing(a, b));
if mul == *bn128_gen::P1_P2_PAIRING {
if mul == Gt::one() {
U256::one()
} else {
U256::zero()
@@ -506,7 +547,7 @@ impl Impl for Bn128PairingImpl {
#[cfg(test)]
mod tests {
use super::{Builtin, Linear, ethereum_builtin, Pricer, Modexp, modexp as me};
use super::{Builtin, Linear, ethereum_builtin, Pricer, ModexpPricer, modexp as me};
use ethjson;
use bigint::prelude::U256;
use bytes::BytesRef;
@@ -662,7 +703,7 @@ mod tests {
fn modexp() {
let f = Builtin {
pricer: Box::new(Modexp { divisor: 20 }),
pricer: Box::new(ModexpPricer { divisor: 20 }),
native: ethereum_builtin("modexp"),
activate_at: 0,
};
@@ -679,7 +720,7 @@ mod tests {
let mut output = vec![0u8; 32];
let expected = FromHex::from_hex("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
let expected_cost = 1638;
let expected_cost = 13056;
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
assert_eq!(output, expected);
@@ -690,15 +731,15 @@ mod tests {
{
let input = FromHex::from_hex("\
0000000000000000000000000000000000000000000000000000000000000000\
0000000000000000000000000000000000000000000000000000000000000020\
0000000000000000000000000000000000000000000000000000000000000020\
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e\
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"
0000000000000000000000000000000000000000000000000000000000000020\
0000000000000000000000000000000000000000000000000000000000000020\
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e\
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"
).unwrap();
let mut output = vec![0u8; 32];
let expected = FromHex::from_hex("0000000000000000000000000000000000000000000000000000000000000000").unwrap();
let expected_cost = 1638;
let expected_cost = 13056;
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
assert_eq!(output, expected);
@@ -718,7 +759,7 @@ mod tests {
let mut output = vec![0u8; 32];
let expected = FromHex::from_hex("3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab").unwrap();
let expected_cost = 102;
let expected_cost = 768;
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
assert_eq!(output, expected);
@@ -749,7 +790,7 @@ mod tests {
let f = Builtin {
pricer: Box::new(Linear { base: 0, word: 0 }),
native: ethereum_builtin("bn128_add"),
native: ethereum_builtin("alt_bn128_add"),
activate_at: 0,
};
@@ -810,7 +851,7 @@ mod tests {
let f = Builtin {
pricer: Box::new(Linear { base: 0, word: 0 }),
native: ethereum_builtin("bn128_mul"),
native: ethereum_builtin("alt_bn128_mul"),
activate_at: 0,
};
@@ -850,7 +891,7 @@ mod tests {
fn builtin_pairing() -> Builtin {
Builtin {
pricer: Box::new(Linear { base: 0, word: 0 }),
native: ethereum_builtin("bn128_pairing"),
native: ethereum_builtin("alt_bn128_pairing"),
activate_at: 0,
}
}

View File

@@ -2140,11 +2140,13 @@ mod tests {
}];
let receipts = vec![Receipt {
state_root: state_root,
status_code: None,
gas_used: 5.into(),
log_bloom: Default::default(),
logs: vec![logs[0].clone()],
}, Receipt {
state_root: state_root,
status_code: None,
gas_used: gas_used,
log_bloom: Default::default(),
logs: logs.clone(),

View File

@@ -26,7 +26,7 @@ use bytes;
use util::kvdb::{self, KeyValueDB};
use {state, state_db, client, executive, trace, transaction, db, spec, pod_state};
use factory::Factories;
use evm::{self, VMType};
use evm::{self, VMType, FinalizationResult};
use vm::{self, ActionParams};
/// EVM test Error.
@@ -72,7 +72,8 @@ lazy_static! {
pub static ref HOMESTEAD: spec::Spec = ethereum::new_homestead_test();
pub static ref EIP150: spec::Spec = ethereum::new_eip150_test();
pub static ref EIP161: spec::Spec = ethereum::new_eip161_test();
pub static ref _METROPOLIS: spec::Spec = ethereum::new_metropolis_test();
pub static ref BYZANTIUM: spec::Spec = ethereum::new_byzantium_test();
pub static ref BYZANTIUM_TRANSITION: spec::Spec = ethereum::new_transition_test();
}
/// Simplified, single-block EVM test client.
@@ -89,7 +90,10 @@ impl<'a> EvmTestClient<'a> {
ForkSpec::Homestead => Some(&*HOMESTEAD),
ForkSpec::EIP150 => Some(&*EIP150),
ForkSpec::EIP158 => Some(&*EIP161),
ForkSpec::Metropolis | ForkSpec::Byzantium | ForkSpec::Constantinople => None,
ForkSpec::Byzantium => Some(&*BYZANTIUM),
ForkSpec::EIP158ToByzantiumAt5 => Some(&BYZANTIUM_TRANSITION),
ForkSpec::FrontierToHomesteadAt5 | ForkSpec::HomesteadToDaoAt5 | ForkSpec::HomesteadToEIP150At5 => None,
_ => None,
}
}
@@ -162,7 +166,7 @@ impl<'a> EvmTestClient<'a> {
/// Execute the VM given ActionParams and tracer.
/// Returns amount of gas left and the output.
pub fn call<T: trace::VMTracer>(&mut self, params: ActionParams, vm_tracer: &mut T)
-> Result<(U256, Vec<u8>), EvmTestError>
-> Result<FinalizationResult, EvmTestError>
{
let genesis = self.spec.genesis_header();
let info = client::EnvInfo {
@@ -178,15 +182,13 @@ impl<'a> EvmTestClient<'a> {
let mut tracer = trace::NoopTracer;
let mut output = vec![];
let mut executive = executive::Executive::new(&mut self.state, &info, &*self.spec.engine);
let (gas_left, _) = executive.call(
executive.call(
params,
&mut substate,
bytes::BytesRef::Flexible(&mut output),
&mut tracer,
vm_tracer,
).map_err(EvmTestError::Evm)?;
Ok((gas_left, output))
).map_err(EvmTestError::Evm)
}
/// Executes a SignedTransaction within context of the provided state and `EnvInfo`.
@@ -212,10 +214,13 @@ impl<'a> EvmTestClient<'a> {
let result = self.state.apply_with_tracing(&env_info, &*self.spec.engine, &transaction, tracer, vm_tracer);
match result {
Ok(result) => TransactResult::Ok {
state_root: *self.state.root(),
gas_left: initial_gas - result.receipt.gas_used,
output: result.output
Ok(result) => {
self.state.commit().ok();
TransactResult::Ok {
state_root: *self.state.root(),
gas_left: initial_gas - result.receipt.gas_used,
output: result.output
}
},
Err(error) => TransactResult::Err {
state_root: *self.state.root(),

View File

@@ -619,6 +619,7 @@ impl BlockChainClient for TestBlockChainClient {
if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") {
let receipt = BlockReceipts::new(vec![Receipt::new(
Some(H256::zero()),
None,
U256::zero(),
vec![])]);
let mut rlp = RlpStream::new();

View File

@@ -62,8 +62,8 @@ use unexpected::{Mismatch, OutOfBounds};
use bytes::Bytes;
/// Default EIP-210 contrat code.
/// As defined in https://github.com/ethereum/EIPs/pull/210/commits/9df24a3714af42e3bf350265bdc75b486c909d7f#diff-e02a92c2fb96c1a1bfb05e4c6e2ef5daR49
pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561007a57600143036020526000356101006020510755600061010060205107141561005057600035610100610100602051050761010001555b6000620100006020510714156100755760003561010062010000602051050761020001555b610161565b436000351215801561008c5780610095565b623567e0600035125b9050156100a757600060605260206060f35b610100600035430312156100ca57610100600035075460805260206080f3610160565b62010000600035430312156100e857600061010060003507146100eb565b60005b1561010d576101006101006000350507610100015460a052602060a0f361015f565b63010000006000354303121561012d576000620100006000350714610130565b60005b1561015357610100620100006000350507610200015460c052602060c0f361015e565b600060e052602060e0f35b5b5b5b5b";
/// As defined in https://github.com/ethereum/EIPs/pull/210
pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561006a5760014303600035610100820755610100810715156100455760003561010061010083050761010001555b6201000081071515610064576000356101006201000083050761020001555b5061013e565b4360003512151561008457600060405260206040f361013d565b61010060003543031315156100a857610100600035075460605260206060f361013c565b6101006000350715156100c55762010000600035430313156100c8565b60005b156100ea576101006101006000350507610100015460805260206080f361013b565b620100006000350715156101095763010000006000354303131561010c565b60005b1561012f57610100620100006000350507610200015460a052602060a0f361013a565b600060c052602060c0f35b5b5b5b5b";
/// Voting errors.
#[derive(Debug)]

View File

@@ -51,6 +51,7 @@ const SNAPSHOT_BLOCKS: u64 = 5000;
/// Maximum number of blocks allowed in an ethash snapshot.
const MAX_SNAPSHOT_BLOCKS: u64 = 30000;
const DEFAULT_EIP649_DELAY: u64 = 3_000_000;
/// Ethash params.
#[derive(Debug, PartialEq)]
@@ -105,6 +106,12 @@ pub struct EthashParams {
pub min_gas_price_transition: u64,
/// Do not alow transactions with lower gas price.
pub min_gas_price: U256,
/// EIP-649 transition block.
pub eip649_transition: u64,
/// EIP-649 bomb delay.
pub eip649_delay: u64,
/// EIP-649 base reward.
pub eip649_reward: Option<U256>,
}
impl From<ethjson::spec::EthashParams> for EthashParams {
@@ -135,6 +142,9 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
max_gas_limit: p.max_gas_limit.map_or(U256::max_value(), Into::into),
min_gas_price_transition: p.min_gas_price_transition.map_or(u64::max_value(), Into::into),
min_gas_price: p.min_gas_price.map_or(U256::zero(), Into::into),
eip649_transition: p.eip649_transition.map_or(u64::max_value(), Into::into),
eip649_delay: p.eip649_delay.map_or(DEFAULT_EIP649_DELAY, Into::into),
eip649_reward: p.eip649_reward.map(Into::into),
}
}
}
@@ -215,8 +225,10 @@ impl Engine for Arc<Ethash> {
} else if block_number < self.ethash_params.eip150_transition {
Schedule::new_homestead()
} else {
/// There's no max_code_size transition so we tie it to eip161abc
let max_code_size = if block_number >= self.ethash_params.eip161abc_transition { self.ethash_params.max_code_size as usize } else { usize::max_value() };
let mut schedule = Schedule::new_post_eip150(
self.ethash_params.max_code_size as usize,
max_code_size,
block_number >= self.ethash_params.eip160_transition,
block_number >= self.ethash_params.eip161abc_transition,
block_number >= self.ethash_params.eip161d_transition);
@@ -296,9 +308,14 @@ impl Engine for Arc<Ethash> {
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
use std::ops::Shr;
let reward = self.params().block_reward;
let tracing_enabled = block.tracing_enabled();
let fields = block.fields_mut();
let reward = if fields.header.number() >= self.ethash_params.eip649_transition {
self.ethash_params.eip649_reward.unwrap_or(self.params().block_reward)
} else {
self.params().block_reward
};
let eras_rounds = self.ethash_params.ecip1017_era_rounds;
let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, fields.header.number());
let mut tracer = ExecutiveTracer::default();
@@ -500,7 +517,7 @@ fn ecip1017_eras_block_reward(era_rounds: u64, mut reward: U256, block_number:u6
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
impl Ethash {
fn calculate_difficulty(&self, header: &Header, parent: &Header) -> U256 {
const EXP_DIFF_PERIOD: u64 = 100000;
const EXP_DIFF_PERIOD: u64 = 100_000;
if header.number() == 0 {
panic!("Can't calculate genesis block difficulty");
}
@@ -550,7 +567,11 @@ impl Ethash {
target = cmp::max(min_difficulty, target);
if header.number() < self.ethash_params.bomb_defuse_transition {
if header.number() < self.ethash_params.ecip1010_pause_transition {
let period = ((parent.number() + 1) / EXP_DIFF_PERIOD) as usize;
let mut number = header.number();
if number >= self.ethash_params.eip649_transition {
number = number.saturating_sub(self.ethash_params.eip649_delay);
}
let period = (number / EXP_DIFF_PERIOD) as usize;
if period > 1 {
target = cmp::max(min_difficulty, target + (U256::from(1) << (period - 2)));
}

View File

@@ -87,8 +87,11 @@ pub fn new_transition_test() -> Spec { load(None, include_bytes!("../../res/ethe
/// Create a new Foundation Mainnet chain spec without genesis accounts.
pub fn new_mainnet_like() -> Spec { load(None, include_bytes!("../../res/ethereum/frontier_like_test.json")) }
/// Create a new Foundation Metropolis era spec.
pub fn new_metropolis_test() -> Spec { load(None, include_bytes!("../../res/ethereum/metropolis_test.json")) }
/// Create a new Foundation Byzantium era spec.
pub fn new_byzantium_test() -> Spec { load(None, include_bytes!("../../res/ethereum/byzantium_test.json")) }
/// Create a new Foundation Constantinople era spec.
pub fn new_constantinople_test() -> Spec { load(None, include_bytes!("../../res/ethereum/constantinople_test.json")) }
#[cfg(test)]
mod tests {

View File

@@ -291,7 +291,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
let mut substate = Substate::new();
// NOTE: there can be no invalid transactions from this point.
if !t.is_unsigned() {
if !schedule.eip86 || !t.is_unsigned() {
self.state.inc_nonce(&sender)?;
}
self.state.sub_balance(&sender, &U256::from(gas_cost), &mut substate.to_cleanup_mode(&schedule))?;
@@ -383,12 +383,12 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
mut output: BytesRef,
tracer: &mut T,
vm_tracer: &mut V
) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
) -> vm::Result<FinalizationResult> where T: Tracer, V: VMTracer {
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
trace!("Executive::call(params={:?}) self.env_info={:?}, static={}", params, self.info, self.static_flag);
if (params.call_type == CallType::StaticCall ||
((params.call_type == CallType::Call || params.call_type == CallType::DelegateCall) &&
self.static_flag))
((params.call_type == CallType::Call) &&
self.static_flag))
&& params.value.value() > 0.into() {
return Err(vm::Error::MutableCallInStaticContext);
}
@@ -441,7 +441,11 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
);
}
Ok((params.gas - cost, ReturnData::empty()))
Ok(FinalizationResult {
gas_left: params.gas - cost,
return_data: ReturnData::new(output.to_owned(), 0, output.len()),
apply_state: true,
})
}
} else {
// just drain the whole gas
@@ -488,13 +492,17 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
self.enact_result(&res, substate, unconfirmed_substate);
trace!(target: "executive", "enacted: substate={:?}\n", substate);
res.map(|r| (r.gas_left, r.return_data))
res
} else {
// otherwise it's just a basic transaction, only do tracing, if necessary.
self.state.discard_checkpoint();
tracer.trace_call(trace_info, U256::zero(), trace_output, vec![]);
Ok((params.gas, ReturnData::empty()))
Ok(FinalizationResult {
gas_left: params.gas,
return_data: ReturnData::empty(),
apply_state: true,
})
}
}
}
@@ -509,13 +517,18 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
output: &mut Option<Bytes>,
tracer: &mut T,
vm_tracer: &mut V,
) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
) -> vm::Result<FinalizationResult> where T: Tracer, V: VMTracer {
let scheme = self.engine.create_address_scheme(self.info.number);
if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(&params.address)? {
// EIP-684: If a contract creation is attempted, due to either a creation transaction or the
// CREATE (or future CREATE2) opcode, and the destination address already has either
// nonzero nonce, or nonempty code, then the creation throws immediately, with exactly
// the same behavior as would arise if the first byte in the init code were an invalid
// opcode. This applies retroactively starting from genesis.
if self.state.exists_and_has_code_or_nonce(&params.address)? {
return Err(vm::Error::OutOfGas);
}
trace!("Executive::create(params={:?}) self.env_info={:?}, static={}", params, self.info, self.static_flag);
if params.call_type == CallType::StaticCall || self.static_flag {
let trace_info = tracer.prepare_trace_create(&params);
tracer.trace_failed_create(trace_info, vec![], vm::Error::MutableCallInStaticContext.into());
@@ -565,7 +578,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
};
self.enact_result(&res, substate, unconfirmed_substate);
res.map(|r| (r.gas_left, r.return_data))
res
}
/// Finalizes the transaction (does refunds and suicides).
@@ -573,7 +586,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
&mut self,
t: &SignedTransaction,
mut substate: Substate,
result: vm::Result<(U256, ReturnData)>,
result: vm::Result<FinalizationResult>,
output: Bytes,
trace: Vec<FlatTrace>,
vm_trace: Option<VMTrace>
@@ -587,7 +600,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
let refunds_bound = sstore_refunds + suicide_refunds;
// real ammount to refund
let gas_left_prerefund = match result { Ok((x, _)) => x, _ => 0.into() };
let gas_left_prerefund = match result { Ok(FinalizationResult{ gas_left, .. }) => gas_left, _ => 0.into() };
let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) >> 1);
let gas_left = gas_left_prerefund + refunded;
@@ -631,9 +644,9 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
state_diff: None,
})
},
_ => {
Ok(r) => {
Ok(Executed {
exception: None,
exception: if r.apply_state { None } else { Some(vm::Error::Reverted) },
gas: t.gas,
gas_used: gas_used,
refunded: refunded,
@@ -659,6 +672,8 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
| Err(vm::Error::Wasm {..})
| Err(vm::Error::OutOfStack {..})
| Err(vm::Error::MutableCallInStaticContext)
| Err(vm::Error::OutOfBounds)
| Err(vm::Error::Reverted)
| Ok(FinalizationResult { apply_state: false, .. }) => {
self.state.revert_to_checkpoint();
},
@@ -716,7 +731,7 @@ mod tests {
let engine = TestEngine::new(0);
let mut substate = Substate::new();
let (gas_left, _) = {
let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
};
@@ -774,7 +789,7 @@ mod tests {
let engine = TestEngine::new(0);
let mut substate = Substate::new();
let (gas_left, _) = {
let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
};
@@ -832,7 +847,7 @@ mod tests {
let mut tracer = ExecutiveTracer::default();
let mut vm_tracer = ExecutiveVMTracer::toplevel();
let (gas_left, _) = {
let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &engine);
let output = BytesRef::Fixed(&mut[0u8;0]);
ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap()
@@ -941,7 +956,7 @@ mod tests {
let mut tracer = ExecutiveTracer::default();
let mut vm_tracer = ExecutiveVMTracer::toplevel();
let (gas_left, _) = {
let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params.clone(), &mut substate, &mut None, &mut tracer, &mut vm_tracer).unwrap()
};
@@ -1026,7 +1041,7 @@ mod tests {
let engine = TestEngine::new(0);
let mut substate = Substate::new();
let (gas_left, _) = {
let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
};
@@ -1137,7 +1152,7 @@ mod tests {
let engine = TestEngine::new(0);
let mut substate = Substate::new();
let (gas_left, _) = {
let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap()
};
@@ -1181,7 +1196,7 @@ mod tests {
let engine = TestEngine::new(0);
let mut substate = Substate::new();
let (gas_left, _) = {
let FinalizationResult { gas_left, .. } = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap()
};
@@ -1382,11 +1397,11 @@ mod tests {
let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap();
let info = EnvInfo::default();
let engine = TestEngine::new_metropolis();
let engine = TestEngine::new_byzantium();
let mut substate = Substate::new();
let mut output = [0u8; 14];
let (result, _) = {
let FinalizationResult { gas_left: result, .. } = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap()
};

View File

@@ -29,6 +29,7 @@ use vm::{
Ext, ContractCreateResult, MessageCallResult, CreateContractAddress,
ReturnData
};
use evm::FinalizationResult;
use transaction::UNSIGNED_SENDER;
use trace::{Tracer, VMTracer};
@@ -127,6 +128,10 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
}
}
fn is_static(&self) -> bool {
return self.static_flag
}
fn exists(&self, address: &Address) -> vm::Result<bool> {
self.state.exists(address).map_err(Into::into)
}
@@ -216,21 +221,27 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
call_type: CallType::None,
};
if params.sender != UNSIGNED_SENDER {
if let Err(e) = self.state.inc_nonce(&self.origin_info.address) {
debug!(target: "ext", "Database corruption encountered: {:?}", e);
return ContractCreateResult::Failed
if !self.static_flag {
if !self.schedule.eip86 || params.sender != UNSIGNED_SENDER {
if let Err(e) = self.state.inc_nonce(&self.origin_info.address) {
debug!(target: "ext", "Database corruption encountered: {:?}", e);
return ContractCreateResult::Failed
}
}
}
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth, self.static_flag);
// TODO: handle internal error separately
match ex.create(params, self.substate, &mut None, self.tracer, self.vm_tracer) {
Ok((gas_left, _)) => {
Ok(FinalizationResult{ gas_left, apply_state: true, .. }) => {
self.substate.contracts_created.push(address.clone());
ContractCreateResult::Created(address, gas_left)
},
_ => ContractCreateResult::Failed
Ok(FinalizationResult{ gas_left, apply_state: false, return_data }) => {
ContractCreateResult::Reverted(gas_left, return_data)
},
Err(vm::Error::MutableCallInStaticContext) => ContractCreateResult::FailedInStaticCall,
_ => ContractCreateResult::Failed,
}
}
@@ -275,7 +286,8 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth, self.static_flag);
match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) {
Ok((gas_left, return_data)) => MessageCallResult::Success(gas_left, return_data),
Ok(FinalizationResult{ gas_left, return_data, apply_state: true }) => MessageCallResult::Success(gas_left, return_data),
Ok(FinalizationResult{ gas_left, return_data, apply_state: false }) => MessageCallResult::Reverted(gas_left, return_data),
_ => MessageCallResult::Failed
}
}
@@ -289,7 +301,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
}
#[cfg_attr(feature="dev", allow(match_ref_pats))]
fn ret(mut self, gas: &U256, data: &ReturnData) -> vm::Result<U256>
fn ret(mut self, gas: &U256, data: &ReturnData, apply_state: bool) -> vm::Result<U256>
where Self: Sized {
let handle_copy = |to: &mut Option<&mut Bytes>| {
to.as_mut().map(|b| **b = data.to_vec());
@@ -309,7 +321,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
vec.extend_from_slice(&*data);
Ok(*gas)
},
OutputPolicy::InitContract(ref mut copy) => {
OutputPolicy::InitContract(ref mut copy) if apply_state => {
let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas);
if return_cost > *gas || data.len() > self.schedule.create_data_limit {
return match self.schedule.exceptional_failed_code_deposit {
@@ -317,12 +329,13 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
false => Ok(*gas)
}
}
handle_copy(copy);
self.state.init_code(&self.origin_info.address, data.to_vec())?;
Ok(*gas - return_cost)
}
},
OutputPolicy::InitContract(_) => {
Ok(*gas)
},
}
}

View File

@@ -15,16 +15,14 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use client::{BlockChainClient, Client, ClientConfig};
use client::{EvmTestClient, BlockChainClient, Client, ClientConfig};
use block::Block;
use ethereum;
use tests::helpers::*;
use spec::Genesis;
use ethjson;
use miner::Miner;
use io::IoChannel;
pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
pub fn json_chain_test(json_data: &[u8]) -> Vec<String> {
::ethcore_logger::init_log();
let tests = ethjson::blockchain::Test::load(json_data).unwrap();
let mut failed = Vec::new();
@@ -42,15 +40,16 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
flush!(" - {}...", name);
let spec = {
let mut spec = match EvmTestClient::spec_from_json(&blockchain.network) {
Some(spec) => (*spec).clone(),
None => {
println!(" - {} | {:?} Ignoring tests because of missing spec", name, blockchain.network);
continue;
}
};
let genesis = Genesis::from(blockchain.genesis());
let state = From::from(blockchain.pre_state.clone());
let mut spec = match era {
ChainEra::Frontier => ethereum::new_frontier_test(),
ChainEra::Homestead => ethereum::new_homestead_test(),
ChainEra::Eip150 => ethereum::new_eip150_test(),
ChainEra::_Eip161 => ethereum::new_eip161_test(),
ChainEra::TransitionTest => ethereum::new_transition_test(),
};
spec.set_genesis_state(state).expect("Failed to overwrite genesis state");
spec.overwrite_genesis_params(genesis);
assert!(spec.is_state_root_valid());
@@ -86,67 +85,69 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
failed
}
mod frontier_era_tests {
use tests::helpers::*;
mod block_tests {
use super::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Frontier)
json_chain_test(json_data)
}
declare_test!{BlockchainTests_bcBlockGasLimitTest, "BlockchainTests/bcBlockGasLimitTest"}
declare_test!{BlockchainTests_bcForkBlockTest, "BlockchainTests/bcForkBlockTest"}
declare_test!{BlockchainTests_bcExploitTest, "BlockchainTests/bcExploitTest"}
declare_test!{BlockchainTests_bcForgedTest, "BlockchainTests/bcForgedTest"}
declare_test!{BlockchainTests_bcForkStressTest, "BlockchainTests/bcForkStressTest"}
declare_test!{BlockchainTests_bcForkUncle, "BlockchainTests/bcForkUncle"}
declare_test!{BlockchainTests_bcGasPricerTest, "BlockchainTests/bcGasPricerTest"}
declare_test!{BlockchainTests_bcInvalidHeaderTest, "BlockchainTests/bcInvalidHeaderTest"}
// TODO [ToDr] Ignored because of incorrect JSON (https://github.com/ethereum/tests/pull/113)
declare_test!{ignore => BlockchainTests_bcInvalidRLPTest, "BlockchainTests/bcInvalidRLPTest"}
declare_test!{BlockchainTests_bcMultiChainTest, "BlockchainTests/bcMultiChainTest"}
declare_test!{BlockchainTests_bcRPC_API_Test, "BlockchainTests/bcRPC_API_Test"}
declare_test!{BlockchainTests_bcStateTest, "BlockchainTests/bcStateTest"}
declare_test!{BlockchainTests_bcRandomBlockhashTest, "BlockchainTests/bcRandomBlockhashTest"}
declare_test!{BlockchainTests_bcTotalDifficultyTest, "BlockchainTests/bcTotalDifficultyTest"}
declare_test!{BlockchainTests_bcUncleHeaderValiditiy, "BlockchainTests/bcUncleHeaderValiditiy"}
declare_test!{BlockchainTests_bcUncleTest, "BlockchainTests/bcUncleTest"}
declare_test!{BlockchainTests_bcValidBlockTest, "BlockchainTests/bcValidBlockTest"}
declare_test!{BlockchainTests_bcWalletTest, "BlockchainTests/bcWalletTest"}
declare_test!{BlockchainTests_RandomTests_bl10251623GO, "BlockchainTests/RandomTests/bl10251623GO"}
declare_test!{BlockchainTests_RandomTests_bl201507071825GO, "BlockchainTests/RandomTests/bl201507071825GO"}
declare_test!{BlockchainTests_GeneralStateTest_stAttackTest, "BlockchainTests/GeneralStateTests/stAttackTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stBadOpcodeTest, "BlockchainTests/GeneralStateTests/stBadOpcode/"}
declare_test!{BlockchainTests_GeneralStateTest_stCallCodes, "BlockchainTests/GeneralStateTests/stCallCodes/"}
declare_test!{BlockchainTests_GeneralStateTest_stCallDelegateCodesCallCodeHomestead, "BlockchainTests/GeneralStateTests/stCallDelegateCodesCallCodeHomestead/"}
declare_test!{BlockchainTests_GeneralStateTest_stCallDelegateCodesHomestead, "BlockchainTests/GeneralStateTests/stCallDelegateCodesHomestead/"}
declare_test!{BlockchainTests_GeneralStateTest_stChangedEIP150, "BlockchainTests/GeneralStateTests/stChangedEIP150/"}
declare_test!{BlockchainTests_GeneralStateTest_stCodeSizeLimit, "BlockchainTests/GeneralStateTests/stCodeSizeLimit/"}
declare_test!{BlockchainTests_GeneralStateTest_stCreateTest, "BlockchainTests/GeneralStateTests/stCreateTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stDelegatecallTestHomestead, "BlockchainTests/GeneralStateTests/stDelegatecallTestHomestead/"}
declare_test!{BlockchainTests_GeneralStateTest_stEIP150singleCodeGasPrices, "BlockchainTests/GeneralStateTests/stEIP150singleCodeGasPrices/"}
declare_test!{BlockchainTests_GeneralStateTest_stEIP150Specific, "BlockchainTests/GeneralStateTests/stEIP150Specific/"}
declare_test!{BlockchainTests_GeneralStateTest_stEIP158Specific, "BlockchainTests/GeneralStateTests/stEIP158Specific/"}
declare_test!{BlockchainTests_GeneralStateTest_stExample, "BlockchainTests/GeneralStateTests/stExample/"}
declare_test!{BlockchainTests_GeneralStateTest_stHomesteadSpecific, "BlockchainTests/GeneralStateTests/stHomesteadSpecific/"}
declare_test!{BlockchainTests_GeneralStateTest_stInitCodeTest, "BlockchainTests/GeneralStateTests/stInitCodeTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stLogTests, "BlockchainTests/GeneralStateTests/stLogTests/"}
declare_test!{BlockchainTests_GeneralStateTest_stMemExpandingEIP150Calls, "BlockchainTests/GeneralStateTests/stMemExpandingEIP150Calls/"}
declare_test!{heavy => BlockchainTests_GeneralStateTest_stMemoryStressTest, "BlockchainTests/GeneralStateTests/stMemoryStressTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stMemoryTest, "BlockchainTests/GeneralStateTests/stMemoryTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stNonZeroCallsTest, "BlockchainTests/GeneralStateTests/stNonZeroCallsTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stPreCompiledContracts, "BlockchainTests/GeneralStateTests/stPreCompiledContracts/"}
declare_test!{heavy => BlockchainTests_GeneralStateTest_stQuadraticComplexityTest, "BlockchainTests/GeneralStateTests/stQuadraticComplexityTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stRandom, "BlockchainTests/GeneralStateTests/stRandom/"}
declare_test!{BlockchainTests_GeneralStateTest_stRecursiveCreate, "BlockchainTests/GeneralStateTests/stRecursiveCreate/"}
declare_test!{BlockchainTests_GeneralStateTest_stRefundTest, "BlockchainTests/GeneralStateTests/stRefundTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stReturnDataTest, "BlockchainTests/GeneralStateTests/stReturnDataTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stRevertTest, "BlockchainTests/GeneralStateTests/stRevertTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stSolidityTest, "BlockchainTests/GeneralStateTests/stSolidityTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stSpecialTest, "BlockchainTests/GeneralStateTests/stSpecialTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stStackTests, "BlockchainTests/GeneralStateTests/stStackTests/"}
declare_test!{BlockchainTests_GeneralStateTest_stStaticCall, "BlockchainTests/GeneralStateTests/stStaticCall/"}
declare_test!{BlockchainTests_GeneralStateTest_stSystemOperationsTest, "BlockchainTests/GeneralStateTests/stSystemOperationsTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stTransactionTest, "BlockchainTests/GeneralStateTests/stTransactionTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stTransitionTest, "BlockchainTests/GeneralStateTests/stTransitionTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stWalletTest, "BlockchainTests/GeneralStateTests/stWalletTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stZeroCallsRevert, "BlockchainTests/GeneralStateTests/stZeroCallsRevert/"}
declare_test!{BlockchainTests_GeneralStateTest_stZeroCallsTest, "BlockchainTests/GeneralStateTests/stZeroCallsTest/"}
declare_test!{BlockchainTests_GeneralStateTest_stZeroKnowledge, "BlockchainTests/GeneralStateTests/stZeroKnowledge/"}
declare_test!{BlockchainTests_TransitionTests_bcEIP158ToByzantium, "BlockchainTests/TransitionTests/bcEIP158ToByzantium/"}
declare_test!{BlockchainTests_TransitionTests_bcFrontierToHomestead, "BlockchainTests/TransitionTests/bcFrontierToHomestead/"}
declare_test!{BlockchainTests_TransitionTests_bcHomesteadToDao, "BlockchainTests/TransitionTests/bcHomesteadToDao/"}
declare_test!{BlockchainTests_TransitionTests_bcHomesteadToEIP150, "BlockchainTests/TransitionTests/bcHomesteadToEIP150/"}
}
mod transition_tests {
use tests::helpers::*;
use super::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::TransitionTest)
}
declare_test!{BlockchainTests_TestNetwork_bcSimpleTransitionTest, "BlockchainTests/TestNetwork/bcSimpleTransitionTest"}
declare_test!{BlockchainTests_TestNetwork_bcTheDaoTest, "BlockchainTests/TestNetwork/bcTheDaoTest"}
declare_test!{BlockchainTests_TestNetwork_bcEIP150Test, "BlockchainTests/TestNetwork/bcEIP150Test"}
}
mod eip150_blockchain_tests {
use tests::helpers::*;
use super::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Eip150)
}
declare_test!{BlockchainTests_EIP150_bcBlockGasLimitTest, "BlockchainTests/EIP150/bcBlockGasLimitTest"}
declare_test!{BlockchainTests_EIP150_bcForkStressTest, "BlockchainTests/EIP150/bcForkStressTest"}
declare_test!{BlockchainTests_EIP150_bcGasPricerTest, "BlockchainTests/EIP150/bcGasPricerTest"}
declare_test!{BlockchainTests_EIP150_bcInvalidHeaderTest, "BlockchainTests/EIP150/bcInvalidHeaderTest"}
declare_test!{BlockchainTests_EIP150_bcInvalidRLPTest, "BlockchainTests/EIP150/bcInvalidRLPTest"}
declare_test!{BlockchainTests_EIP150_bcMultiChainTest, "BlockchainTests/EIP150/bcMultiChainTest"}
declare_test!{BlockchainTests_EIP150_bcRPC_API_Test, "BlockchainTests/EIP150/bcRPC_API_Test"}
declare_test!{BlockchainTests_EIP150_bcStateTest, "BlockchainTests/EIP150/bcStateTest"}
declare_test!{BlockchainTests_EIP150_bcTotalDifficultyTest, "BlockchainTests/EIP150/bcTotalDifficultyTest"}
declare_test!{BlockchainTests_EIP150_bcUncleHeaderValiditiy, "BlockchainTests/EIP150/bcUncleHeaderValiditiy"}
declare_test!{BlockchainTests_EIP150_bcUncleTest, "BlockchainTests/EIP150/bcUncleTest"}
declare_test!{BlockchainTests_EIP150_bcValidBlockTest, "BlockchainTests/EIP150/bcValidBlockTest"}
declare_test!{BlockchainTests_EIP150_bcWalletTest, "BlockchainTests/EIP150/bcWalletTest"}
}

View File

@@ -32,6 +32,8 @@ use trace::{Tracer, NoopTracer};
use trace::{VMTracer, NoopVMTracer};
use bytes::{Bytes, BytesRef};
use trie;
use rlp::RlpStream;
use hash::keccak;
#[derive(Debug, PartialEq, Clone)]
struct CallCreate {
@@ -162,8 +164,8 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
self.ext.log(topics, data)
}
fn ret(self, gas: &U256, data: &ReturnData) -> Result<U256, vm::Error> {
self.ext.ret(gas, data)
fn ret(self, gas: &U256, data: &ReturnData, apply_state: bool) -> Result<U256, vm::Error> {
self.ext.ret(gas, data, apply_state)
}
fn suicide(&mut self, refund_address: &Address) -> vm::Result<()> {
@@ -182,6 +184,10 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
0
}
fn is_static(&self) -> bool {
false
}
fn inc_sstore_clears(&mut self) {
self.ext.inc_sstore_clears()
}
@@ -255,6 +261,14 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
(res.finalize(ex), callcreates)
};
let log_hash = {
let mut rlp = RlpStream::new_list(substate.logs.len());
for l in &substate.logs {
rlp.append(l);
}
keccak(&rlp.drain())
};
match res {
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
Ok(res) => {
@@ -262,6 +276,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
fail_unless(Some(res.gas_left) == vm.gas_left.map(Into::into), "gas_left is incorrect");
let vm_output: Option<Vec<u8>> = vm.output.map(Into::into);
fail_unless(Some(output) == vm_output, "output is incorrect");
fail_unless(Some(log_hash) == vm.logs.map(|h| h.0), "logs are incorrect");
for (address, account) in vm.post_state.unwrap().into_iter() {
let address = address.into();
@@ -295,15 +310,15 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
}
declare_test!{ExecutiveTests_vmArithmeticTest, "VMTests/vmArithmeticTest"}
declare_test!{ExecutiveTests_vmBitwiseLogicOperationTest, "VMTests/vmBitwiseLogicOperationTest"}
declare_test!{ExecutiveTests_vmBitwiseLogicOperationTest, "VMTests/vmBitwiseLogicOperation"}
declare_test!{ExecutiveTests_vmBlockInfoTest, "VMTests/vmBlockInfoTest"}
// TODO [todr] Fails with Signal 11 when using JIT
declare_test!{ExecutiveTests_vmEnvironmentalInfoTest, "VMTests/vmEnvironmentalInfoTest"}
declare_test!{ExecutiveTests_vmIOandFlowOperationsTest, "VMTests/vmIOandFlowOperationsTest"}
declare_test!{heavy => ExecutiveTests_vmInputLimits, "VMTests/vmInputLimits"}
declare_test!{ExecutiveTests_vmEnvironmentalInfoTest, "VMTests/vmEnvironmentalInfo"}
declare_test!{ExecutiveTests_vmIOandFlowOperationsTest, "VMTests/vmIOandFlowOperations"}
declare_test!{ExecutiveTests_vmLogTest, "VMTests/vmLogTest"}
declare_test!{ExecutiveTests_vmPerformanceTest, "VMTests/vmPerformanceTest"}
declare_test!{heavy => ExecutiveTests_vmPerformance, "VMTests/vmPerformance"}
declare_test!{ExecutiveTests_vmPushDupSwapTest, "VMTests/vmPushDupSwapTest"}
declare_test!{ExecutiveTests_vmRandomTest, "VMTests/vmRandomTest"}
declare_test!{ExecutiveTests_vmSha3Test, "VMTests/vmSha3Test"}
declare_test!{ExecutiveTests_vmSystemOperationsTest, "VMTests/vmSystemOperationsTest"}
declare_test!{ExecutiveTests_vmtests, "VMTests/vmtests"}
declare_test!{ExecutiveTests_vmSystemOperationsTest, "VMTests/vmSystemOperations"}
declare_test!{ExecutiveTests_vmTests, "VMTests/vmTests"}

View File

@@ -1,39 +0,0 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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.
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
use super::chain::json_chain_test;
use tests::helpers::*;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Homestead)
}
declare_test!{BlockchainTests_Homestead_bcBlockGasLimitTest, "BlockchainTests/Homestead/bcBlockGasLimitTest"}
declare_test!{BlockchainTests_Homestead_bcForkStressTest, "BlockchainTests/Homestead/bcForkStressTest"}
declare_test!{BlockchainTests_Homestead_bcGasPricerTest, "BlockchainTests/Homestead/bcGasPricerTest"}
declare_test!{BlockchainTests_Homestead_bcInvalidHeaderTest, "BlockchainTests/Homestead/bcInvalidHeaderTest"}
declare_test!{BlockchainTests_Homestead_bcInvalidRLPTest, "BlockchainTests/Homestead/bcInvalidRLPTest"}
declare_test!{BlockchainTests_Homestead_bcMultiChainTest, "BlockchainTests/Homestead/bcMultiChainTest"}
declare_test!{BlockchainTests_Homestead_bcRPC_API_Test, "BlockchainTests/Homestead/bcRPC_API_Test"}
declare_test!{BlockchainTests_Homestead_bcStateTest, "BlockchainTests/Homestead/bcStateTest"}
declare_test!{BlockchainTests_Homestead_bcTotalDifficultyTest, "BlockchainTests/Homestead/bcTotalDifficultyTest"}
declare_test!{BlockchainTests_Homestead_bcUncleHeaderValiditiy, "BlockchainTests/Homestead/bcUncleHeaderValiditiy"}
declare_test!{BlockchainTests_Homestead_bcUncleTest, "BlockchainTests/Homestead/bcUncleTest"}
declare_test!{BlockchainTests_Homestead_bcValidBlockTest, "BlockchainTests/Homestead/bcValidBlockTest"}
declare_test!{BlockchainTests_Homestead_bcWalletTest, "BlockchainTests/Homestead/bcWalletTest"}
declare_test!{BlockchainTests_Homestead_bcShanghaiLove, "BlockchainTests/Homestead/bcShanghaiLove"}
declare_test!{BlockchainTests_Homestead_bcSuicideIssue, "BlockchainTests/Homestead/bcSuicideIssue"}
declare_test!{BlockchainTests_Homestead_bcExploitTest, "BlockchainTests/Homestead/bcExploitTest"}

View File

@@ -21,5 +21,4 @@ mod transaction;
mod executive;
mod state;
mod chain;
mod homestead_chain;
mod trie;

View File

@@ -97,9 +97,8 @@ mod state_tests {
}
declare_test!{GeneralStateTest_stAttackTest, "GeneralStateTests/stAttackTest/"}
declare_test!{GeneralStateTest_stBoundsTest, "GeneralStateTests/stBoundsTest/"}
declare_test!{GeneralStateTest_stBadOpcodeTest, "GeneralStateTests/stBadOpcode/"}
declare_test!{GeneralStateTest_stCallCodes, "GeneralStateTests/stCallCodes/"}
declare_test!{skip => [ "createJS_ExampleContract" ], GeneralStateTest_stCallCreateCallCodeTest, "GeneralStateTests/stCallCreateCallCodeTest/"}
declare_test!{GeneralStateTest_stCallDelegateCodesCallCodeHomestead, "GeneralStateTests/stCallDelegateCodesCallCodeHomestead/"}
declare_test!{GeneralStateTest_stCallDelegateCodesHomestead, "GeneralStateTests/stCallDelegateCodesHomestead/"}
declare_test!{GeneralStateTest_stChangedEIP150, "GeneralStateTests/stChangedEIP150/"}
@@ -108,6 +107,7 @@ mod state_tests {
declare_test!{GeneralStateTest_stDelegatecallTestHomestead, "GeneralStateTests/stDelegatecallTestHomestead/"}
declare_test!{GeneralStateTest_stEIP150singleCodeGasPrices, "GeneralStateTests/stEIP150singleCodeGasPrices/"}
declare_test!{GeneralStateTest_stEIP150Specific, "GeneralStateTests/stEIP150Specific/"}
declare_test!{GeneralStateTest_stEIP158Specific, "GeneralStateTests/stEIP158Specific/"}
declare_test!{GeneralStateTest_stExample, "GeneralStateTests/stExample/"}
declare_test!{GeneralStateTest_stHomesteadSpecific, "GeneralStateTests/stHomesteadSpecific/"}
declare_test!{GeneralStateTest_stInitCodeTest, "GeneralStateTests/stInitCodeTest/"}
@@ -121,15 +121,18 @@ mod state_tests {
declare_test!{GeneralStateTest_stRandom, "GeneralStateTests/stRandom/"}
declare_test!{GeneralStateTest_stRecursiveCreate, "GeneralStateTests/stRecursiveCreate/"}
declare_test!{GeneralStateTest_stRefundTest, "GeneralStateTests/stRefundTest/"}
declare_test!{skip => [ "RevertDepthCreateAddressCollision" ], GeneralStateTest_stRevertTest, "GeneralStateTests/stRevertTest/"}
declare_test!{GeneralStateTest_stReturnDataTest, "GeneralStateTests/stReturnDataTest/"}
declare_test!{GeneralStateTest_stRevertTest, "GeneralStateTests/stRevertTest/"}
declare_test!{GeneralStateTest_stSolidityTest, "GeneralStateTests/stSolidityTest/"}
declare_test!{GeneralStateTest_stSpecialTest, "GeneralStateTests/stSpecialTest/"}
declare_test!{GeneralStateTest_stStackTests, "GeneralStateTests/stStackTests/"}
declare_test!{GeneralStateTest_stStaticCall, "GeneralStateTests/stStaticCall/"}
declare_test!{GeneralStateTest_stSystemOperationsTest, "GeneralStateTests/stSystemOperationsTest/"}
declare_test!{GeneralStateTest_stTransactionTest, "GeneralStateTests/stTransactionTest/"}
declare_test!{GeneralStateTest_stTransitionTest, "GeneralStateTests/stTransitionTest/"}
declare_test!{GeneralStateTest_stWalletTest, "GeneralStateTests/stWalletTest/"}
declare_test!{GeneralStateTest_stZeroCallsRevert, "GeneralStateTests/stZeroCallsRevert/"}
declare_test!{GeneralStateTest_stZeroCallsTest, "GeneralStateTests/stZeroCallsTest/"}
declare_test!{GeneralStateTest_stZeroKnowledge, "GeneralStateTests/stZeroKnowledge/"}
}

View File

@@ -25,7 +25,7 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
let mut failed = Vec::new();
let frontier_schedule = evm::Schedule::new_frontier();
let homestead_schedule = evm::Schedule::new_homestead();
let metropolis_schedule = evm::Schedule::new_metropolis();
let byzantium_schedule = evm::Schedule::new_byzantium();
for (name, test) in tests.into_iter() {
let mut fail_unless = |cond: bool, title: &str| if !cond { failed.push(name.clone()); println!("Transaction failed: {:?}: {:?}", name, title); };
@@ -34,7 +34,7 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
None => &frontier_schedule,
Some(x) if x < 1_150_000 => &frontier_schedule,
Some(x) if x < 3_000_000 => &homestead_schedule,
Some(_) => &metropolis_schedule
Some(_) => &byzantium_schedule
};
let allow_chain_id_of_one = number.map_or(false, |n| n >= 2_675_000);
let allow_unsigned = number.map_or(false, |n| n >= 3_000_000);
@@ -75,18 +75,13 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
failed
}
declare_test!{TransactionTests_ttTransactionTest, "TransactionTests/ttTransactionTest"}
declare_test!{heavy => TransactionTests_tt10mbDataField, "TransactionTests/tt10mbDataField"}
declare_test!{TransactionTests_ttWrongRLPTransaction, "TransactionTests/ttWrongRLPTransaction"}
declare_test!{TransactionTests_Homestead_ttTransactionTest, "TransactionTests/Homestead/ttTransactionTest"}
declare_test!{heavy => TransactionTests_Homestead_tt10mbDataField, "TransactionTests/Homestead/tt10mbDataField"}
declare_test!{TransactionTests_Homestead_ttWrongRLPTransaction, "TransactionTests/Homestead/ttWrongRLPTransaction"}
declare_test!{TransactionTests_RandomTests_tr201506052141PYTHON, "TransactionTests/RandomTests/tr201506052141PYTHON"}
declare_test!{TransactionTests_Homestead_ttTransactionTestEip155VitaliksTests, "TransactionTests/Homestead/ttTransactionTestEip155VitaliksTests"}
declare_test!{TransactionTests_EIP155_ttTransactionTest, "TransactionTests/EIP155/ttTransactionTest"}
declare_test!{TransactionTests_EIP155_ttTransactionTestEip155VitaliksTests, "TransactionTests/EIP155/ttTransactionTestEip155VitaliksTests"}
declare_test!{TransactionTests_EIP155_ttTransactionTestVRule, "TransactionTests/EIP155/ttTransactionTestVRule"}
declare_test!{TransactionTests_Metropolis_ttMetropolisTest, "TransactionTests/Metropolis/ttMetropolisTest"}
declare_test!{TransactionTests_Metropolis_ttTransactionTest, "TransactionTests/Metropolis/ttTransactionTest"}
declare_test!{TransactionTests_Metropolis_ttTransactionTestZeroSig, "TransactionTests/Metropolis/ttTransactionTestZeroSig"}
declare_test!{TransactionTests_ttEip155VitaliksHomesead, "TransactionTests/ttEip155VitaliksHomesead"}
declare_test!{TransactionTests_ttEip155VitaliksEip158, "TransactionTests/ttEip155VitaliksEip158"}
declare_test!{TransactionTests_ttEip158, "TransactionTests/ttEip158"}
declare_test!{TransactionTests_ttFrontier, "TransactionTests/ttFrontier"}
declare_test!{TransactionTests_ttHomestead, "TransactionTests/ttHomestead"}
declare_test!{TransactionTests_ttVRuleEip158, "TransactionTests/ttVRuleEip158"}
declare_test!{TransactionTests_ttWrongRLPFrontier, "TransactionTests/ttWrongRLPFrontier"}
declare_test!{TransactionTests_ttWrongRLPHomestead, "TransactionTests/ttWrongRLPHomestead"}
declare_test!{TransactionTests_ttConstantinople, "TransactionTests/ttConstantinople"}
declare_test!{TransactionTests_ttSpecConstantinople, "TransactionTests/ttSpecConstantinople"}

View File

@@ -70,6 +70,8 @@ pub struct CommonParams {
pub fork_block: Option<(BlockNumber, H256)>,
/// Number of first block where EIP-98 rules begin.
pub eip98_transition: BlockNumber,
/// Number of first block where EIP-658 rules begin.
pub eip658_transition: BlockNumber,
/// Number of first block where EIP-155 rules begin.
pub eip155_transition: BlockNumber,
/// Validate block receipts root.
@@ -125,7 +127,7 @@ impl CommonParams {
schedule.have_static_call = block_number >= self.eip214_transition;
schedule.have_return_data = block_number >= self.eip211_transition;
if block_number >= self.eip210_transition {
schedule.blockhash_gas = 350;
schedule.blockhash_gas = 800;
}
if block_number >= self.dust_protection_transition {
schedule.kill_dust = match self.remove_dust_contracts {
@@ -172,6 +174,7 @@ impl From<ethjson::spec::Params> for CommonParams {
eip210_contract_gas: p.eip210_contract_gas.map_or(1000000.into(), Into::into),
eip211_transition: p.eip211_transition.map_or(BlockNumber::max_value(), Into::into),
eip214_transition: p.eip214_transition.map_or(BlockNumber::max_value(), Into::into),
eip658_transition: p.eip658_transition.map_or(BlockNumber::max_value(), Into::into),
dust_protection_transition: p.dust_protection_transition.map_or(BlockNumber::max_value(), Into::into),
nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into),
remove_dust_contracts: p.remove_dust_contracts.unwrap_or(false),
@@ -229,7 +232,33 @@ pub struct Spec {
genesis_state: PodState,
}
fn load_from<T: AsRef<Path>>(cache_dir: T, s: ethjson::spec::Spec) -> Result<Spec, Error> {
#[cfg(test)]
impl Clone for Spec {
fn clone(&self) -> Spec {
Spec {
name: self.name.clone(),
engine: self.engine.clone(),
data_dir: self.data_dir.clone(),
nodes: self.nodes.clone(),
parent_hash: self.parent_hash.clone(),
transactions_root: self.transactions_root.clone(),
receipts_root: self.receipts_root.clone(),
author: self.author.clone(),
difficulty: self.difficulty.clone(),
gas_limit: self.gas_limit.clone(),
gas_used: self.gas_used.clone(),
timestamp: self.timestamp.clone(),
extra_data: self.extra_data.clone(),
seal_rlp: self.seal_rlp.clone(),
constructors: self.constructors.clone(),
state_root_memo: RwLock::new(*self.state_root_memo.read()),
genesis_state: self.genesis_state.clone(),
}
}
}
/// Load from JSON object.
pub fn load_from<T: AsRef<Path>>(cache_dir: T, s: ethjson::spec::Spec) -> Result<Spec, Error> {
let builtins = s.accounts.builtins().into_iter().map(|p| (p.0.into(), From::from(p.1))).collect();
let g = Genesis::from(s.genesis);
let GenericSeal(seal_rlp) = g.seal.into();

View File

@@ -503,9 +503,10 @@ impl<B: Backend> State<B> {
self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null()))
}
/// Determine whether an account exists and has code.
pub fn exists_and_has_code(&self, a: &Address) -> trie::Result<bool> {
self.ensure_cached(a, RequireCache::CodeSize, false, |a| a.map_or(false, |a| a.code_size().map_or(false, |size| size != 0)))
/// Determine whether an account exists and has code or non-zero nonce.
pub fn exists_and_has_code_or_nonce(&self, a: &Address) -> trie::Result<bool> {
self.ensure_cached(a, RequireCache::CodeSize, false,
|a| a.map_or(false, |a| a.code_hash() != KECCAK_EMPTY || *a.nonce() != self.account_start_nonce))
}
/// Get the balance of account `a`.
@@ -697,15 +698,26 @@ impl<B: Backend> State<B> {
let options = TransactOptions::new(tracer, vm_tracer);
let e = self.execute(env_info, engine, t, options, false)?;
let state_root = if env_info.number < engine.params().eip98_transition || env_info.number < engine.params().validate_receipts_transition {
let eip658 = env_info.number >= engine.params().eip658_transition;
let no_intermediate_commits =
eip658 ||
(env_info.number >= engine.params().eip98_transition && env_info.number >= engine.params().validate_receipts_transition);
let state_root = if no_intermediate_commits {
None
} else {
self.commit()?;
Some(self.root().clone())
};
let status_byte = if eip658 {
Some(if e.exception.is_some() { 0 } else { 1 })
} else {
None
};
let output = e.output;
let receipt = Receipt::new(state_root, e.cumulative_gas_used, e.logs);
let receipt = Receipt::new(state_root, status_byte, e.cumulative_gas_used, e.logs);
trace!(target: "state", "Transaction receipt: {:?}", receipt);
Ok(ApplyOutcome {

View File

@@ -24,7 +24,7 @@ fn test_blockhash_eip210(factory: Factory) {
let test_blockhash_contract = "73fffffffffffffffffffffffffffffffffffffffe33141561007a57600143036020526000356101006020510755600061010060205107141561005057600035610100610100602051050761010001555b6000620100006020510714156100755760003561010062010000602051050761020001555b61014a565b4360003512151561009057600060405260206040f35b610100600035430312156100b357610100600035075460605260206060f3610149565b62010000600035430312156100d157600061010060003507146100d4565b60005b156100f6576101006101006000350507610100015460805260206080f3610148565b630100000060003543031215610116576000620100006000350714610119565b60005b1561013c57610100620100006000350507610200015460a052602060a0f3610147565b600060c052602060c0f35b5b5b5b5b";
let blockhash_contract_code = Arc::new(test_blockhash_contract.from_hex().unwrap());
let blockhash_contract_code_hash = keccak(blockhash_contract_code.as_ref());
let engine = TestEngine::new_metropolis();
let engine = TestEngine::new_constantinople();
let mut env_info = EnvInfo::default();
// populate state with 256 last hashes

View File

@@ -42,15 +42,6 @@ use transaction::{Action, Transaction, SignedTransaction};
use rlp::{self, RlpStream};
use views::BlockView;
#[cfg(feature = "json-tests")]
pub enum ChainEra {
Frontier,
Homestead,
Eip150,
_Eip161,
TransitionTest,
}
pub struct TestEngine {
engine: Arc<Engine>,
max_depth: usize,
@@ -64,9 +55,16 @@ impl TestEngine {
}
}
pub fn new_metropolis() -> TestEngine {
pub fn new_byzantium() -> TestEngine {
TestEngine {
engine: ethereum::new_metropolis_test().engine,
engine: ethereum::new_byzantium_test().engine,
max_depth: 0,
}
}
pub fn new_constantinople() -> TestEngine {
TestEngine {
engine: ethereum::new_constantinople_test().engine,
max_depth: 0,
}
}
@@ -427,5 +425,8 @@ pub fn get_default_ethash_params() -> EthashParams {
max_gas_limit: U256::max_value(),
min_gas_price_transition: u64::max_value(),
min_gas_price: U256::zero(),
eip649_transition: u64::max_value(),
eip649_delay: 3_000_000,
eip649_reward: None,
}
}

View File

@@ -43,6 +43,10 @@ pub enum Error {
MutableCallInStaticContext,
/// Wasm error
Wasm,
/// Contract tried to access past the return data buffer.
OutOfBounds,
/// Execution has been reverted with REVERT instruction.
Reverted,
}
impl<'a> From<&'a VmError> for Error {
@@ -57,6 +61,8 @@ impl<'a> From<&'a VmError> for Error {
VmError::Wasm { .. } => Error::Wasm,
VmError::Internal(_) => Error::Internal,
VmError::MutableCallInStaticContext => Error::MutableCallInStaticContext,
VmError::OutOfBounds => Error::OutOfBounds,
VmError::Reverted => Error::Reverted,
}
}
}
@@ -80,6 +86,8 @@ impl fmt::Display for Error {
Wasm => "Wasm runtime error",
Internal => "Internal error",
MutableCallInStaticContext => "Mutable Call In Static Context",
OutOfBounds => "Out of bounds",
Reverted => "Reverted",
};
message.fmt(f)
}
@@ -98,6 +106,8 @@ impl Encodable for Error {
BuiltIn => 6,
MutableCallInStaticContext => 7,
Wasm => 8,
OutOfBounds => 9,
Reverted => 10,
};
s.append_internal(&value);
@@ -118,6 +128,8 @@ impl Decodable for Error {
6 => Ok(BuiltIn),
7 => Ok(MutableCallInStaticContext),
8 => Ok(Wasm),
9 => Ok(OutOfBounds),
10 => Ok(Reverted),
_ => Err(DecoderError::Custom("Invalid error type")),
}
}