[beta] Byzantium updates (#6529)
* fix modexp bug: return 0 if base=0 (#6424) * Running state test using parity-evm (#6355) * Initial version of state tests. * Refactor state to support tracing. * Unify TransactResult. * Add test. * Byzantium updates
This commit is contained in:
parent
d8bf5fc848
commit
bb311e838b
23
Cargo.lock
generated
23
Cargo.lock
generated
@ -106,6 +106,17 @@ version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bigint"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -175,7 +186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
[[package]]
|
||||
name = "bn"
|
||||
version = "0.4.4"
|
||||
source = "git+https://github.com/paritytech/bn#b97e95a45f4484a41a515338c4f0e093bf6675e0"
|
||||
source = "git+https://github.com/paritytech/bn#c9831a8d10d55045692394cbc10efe0321ddb16f"
|
||||
dependencies = [
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -311,6 +322,11 @@ name = "crossbeam"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "crypt32-sys"
|
||||
version = "0.2.0"
|
||||
@ -492,7 +508,7 @@ dependencies = [
|
||||
name = "ethcore-bigint"
|
||||
version = "0.1.3"
|
||||
dependencies = [
|
||||
"bigint 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -876,6 +892,7 @@ dependencies = [
|
||||
"docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore 1.7.0",
|
||||
"ethcore-util 1.7.2",
|
||||
"ethjson 0.1.0",
|
||||
"evm 0.1.0",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3106,6 +3123,7 @@ dependencies = [
|
||||
"checksum base-x 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f59103b47307f76e03bef1633aec7fa9e29bfb5aa6daf5a334f94233c71f6c1"
|
||||
"checksum base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9605ba46d61df0410d8ac686b0007add8172eba90e8e909c347856fe794d8c"
|
||||
"checksum bigint 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0673c930652d3d4d6dcd5c45b5db4fa5f8f33994d7323618c43c083b223e8c"
|
||||
"checksum bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5442186ef6560f30f1ee4b9c1e4c87a35a6879d3644550cc248ec2b955eb5fcd"
|
||||
"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e"
|
||||
"checksum bit-set 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6e1e6fb1c9e3d6fcdec57216a74eaa03e41f52a22f13a16438251d8e88b89da"
|
||||
"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
|
||||
@ -3131,6 +3149,7 @@ dependencies = [
|
||||
"checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd"
|
||||
"checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5"
|
||||
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
|
||||
"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda"
|
||||
"checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec"
|
||||
"checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "<none>"
|
||||
"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9"
|
||||
|
97
ethcore/benches/evm.rs
Normal file
97
ethcore/benches/evm.rs
Normal file
@ -0,0 +1,97 @@
|
||||
// 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/>.
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
extern crate ethcore_util as util;
|
||||
extern crate rand;
|
||||
extern crate bn;
|
||||
extern crate crypto;
|
||||
extern crate rustc_serialize;
|
||||
extern crate ethkey;
|
||||
|
||||
use self::test::{Bencher};
|
||||
use rand::{StdRng};
|
||||
|
||||
|
||||
#[bench]
|
||||
fn bn_128_pairing(b: &mut Bencher) {
|
||||
use bn::{pairing, G1, G2, Fr, Group};
|
||||
|
||||
let rng = &mut ::rand::thread_rng();
|
||||
|
||||
let sk0 = Fr::random(rng);
|
||||
let sk1 = Fr::random(rng);
|
||||
|
||||
let pk0 = G1::one() * sk0;
|
||||
let pk1 = G2::one() * sk1;
|
||||
|
||||
b.iter(|| {
|
||||
let _ = pairing(pk0, pk1);
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bn_128_mul(b: &mut Bencher) {
|
||||
use bn::{AffineG1, G1, Fr, Group};
|
||||
|
||||
let mut rng = StdRng::new().unwrap();
|
||||
let p: G1 = G1::random(&mut rng);
|
||||
let fr = Fr::random(&mut rng);
|
||||
|
||||
b.iter(|| {
|
||||
let _ = AffineG1::from_jacobian(p * fr);
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn sha256(b: &mut Bencher) {
|
||||
use crypto::sha2::Sha256;
|
||||
use crypto::digest::Digest;
|
||||
|
||||
let mut input: [u8; 256] = [0; 256];
|
||||
let mut out = [0; 32];
|
||||
|
||||
b.iter(|| {
|
||||
let mut sha = Sha256::new();
|
||||
sha.input(&input);
|
||||
sha.result(&mut input[0..32]);
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ecrecover(b: &mut Bencher) {
|
||||
use rustc_serialize::hex::FromHex;
|
||||
use ethkey::{Signature, recover as ec_recover};
|
||||
use util::H256;
|
||||
let input = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
|
||||
let hash = H256::from_slice(&input[0..32]);
|
||||
let v = H256::from_slice(&input[32..64]);
|
||||
let r = H256::from_slice(&input[64..96]);
|
||||
let s = H256::from_slice(&input[96..128]);
|
||||
|
||||
let bit = match v[31] {
|
||||
27 | 28 if &v.0[..31] == &[0; 31] => v[31] - 27,
|
||||
_ => { return; },
|
||||
};
|
||||
|
||||
let s = Signature::from_rsv(&r, &s, bit);
|
||||
b.iter(|| {
|
||||
let _ = ec_recover(&s, &hash);
|
||||
});
|
||||
}
|
||||
|
@ -69,6 +69,10 @@ pub enum Error {
|
||||
Internal(String),
|
||||
/// Wasm runtime error
|
||||
Wasm(String),
|
||||
/// Out of bounds access in RETURNDATACOPY.
|
||||
OutOfBounds,
|
||||
/// Execution has been reverted with REVERT.
|
||||
Reverted,
|
||||
}
|
||||
|
||||
impl From<Box<trie::TrieError>> for Error {
|
||||
@ -96,6 +100,8 @@ impl fmt::Display for Error {
|
||||
Internal(ref msg) => write!(f, "Internal error: {}", msg),
|
||||
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
|
||||
Wasm(ref msg) => write!(f, "Internal error: {}", msg),
|
||||
OutOfBounds => write!(f, "Out of bounds"),
|
||||
Reverted => write!(f, "Reverted"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -179,7 +185,7 @@ impl Finalize for Result<GasLeft> {
|
||||
fn finalize<E: Ext>(self, ext: E) -> Result<FinalizationResult> {
|
||||
match self {
|
||||
Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { gas_left: gas_left, apply_state: true, return_data: ReturnData::empty() }),
|
||||
Ok(GasLeft::NeedsReturn {gas_left, data, apply_state}) => ext.ret(&gas_left, &data).map(|gas_left| FinalizationResult {
|
||||
Ok(GasLeft::NeedsReturn {gas_left, data, apply_state}) => ext.ret(&gas_left, &data, apply_state).map(|gas_left| FinalizationResult {
|
||||
gas_left: gas_left,
|
||||
apply_state: apply_state,
|
||||
return_data: data,
|
||||
|
@ -29,7 +29,12 @@ pub enum ContractCreateResult {
|
||||
Created(Address, U256),
|
||||
/// Returned when contract creation failed.
|
||||
/// VM doesn't have to know the reason.
|
||||
Failed
|
||||
Failed,
|
||||
/// Returned when contract creation failed.
|
||||
/// VM doesn't have to know the reason.
|
||||
FailedInStaticCall,
|
||||
/// Reverted with REVERT.
|
||||
Reverted(U256, ReturnData),
|
||||
}
|
||||
|
||||
/// Result of externalities call function.
|
||||
@ -39,7 +44,10 @@ pub enum MessageCallResult {
|
||||
Success(U256, ReturnData),
|
||||
/// Returned when message call failed.
|
||||
/// VM doesn't have to know the reason.
|
||||
Failed
|
||||
Failed,
|
||||
/// Returned when message call was reverted.
|
||||
/// Contains gas left and output data.
|
||||
Reverted(U256, ReturnData),
|
||||
}
|
||||
|
||||
/// Specifies how an address is calculated for a new contract.
|
||||
@ -109,7 +117,7 @@ pub trait Ext {
|
||||
|
||||
/// Should be called when transaction calls `RETURN` opcode.
|
||||
/// Returns gas_left if cost of returning the data is not too high.
|
||||
fn ret(self, gas: &U256, data: &ReturnData) -> evm::Result<U256>;
|
||||
fn ret(self, gas: &U256, data: &ReturnData, apply_state: bool) -> evm::Result<U256>;
|
||||
|
||||
/// Should be called when contract commits suicide.
|
||||
/// Address to which funds should be refunded.
|
||||
@ -138,4 +146,7 @@ pub trait Ext {
|
||||
|
||||
/// Trace the finalised execution of a single instruction.
|
||||
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
|
||||
|
||||
/// Check if running in static context.
|
||||
fn is_static(&self) -> bool;
|
||||
}
|
||||
|
@ -319,6 +319,9 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
let contract_code = self.mem.read_slice(init_off, init_size);
|
||||
let can_create = ext.balance(¶ms.address)? >= endowment && ext.depth() < ext.schedule().max_depth;
|
||||
|
||||
// clear return data buffer before creating new call frame.
|
||||
self.return_data = ReturnData::empty();
|
||||
|
||||
if !can_create {
|
||||
stack.push(U256::zero());
|
||||
return Ok(InstructionResult::UnusedGas(create_gas));
|
||||
@ -330,10 +333,18 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
stack.push(address_to_u256(address));
|
||||
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater.")))
|
||||
},
|
||||
ContractCreateResult::Reverted(gas_left, return_data) => {
|
||||
stack.push(U256::zero());
|
||||
self.return_data = return_data;
|
||||
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater.")))
|
||||
},
|
||||
ContractCreateResult::Failed => {
|
||||
stack.push(U256::zero());
|
||||
Ok(InstructionResult::Ok)
|
||||
}
|
||||
},
|
||||
ContractCreateResult::FailedInStaticCall => {
|
||||
Err(evm::Error::MutableCallInStaticContext)
|
||||
},
|
||||
};
|
||||
},
|
||||
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => {
|
||||
@ -344,8 +355,10 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
let code_address = stack.pop_back();
|
||||
let code_address = u256_to_address(&code_address);
|
||||
|
||||
let value = if instruction == instructions::DELEGATECALL || instruction == instructions::STATICCALL {
|
||||
let value = if instruction == instructions::DELEGATECALL {
|
||||
None
|
||||
} else if instruction == instructions::STATICCALL {
|
||||
Some(U256::zero())
|
||||
} else {
|
||||
Some(stack.pop_back())
|
||||
};
|
||||
@ -364,6 +377,9 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
// Get sender & receive addresses, check if we have balance
|
||||
let (sender_address, receive_address, has_balance, call_type) = match instruction {
|
||||
instructions::CALL => {
|
||||
if ext.is_static() && value.map_or(false, |v| !v.is_zero()) {
|
||||
return Err(evm::Error::MutableCallInStaticContext);
|
||||
}
|
||||
let has_balance = ext.balance(¶ms.address)? >= value.expect("value set for all but delegate call; qed");
|
||||
(¶ms.address, &code_address, has_balance, CallType::Call)
|
||||
},
|
||||
@ -372,10 +388,13 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
(¶ms.address, ¶ms.address, has_balance, CallType::CallCode)
|
||||
},
|
||||
instructions::DELEGATECALL => (¶ms.sender, ¶ms.address, true, CallType::DelegateCall),
|
||||
instructions::STATICCALL => (¶ms.sender, ¶ms.address, true, CallType::StaticCall),
|
||||
instructions::STATICCALL => (¶ms.address, &code_address, true, CallType::StaticCall),
|
||||
_ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction))
|
||||
};
|
||||
|
||||
// clear return data buffer before creating new call frame.
|
||||
self.return_data = ReturnData::empty();
|
||||
|
||||
let can_call = has_balance && ext.depth() < ext.schedule().max_depth;
|
||||
if !can_call {
|
||||
stack.push(U256::zero());
|
||||
@ -394,12 +413,17 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
MessageCallResult::Success(gas_left, data) => {
|
||||
stack.push(U256::one());
|
||||
self.return_data = data;
|
||||
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater then current one")))
|
||||
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater than current one")))
|
||||
},
|
||||
MessageCallResult::Reverted(gas_left, data) => {
|
||||
stack.push(U256::zero());
|
||||
self.return_data = data;
|
||||
Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater than current one")))
|
||||
},
|
||||
MessageCallResult::Failed => {
|
||||
stack.push(U256::zero());
|
||||
Ok(InstructionResult::Ok)
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
instructions::RETURN => {
|
||||
@ -537,6 +561,14 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
Self::copy_data_to_memory(&mut self.mem, stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8]));
|
||||
},
|
||||
instructions::RETURNDATACOPY => {
|
||||
{
|
||||
let source_offset = stack.peek(1);
|
||||
let size = stack.peek(2);
|
||||
let return_data_len = U256::from(self.return_data.len());
|
||||
if source_offset.overflow_add(*size).0 > return_data_len {
|
||||
return Err(evm::Error::OutOfBounds);
|
||||
}
|
||||
}
|
||||
Self::copy_data_to_memory(&mut self.mem, stack, &*self.return_data);
|
||||
},
|
||||
instructions::CODECOPY => {
|
||||
|
@ -111,6 +111,8 @@ pub struct Schedule {
|
||||
pub have_return_data: bool,
|
||||
/// Kill basic accounts below this balance if touched.
|
||||
pub kill_dust: CleanDustMode,
|
||||
/// Enable EIP-86 rules
|
||||
pub eip86: bool,
|
||||
}
|
||||
|
||||
/// Dust accounts cleanup mode.
|
||||
@ -184,17 +186,17 @@ impl Schedule {
|
||||
blockhash_gas: 20,
|
||||
have_static_call: false,
|
||||
kill_dust: CleanDustMode::Off,
|
||||
eip86: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Schedule for the Metropolis of the Ethereum main net.
|
||||
pub fn new_metropolis() -> Schedule {
|
||||
/// Schedule for the Byzantium fork of the Ethereum main net.
|
||||
pub fn new_byzantium() -> Schedule {
|
||||
let mut schedule = Self::new_post_eip150(24576, true, true, true);
|
||||
schedule.have_create2 = true;
|
||||
schedule.have_revert = true;
|
||||
schedule.have_static_call = true;
|
||||
schedule.have_return_data = true;
|
||||
schedule.blockhash_gas = 350;
|
||||
schedule
|
||||
}
|
||||
|
||||
@ -246,6 +248,7 @@ impl Schedule {
|
||||
blockhash_gas: 20,
|
||||
have_static_call: false,
|
||||
kill_dust: CleanDustMode::Off,
|
||||
eip86: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,7 +163,16 @@ impl<'a> Runtime<'a> {
|
||||
ext::ContractCreateResult::Failed => {
|
||||
trace!(target: "wasm", "runtime: create contract fail");
|
||||
Ok(Some((-1i32).into()))
|
||||
}
|
||||
},
|
||||
ext::ContractCreateResult::Reverted(gas_left, _) => {
|
||||
trace!(target: "wasm", "runtime: create contract reverted");
|
||||
self.gas_counter = self.gas_limit - gas_left.low_u64();
|
||||
Ok(Some((-1i32).into()))
|
||||
},
|
||||
ext::ContractCreateResult::FailedInStaticCall => {
|
||||
trace!(target: "wasm", "runtime: create contract called in static context");
|
||||
Err(interpreter::Error::Trap("CREATE in static context".to_owned()))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -927,6 +927,7 @@ mod tests {
|
||||
fn check_receipts() {
|
||||
let receipts = (0..5).map(|_| Receipt {
|
||||
state_root: Some(H256::random()),
|
||||
status_code: None,
|
||||
gas_used: 21_000u64.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: Vec::new(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "Metropolis (Test)",
|
||||
"name": "Byzantium (Test)",
|
||||
"engine": {
|
||||
"Ethash": {
|
||||
"params": {
|
||||
@ -7,27 +7,31 @@
|
||||
"minimumDifficulty": "0x020000",
|
||||
"difficultyBoundDivisor": "0x0800",
|
||||
"durationLimit": "0x0d",
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"homesteadTransition": "0x0",
|
||||
"eip150Transition": "0x0",
|
||||
"eip155Transition": "0x0",
|
||||
"eip160Transition": "0x0",
|
||||
"eip161abcTransition": "0x0",
|
||||
"eip161dTransition": "0x0",
|
||||
"maxCodeSize": 24576
|
||||
"maxCodeSize": 24576,
|
||||
"eip649Reward": "0x29A2241AF62C0000",
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"eip100bTransition": "0x0",
|
||||
"eip649Transition": "0x0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1",
|
||||
"eip98Transition": "0x0",
|
||||
"eip86Transition": "0x0",
|
||||
"eip98Transition": "0xffffffffffffffff",
|
||||
"eip140Transition": "0x0",
|
||||
"eip210Transition": "0x0"
|
||||
"eip211Transition": "0x0",
|
||||
"eip214Transition": "0x0",
|
||||
"eip658Transition": "0x0"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
@ -47,6 +51,10 @@
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "0x00", "pricing": { "modexp": { "divisor": 20 } } } },
|
||||
"0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": "0x00", "pricing": { "linear": { "base": 500, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": "0x00", "pricing": { "linear": { "base": 40000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": "0x00", "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }
|
||||
}
|
||||
}
|
61
ethcore/res/ethereum/constantinople_test.json
Normal file
61
ethcore/res/ethereum/constantinople_test.json
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "Byzantium (Test)",
|
||||
"engine": {
|
||||
"Ethash": {
|
||||
"params": {
|
||||
"gasLimitBoundDivisor": "0x0400",
|
||||
"minimumDifficulty": "0x020000",
|
||||
"difficultyBoundDivisor": "0x0800",
|
||||
"durationLimit": "0x0d",
|
||||
"homesteadTransition": "0x0",
|
||||
"eip150Transition": "0x0",
|
||||
"eip155Transition": "0x0",
|
||||
"eip160Transition": "0x0",
|
||||
"eip161abcTransition": "0x0",
|
||||
"eip161dTransition": "0x0",
|
||||
"maxCodeSize": 24576,
|
||||
"eip649Reward": "0x29A2241AF62C0000",
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"eip100bTransition": "0x0",
|
||||
"eip649Transition": "0x0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1",
|
||||
"eip98Transition": "0xffffffffffffffff",
|
||||
"eip140Transition": "0x0",
|
||||
"eip210Transition": "0x0",
|
||||
"eip211Transition": "0x0",
|
||||
"eip214Transition": "0x0",
|
||||
"eip658Transition": "0x0"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
"ethereum": {
|
||||
"nonce": "0x0000000000000042",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"difficulty": "0x400000000",
|
||||
"author": "0x0000000000000000000000000000000000000000",
|
||||
"timestamp": "0x00",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
|
||||
"gasLimit": "0x1388"
|
||||
},
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "0x00", "pricing": { "modexp": { "divisor": 100 } } } },
|
||||
"0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": "0x00", "pricing": { "linear": { "base": 500, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": "0x00", "pricing": { "linear": { "base": 2000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": "0x00", "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }
|
||||
}
|
||||
}
|
@ -190,10 +190,10 @@
|
||||
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "0x7fffffffffffff", "pricing": { "modexp": { "divisor": 20 } } } },
|
||||
"0000000000000000000000000000000000000006": { "builtin": { "name": "bn128_add", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000007": { "builtin": { "name": "bn128_mul", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000008": { "builtin": { "name": "bn128_pairing", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 999999, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "0x7fffffffffffff", "pricing": { "modexp": { "divisor": 100 } } } },
|
||||
"0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 500, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": "0x7fffffffffffff", "pricing": { "linear": { "base": 2000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": "0x7fffffffffffff", "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
|
||||
"3282791d6fd713f1e94f4bfd565eaa78b3a0599d": {
|
||||
"balance": "1337000000000000000000"
|
||||
},
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit ef191fdc61cf76cdb9cdc147465fb447304b0ed2
|
||||
Subproject commit 9b722a014a2b2c9ea6eac456fe01a5c3dd1042a8
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "EIP150.1b hard-fork consensus test",
|
||||
"name": "Transition consensus test spec template",
|
||||
"engine": {
|
||||
"Ethash": {
|
||||
"params": {
|
||||
@ -9,132 +9,16 @@
|
||||
"durationLimit": "0x0d",
|
||||
"blockReward": "0x4563918244F40000",
|
||||
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
|
||||
"homesteadTransition": "0x5",
|
||||
"daoHardforkTransition": "0x8",
|
||||
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
|
||||
"daoHardforkAccounts": [
|
||||
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
|
||||
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
|
||||
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
|
||||
"0xecd135fa4f61a655311e86238c92adcd779555d2",
|
||||
"0x1975bd06d486162d5dc297798dfc41edd5d160a7",
|
||||
"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6",
|
||||
"0x319f70bab6845585f412ec7724b744fec6095c85",
|
||||
"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936",
|
||||
"0x5c8536898fbb74fc7445814902fd08422eac56d0",
|
||||
"0x6966ab0d485353095148a2155858910e0965b6f9",
|
||||
"0x779543a0491a837ca36ce8c635d6154e3c4911a6",
|
||||
"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c",
|
||||
"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5",
|
||||
"0x9c50426be05db97f5d64fc54bf89eff947f0a321",
|
||||
"0x200450f06520bdd6c527622a273333384d870efb",
|
||||
"0xbe8539bfe837b67d1282b2b1d61c3f723966f049",
|
||||
"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb",
|
||||
"0xf1385fb24aad0cd7432824085e42aff90886fef5",
|
||||
"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091",
|
||||
"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd",
|
||||
"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6",
|
||||
"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7",
|
||||
"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5",
|
||||
"0x24c4d950dfd4dd1902bbed3508144a54542bba94",
|
||||
"0x9f27daea7aca0aa0446220b98d028715e3bc803d",
|
||||
"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90",
|
||||
"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b",
|
||||
"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf",
|
||||
"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d",
|
||||
"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6",
|
||||
"0x492ea3bb0f3315521c31f273e565b868fc090f17",
|
||||
"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00",
|
||||
"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416",
|
||||
"0xceaeb481747ca6c540a000c1f3641f8cef161fa7",
|
||||
"0xcc34673c6c40e791051898567a1222daf90be287",
|
||||
"0x579a80d909f346fbfb1189493f521d7f48d52238",
|
||||
"0xe308bd1ac5fda103967359b2712dd89deffb7973",
|
||||
"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c",
|
||||
"0xac1ecab32727358dba8962a0f3b261731aad9723",
|
||||
"0x4fd6ace747f06ece9c49699c7cabc62d02211f75",
|
||||
"0x440c59b325d2997a134c2c7c60a8c61611212bad",
|
||||
"0x4486a3d68fac6967006d7a517b889fd3f98c102b",
|
||||
"0x9c15b54878ba618f494b38f0ae7443db6af648ba",
|
||||
"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f",
|
||||
"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241",
|
||||
"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50",
|
||||
"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b",
|
||||
"0xb9637156d330c0d605a791f1c31ba5890582fe1c",
|
||||
"0x6131c42fa982e56929107413a9d526fd99405560",
|
||||
"0x1591fc0f688c81fbeb17f5426a162a7024d430c2",
|
||||
"0x542a9515200d14b68e934e9830d91645a980dd7a",
|
||||
"0xc4bbd073882dd2add2424cf47d35213405b01324",
|
||||
"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4",
|
||||
"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb",
|
||||
"0x3ba4d81db016dc2890c81f3acec2454bff5aada5",
|
||||
"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab",
|
||||
"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1",
|
||||
"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5",
|
||||
"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53",
|
||||
"0x97f43a37f595ab5dd318fb46e7a155eae057317a",
|
||||
"0x52c5317c848ba20c7504cb2c8052abd1fde29d03",
|
||||
"0x4863226780fe7c0356454236d3b1c8792785748d",
|
||||
"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479",
|
||||
"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c",
|
||||
"0x057b56736d32b86616a10f619859c6cd6f59092a",
|
||||
"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192",
|
||||
"0x304a554a310c7e546dfe434669c62820b7d83490",
|
||||
"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79",
|
||||
"0x4deb0033bb26bc534b197e61d19e0733e5679784",
|
||||
"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a",
|
||||
"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b",
|
||||
"0x4fa802324e929786dbda3b8820dc7834e9134a2a",
|
||||
"0x9da397b9e80755301a3b32173283a91c0ef6c87e",
|
||||
"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6",
|
||||
"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9",
|
||||
"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f",
|
||||
"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76",
|
||||
"0x12e626b0eebfe86a56d633b9864e389b45dcb260",
|
||||
"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7",
|
||||
"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5",
|
||||
"0xd164b088bd9108b60d0ca3751da4bceb207b0782",
|
||||
"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b",
|
||||
"0x1cba23d343a983e9b5cfd19496b9a9701ada385f",
|
||||
"0xa82f360a8d3455c5c41366975bde739c37bfeb8a",
|
||||
"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339",
|
||||
"0x005f5cee7a43331d5a3d3eec71305925a62f34b6",
|
||||
"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d",
|
||||
"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e",
|
||||
"0xbc07118b9ac290e4622f5e77a0853539789effbe",
|
||||
"0x47e7aa56d6bdf3f36be34619660de61275420af8",
|
||||
"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225",
|
||||
"0xadf80daec7ba8dcf15392f1ac611fff65d94f880",
|
||||
"0x5524c55fb03cf21f549444ccbecb664d0acad706",
|
||||
"0x40b803a9abce16f50f36a77ba41180eb90023925",
|
||||
"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
|
||||
"0x17802f43a0137c506ba92291391a8a8f207f487d",
|
||||
"0x253488078a4edf4d6f42f113d1e62836a942cf1a",
|
||||
"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915",
|
||||
"0xb136707642a4ea12fb4bae820f03d2562ebff487",
|
||||
"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940",
|
||||
"0xf14c14075d6c4ed84b86798af0956deef67365b5",
|
||||
"0xca544e5c4687d109611d0f8f928b53a25af72448",
|
||||
"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
|
||||
"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7",
|
||||
"0x6d87578288b6cb5549d5076a207456a1f6a63dc0",
|
||||
"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e",
|
||||
"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
|
||||
"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2",
|
||||
"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
|
||||
"0xd343b217de44030afaa275f54d31a9317c7f441e",
|
||||
"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
|
||||
"0xda2fef9e4a3230988ff17df2165440f37e8b1708",
|
||||
"0xf4c64518ea10f995918a454158c6b61407ea345c",
|
||||
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
|
||||
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
|
||||
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
|
||||
],
|
||||
"eip150Transition": "0xa",
|
||||
"eip155Transition": "0x7fffffffffffffff",
|
||||
"eip160Transition": "0x7fffffffffffffff",
|
||||
"eip161abcTransition": "0x7fffffffffffffff",
|
||||
"eip161dTransition": "0x7fffffffffffffff"
|
||||
"eip155Transition": "5",
|
||||
"homesteadTransition": "0",
|
||||
"eip150Transition": "0",
|
||||
"eip160Transition": "0",
|
||||
"eip161abcTransition": "0",
|
||||
"eip161dTransition": "0",
|
||||
"maxCodeSize": 24576,
|
||||
"eip649Reward": "0x29A2241AF62C0000",
|
||||
"eip100bTransition": "5",
|
||||
"eip649Transition": "5"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -143,8 +27,12 @@
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1",
|
||||
"eip98Transition": "0x7fffffffffffff",
|
||||
"eip86Transition": "0x7fffffffffffff"
|
||||
"eip98Transition": "0xffffffffffffffff",
|
||||
"eip140Transition": "5",
|
||||
"eip211Transition": "5",
|
||||
"eip214Transition": "5",
|
||||
"eip155Transition": "5",
|
||||
"eip658Transition": "5"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
@ -161,9 +49,13 @@
|
||||
"gasLimit": "0x1388"
|
||||
},
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "5", "pricing": { "modexp": { "divisor": 100 } } } },
|
||||
"0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": "5", "pricing": { "linear": { "base": 500, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": "5", "pricing": { "linear": { "base": 2000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": "5", "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }
|
||||
}
|
||||
}
|
||||
|
@ -2039,6 +2039,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![
|
||||
@ -2048,6 +2049,7 @@ mod tests {
|
||||
},
|
||||
Receipt {
|
||||
state_root: Some(H256::default()),
|
||||
status_code: None,
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: vec![
|
||||
@ -2057,6 +2059,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![
|
||||
|
@ -61,7 +61,7 @@ struct Linear {
|
||||
}
|
||||
|
||||
/// A special pricing model for modular exponentiation.
|
||||
struct Modexp {
|
||||
struct ModexpPricer {
|
||||
divisor: usize,
|
||||
}
|
||||
|
||||
@ -71,7 +71,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];
|
||||
@ -85,17 +98,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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -135,7 +180,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
|
||||
@ -144,6 +189,12 @@ impl From<ethjson::spec::Builtin> for Builtin {
|
||||
}
|
||||
})
|
||||
}
|
||||
ethjson::spec::Pricing::AltBn128Pairing(pricer) => {
|
||||
Box::new(AltBn128PairingPricer {
|
||||
base: pricer.base,
|
||||
pair: pricer.pair,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Builtin {
|
||||
@ -162,9 +213,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),
|
||||
}
|
||||
}
|
||||
@ -266,6 +317,38 @@ impl Impl for Ripemd160 {
|
||||
}
|
||||
}
|
||||
|
||||
// calculate modexp: exponentiation by squaring. the `num` crate has pow, but not modular.
|
||||
fn modexp(mut base: BigUint, mut exp: BigUint, modulus: BigUint) -> BigUint {
|
||||
use num::Integer;
|
||||
|
||||
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();
|
||||
base = base % &modulus;
|
||||
|
||||
// fast path for base divisible by modulus.
|
||||
if base.is_zero() { return BigUint::zero() }
|
||||
while !exp.is_zero() {
|
||||
if exp.is_odd() {
|
||||
result = (result * &base) % &modulus;
|
||||
}
|
||||
|
||||
exp = exp >> 1;
|
||||
base = (base.clone() * base) % &modulus;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
impl Impl for ModexpImpl {
|
||||
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> {
|
||||
let mut reader = input.chain(io::repeat(0));
|
||||
@ -283,47 +366,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);
|
||||
|
||||
// calculate modexp: exponentiation by squaring. the `num` crate has pow, but not modular.
|
||||
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.
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let mut result = BigUint::one();
|
||||
base = base % &modulus;
|
||||
|
||||
// fast path for base divisible by modulus.
|
||||
if base.is_zero() { return result }
|
||||
while !exp.is_zero() {
|
||||
if exp.is_odd() {
|
||||
result = (result * &base) % &modulus;
|
||||
}
|
||||
|
||||
exp = exp >> 1;
|
||||
base = (base.clone() * base) % &modulus;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -352,8 +413,8 @@ fn read_point(reader: &mut io::Chain<&[u8], io::Repeat>) -> Result<::bn::G1, Err
|
||||
let px = Fq::from_slice(&buf[0..32]).map_err(|_| Error::from("Invalid point x coordinate"))?;
|
||||
|
||||
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 x coordinate"))?;
|
||||
|
||||
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()
|
||||
@ -404,50 +465,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 {
|
||||
@ -459,34 +499,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()
|
||||
@ -503,10 +545,44 @@ impl Impl for Bn128PairingImpl {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Builtin, Linear, ethereum_builtin, Pricer, Modexp};
|
||||
use super::{Builtin, Linear, ethereum_builtin, Pricer, ModexpPricer, modexp as me};
|
||||
use ethjson;
|
||||
use util::{U256, BytesRef};
|
||||
use rustc_hex::FromHex;
|
||||
use num::{BigUint, Zero, One};
|
||||
|
||||
#[test]
|
||||
fn modexp_func() {
|
||||
// n^0 % m == 1
|
||||
let mut base = BigUint::parse_bytes(b"12345", 10).unwrap();
|
||||
let mut exp = BigUint::zero();
|
||||
let mut modulus = BigUint::parse_bytes(b"789", 10).unwrap();
|
||||
assert_eq!(me(base, exp, modulus), BigUint::one());
|
||||
|
||||
// 0^n % m == 0
|
||||
base = BigUint::zero();
|
||||
exp = BigUint::parse_bytes(b"12345", 10).unwrap();
|
||||
modulus = BigUint::parse_bytes(b"789", 10).unwrap();
|
||||
assert_eq!(me(base, exp, modulus), BigUint::zero());
|
||||
|
||||
// n^m % 1 == 0
|
||||
base = BigUint::parse_bytes(b"12345", 10).unwrap();
|
||||
exp = BigUint::parse_bytes(b"789", 10).unwrap();
|
||||
modulus = BigUint::one();
|
||||
assert_eq!(me(base, exp, modulus), BigUint::zero());
|
||||
|
||||
// if n % d == 0, then n^m % d == 0
|
||||
base = BigUint::parse_bytes(b"12345", 10).unwrap();
|
||||
exp = BigUint::parse_bytes(b"789", 10).unwrap();
|
||||
modulus = BigUint::parse_bytes(b"15", 10).unwrap();
|
||||
assert_eq!(me(base, exp, modulus), BigUint::zero());
|
||||
|
||||
// others
|
||||
base = BigUint::parse_bytes(b"12345", 10).unwrap();
|
||||
exp = BigUint::parse_bytes(b"789", 10).unwrap();
|
||||
modulus = BigUint::parse_bytes(b"97", 10).unwrap();
|
||||
assert_eq!(me(base, exp, modulus), BigUint::parse_bytes(b"55", 10).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn identity() {
|
||||
@ -632,7 +708,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,
|
||||
};
|
||||
@ -649,7 +725,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);
|
||||
@ -660,15 +736,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);
|
||||
@ -688,7 +764,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);
|
||||
@ -719,7 +795,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,
|
||||
};
|
||||
|
||||
@ -780,7 +856,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,
|
||||
};
|
||||
|
||||
@ -820,7 +896,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,
|
||||
}
|
||||
}
|
||||
|
@ -1120,6 +1120,41 @@ impl Client {
|
||||
BlockId::Latest | BlockId::Pending => Some(self.chain.read().best_block_number()),
|
||||
}
|
||||
}
|
||||
|
||||
fn do_virtual_call(&self, env_info: &EnvInfo, state: &mut State<StateDB>, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
fn call<E, V, T>(
|
||||
state: &mut State<StateDB>,
|
||||
env_info: &EnvInfo,
|
||||
engine: &E,
|
||||
state_diff: bool,
|
||||
transaction: &SignedTransaction,
|
||||
options: TransactOptions<T, V>,
|
||||
) -> Result<Executed, CallError> where
|
||||
E: Engine + ?Sized,
|
||||
T: trace::Tracer,
|
||||
V: trace::VMTracer,
|
||||
{
|
||||
let options = options.dont_check_nonce();
|
||||
let original_state = if state_diff { Some(state.clone()) } else { None };
|
||||
|
||||
let mut ret = Executive::new(state, env_info, engine).transact_virtual(transaction, options)?;
|
||||
|
||||
if let Some(original) = original_state {
|
||||
ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?);
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
let state_diff = analytics.state_diffing;
|
||||
let engine = &*self.engine;
|
||||
|
||||
match (analytics.transaction_tracing, analytics.vm_tracing) {
|
||||
(true, true) => call(state, env_info, engine, state_diff, t, TransactOptions::with_tracing_and_vm_tracing()),
|
||||
(true, false) => call(state, env_info, engine, state_diff, t, TransactOptions::with_tracing()),
|
||||
(false, true) => call(state, env_info, engine, state_diff, t, TransactOptions::with_vm_tracing()),
|
||||
(false, false) => call(state, env_info, engine, state_diff, t, TransactOptions::with_no_tracing()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl snapshot::DatabaseRestore for Client {
|
||||
@ -1150,19 +1185,8 @@ impl BlockChainClient for Client {
|
||||
|
||||
// that's just a copy of the state.
|
||||
let mut state = self.state_at(block).ok_or(CallError::StatePruned)?;
|
||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||
|
||||
let options = TransactOptions::new(analytics.transaction_tracing, analytics.vm_tracing)
|
||||
.dont_check_nonce()
|
||||
.save_output_from_contract();
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact_virtual(t, options)?;
|
||||
|
||||
// TODO gav move this into Executive.
|
||||
if let Some(original) = original_state {
|
||||
ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?);
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
self.do_virtual_call(&env_info, &mut state, t, analytics)
|
||||
}
|
||||
|
||||
fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result<U256, CallError> {
|
||||
@ -1177,7 +1201,7 @@ impl BlockChainClient for Client {
|
||||
// that's just a copy of the state.
|
||||
let original_state = self.state_at(block).ok_or(CallError::StatePruned)?;
|
||||
let sender = t.sender();
|
||||
let options = TransactOptions::with_tracing().dont_check_nonce();
|
||||
let options = || TransactOptions::with_tracing();
|
||||
|
||||
let cond = |gas| {
|
||||
let mut tx = t.as_unsigned().clone();
|
||||
@ -1186,7 +1210,7 @@ impl BlockChainClient for Client {
|
||||
|
||||
let mut state = original_state.clone();
|
||||
Ok(Executive::new(&mut state, &env_info, &*self.engine)
|
||||
.transact_virtual(&tx, options.clone())
|
||||
.transact_virtual(&tx, options())
|
||||
.map(|r| r.exception.is_none())
|
||||
.unwrap_or(false))
|
||||
};
|
||||
@ -1242,24 +1266,17 @@ impl BlockChainClient for Client {
|
||||
return Err(CallError::TransactionNotFound);
|
||||
}
|
||||
|
||||
let options = TransactOptions::new(analytics.transaction_tracing, analytics.vm_tracing)
|
||||
.dont_check_nonce()
|
||||
.save_output_from_contract();
|
||||
const PROOF: &'static str = "Transactions fetched from blockchain; blockchain transactions are valid; qed";
|
||||
let rest = txs.split_off(address.index);
|
||||
for t in txs {
|
||||
let t = SignedTransaction::new(t).expect(PROOF);
|
||||
let x = Executive::new(&mut state, &env_info, &*self.engine).transact(&t, Default::default())?;
|
||||
let x = Executive::new(&mut state, &env_info, &*self.engine).transact(&t, TransactOptions::with_no_tracing())?;
|
||||
env_info.gas_used = env_info.gas_used + x.gas_used;
|
||||
}
|
||||
let first = rest.into_iter().next().expect("We split off < `address.index`; Length is checked earlier; qed");
|
||||
let t = SignedTransaction::new(first).expect(PROOF);
|
||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact(&t, options)?;
|
||||
if let Some(original) = original_state {
|
||||
ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?)
|
||||
}
|
||||
Ok(ret)
|
||||
|
||||
self.do_virtual_call(&env_info, &mut state, &t, analytics)
|
||||
}
|
||||
|
||||
fn mode(&self) -> IpcMode {
|
||||
@ -2047,11 +2064,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(),
|
||||
|
@ -18,11 +18,11 @@
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use util::{self, U256, journaldb, trie};
|
||||
use util::{self, U256, H256, journaldb, trie};
|
||||
use util::kvdb::{self, KeyValueDB};
|
||||
use {state, state_db, client, executive, trace, db, spec};
|
||||
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 evm::action_params::ActionParams;
|
||||
|
||||
/// EVM test Error.
|
||||
@ -33,9 +33,17 @@ pub enum EvmTestError {
|
||||
/// EVM error.
|
||||
Evm(evm::Error),
|
||||
/// Initialization error.
|
||||
Initialization(::error::Error),
|
||||
ClientError(::error::Error),
|
||||
/// Low-level database error.
|
||||
Database(String),
|
||||
/// Post-condition failure,
|
||||
PostCondition(String),
|
||||
}
|
||||
|
||||
impl<E: Into<::error::Error>> From<E> for EvmTestError {
|
||||
fn from(err: E) -> Self {
|
||||
EvmTestError::ClientError(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EvmTestError {
|
||||
@ -45,52 +53,118 @@ impl fmt::Display for EvmTestError {
|
||||
match *self {
|
||||
Trie(ref err) => write!(fmt, "Trie: {}", err),
|
||||
Evm(ref err) => write!(fmt, "EVM: {}", err),
|
||||
Initialization(ref err) => write!(fmt, "Initialization: {}", err),
|
||||
ClientError(ref err) => write!(fmt, "{}", err),
|
||||
Database(ref err) => write!(fmt, "DB: {}", err),
|
||||
PostCondition(ref err) => write!(fmt, "{}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Simplified, single-block EVM test client.
|
||||
pub struct EvmTestClient {
|
||||
state_db: state_db::StateDB,
|
||||
factories: Factories,
|
||||
spec: spec::Spec,
|
||||
use ethereum;
|
||||
use ethjson::state::test::ForkSpec;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref FRONTIER: spec::Spec = ethereum::new_frontier_test();
|
||||
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 BYZANTIUM: spec::Spec = ethereum::new_byzantium_test();
|
||||
pub static ref BYZANTIUM_TRANSITION: spec::Spec = ethereum::new_transition_test();
|
||||
}
|
||||
|
||||
impl EvmTestClient {
|
||||
/// Creates new EVM test client with in-memory DB initialized with genesis of given Spec.
|
||||
pub fn new(spec: spec::Spec) -> Result<Self, EvmTestError> {
|
||||
let factories = Factories {
|
||||
vm: evm::Factory::new(VMType::Interpreter, 5 * 1024),
|
||||
trie: trie::TrieFactory::new(trie::TrieSpec::Secure),
|
||||
accountdb: Default::default(),
|
||||
};
|
||||
let db = Arc::new(kvdb::in_memory(db::NUM_COLUMNS.expect("We use column-based DB; qed")));
|
||||
let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, db::COL_STATE);
|
||||
let mut state_db = state_db::StateDB::new(journal_db, 5 * 1024 * 1024);
|
||||
state_db = spec.ensure_db_good(state_db, &factories).map_err(EvmTestError::Initialization)?;
|
||||
// Write DB
|
||||
{
|
||||
let mut batch = kvdb::DBTransaction::new();
|
||||
state_db.journal_under(&mut batch, 0, &spec.genesis_header().hash()).map_err(|e| EvmTestError::Initialization(e.into()))?;
|
||||
db.write(batch).map_err(EvmTestError::Database)?;
|
||||
/// Simplified, single-block EVM test client.
|
||||
pub struct EvmTestClient<'a> {
|
||||
state: state::State<state_db::StateDB>,
|
||||
spec: &'a spec::Spec,
|
||||
}
|
||||
|
||||
impl<'a> EvmTestClient<'a> {
|
||||
/// Converts a json spec definition into spec.
|
||||
pub fn spec_from_json(spec: &ForkSpec) -> Option<&'static spec::Spec> {
|
||||
match *spec {
|
||||
ForkSpec::Frontier => Some(&*FRONTIER),
|
||||
ForkSpec::Homestead => Some(&*HOMESTEAD),
|
||||
ForkSpec::EIP150 => Some(&*EIP150),
|
||||
ForkSpec::EIP158 => Some(&*EIP161),
|
||||
ForkSpec::Byzantium => Some(&*BYZANTIUM),
|
||||
ForkSpec::EIP158ToByzantiumAt5 => Some(&BYZANTIUM_TRANSITION),
|
||||
ForkSpec::FrontierToHomesteadAt5 | ForkSpec::HomesteadToDaoAt5 | ForkSpec::HomesteadToEIP150At5 => None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new EVM test client with in-memory DB initialized with genesis of given Spec.
|
||||
pub fn new(spec: &'a spec::Spec) -> Result<Self, EvmTestError> {
|
||||
let factories = Self::factories();
|
||||
let state = Self::state_from_spec(spec, &factories)?;
|
||||
|
||||
Ok(EvmTestClient {
|
||||
state_db,
|
||||
factories,
|
||||
state,
|
||||
spec,
|
||||
})
|
||||
}
|
||||
|
||||
/// Call given contract.
|
||||
/// Creates new EVM test client with in-memory DB initialized with given PodState.
|
||||
pub fn from_pod_state(spec: &'a spec::Spec, pod_state: pod_state::PodState) -> Result<Self, EvmTestError> {
|
||||
let factories = Self::factories();
|
||||
let state = Self::state_from_pod(spec, &factories, pod_state)?;
|
||||
|
||||
Ok(EvmTestClient {
|
||||
state,
|
||||
spec,
|
||||
})
|
||||
}
|
||||
|
||||
fn factories() -> Factories {
|
||||
Factories {
|
||||
vm: evm::Factory::new(VMType::Interpreter, 5 * 1024),
|
||||
trie: trie::TrieFactory::new(trie::TrieSpec::Secure),
|
||||
accountdb: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn state_from_spec(spec: &'a spec::Spec, factories: &Factories) -> Result<state::State<state_db::StateDB>, EvmTestError> {
|
||||
let db = Arc::new(kvdb::in_memory(db::NUM_COLUMNS.expect("We use column-based DB; qed")));
|
||||
let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, db::COL_STATE);
|
||||
let mut state_db = state_db::StateDB::new(journal_db, 5 * 1024 * 1024);
|
||||
state_db = spec.ensure_db_good(state_db, factories)?;
|
||||
|
||||
let genesis = spec.genesis_header();
|
||||
// Write DB
|
||||
{
|
||||
let mut batch = kvdb::DBTransaction::new();
|
||||
state_db.journal_under(&mut batch, 0, &genesis.hash())?;
|
||||
db.write(batch).map_err(EvmTestError::Database)?;
|
||||
}
|
||||
|
||||
state::State::from_existing(
|
||||
state_db,
|
||||
*genesis.state_root(),
|
||||
spec.engine.account_start_nonce(0),
|
||||
factories.clone()
|
||||
).map_err(EvmTestError::Trie)
|
||||
}
|
||||
|
||||
fn state_from_pod(spec: &'a spec::Spec, factories: &Factories, pod_state: pod_state::PodState) -> Result<state::State<state_db::StateDB>, EvmTestError> {
|
||||
let db = Arc::new(kvdb::in_memory(db::NUM_COLUMNS.expect("We use column-based DB; qed")));
|
||||
let journal_db = journaldb::new(db.clone(), journaldb::Algorithm::EarlyMerge, db::COL_STATE);
|
||||
let state_db = state_db::StateDB::new(journal_db, 5 * 1024 * 1024);
|
||||
let mut state = state::State::new(
|
||||
state_db,
|
||||
spec.engine.account_start_nonce(0),
|
||||
factories.clone(),
|
||||
);
|
||||
state.populate_from(pod_state);
|
||||
state.commit()?;
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
/// 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 mut state = state::State::from_existing(self.state_db.boxed_clone(), *genesis.state_root(), self.spec.engine.account_start_nonce(0), self.factories.clone())
|
||||
.map_err(EvmTestError::Trie)?;
|
||||
let info = client::EnvInfo {
|
||||
number: genesis.number(),
|
||||
author: *genesis.author(),
|
||||
@ -103,15 +177,71 @@ impl EvmTestClient {
|
||||
let mut substate = state::Substate::new();
|
||||
let mut tracer = trace::NoopTracer;
|
||||
let mut output = vec![];
|
||||
let mut executive = executive::Executive::new(&mut state, &info, &*self.spec.engine);
|
||||
let (gas_left, _) = executive.call(
|
||||
let mut executive = executive::Executive::new(&mut self.state, &info, &*self.spec.engine);
|
||||
executive.call(
|
||||
params,
|
||||
&mut substate,
|
||||
util::BytesRef::Flexible(&mut output),
|
||||
&mut tracer,
|
||||
vm_tracer,
|
||||
).map_err(EvmTestError::Evm)?;
|
||||
).map_err(EvmTestError::Evm)
|
||||
}
|
||||
|
||||
Ok((gas_left, output))
|
||||
/// Executes a SignedTransaction within context of the provided state and `EnvInfo`.
|
||||
/// Returns the state root, gas left and the output.
|
||||
pub fn transact<T: trace::VMTracer>(
|
||||
&mut self,
|
||||
env_info: &client::EnvInfo,
|
||||
transaction: transaction::SignedTransaction,
|
||||
vm_tracer: T,
|
||||
) -> TransactResult {
|
||||
let initial_gas = transaction.gas;
|
||||
// Verify transaction
|
||||
let is_ok = transaction.verify_basic(true, None, env_info.number >= self.spec.engine.params().eip86_transition);
|
||||
if let Err(error) = is_ok {
|
||||
return TransactResult::Err {
|
||||
state_root: *self.state.root(),
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
// Apply transaction
|
||||
let tracer = trace::NoopTracer;
|
||||
let result = self.state.apply_with_tracing(&env_info, &*self.spec.engine, &transaction, tracer, vm_tracer);
|
||||
|
||||
match result {
|
||||
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(),
|
||||
error,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A result of applying transaction to the state.
|
||||
pub enum TransactResult {
|
||||
/// Successful execution
|
||||
Ok {
|
||||
/// State root
|
||||
state_root: H256,
|
||||
/// Amount of gas left
|
||||
gas_left: U256,
|
||||
/// Output
|
||||
output: Vec<u8>,
|
||||
},
|
||||
/// Transaction failed to run
|
||||
Err {
|
||||
/// State root
|
||||
state_root: H256,
|
||||
/// Execution error
|
||||
error: ::error::Error,
|
||||
},
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ mod client;
|
||||
pub use self::client::*;
|
||||
pub use self::config::{Mode, ClientConfig, DatabaseCompactionProfile, BlockChainConfig, VMType};
|
||||
pub use self::error::Error;
|
||||
pub use self::evm_test_client::{EvmTestClient, EvmTestError};
|
||||
pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult};
|
||||
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
||||
pub use self::chain_notify::ChainNotify;
|
||||
pub use self::traits::{BlockChainClient, MiningBlockChainClient, EngineClient};
|
||||
|
@ -595,6 +595,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();
|
||||
|
@ -57,8 +57,8 @@ use ethkey::Signature;
|
||||
use util::*;
|
||||
|
||||
/// 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)]
|
||||
|
@ -40,6 +40,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)]
|
||||
@ -102,6 +103,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 {
|
||||
@ -136,6 +143,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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -207,8 +217,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);
|
||||
@ -287,8 +299,13 @@ impl Engine for Arc<Ethash> {
|
||||
/// Apply the block reward on finalisation of the block.
|
||||
/// 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> {
|
||||
let reward = self.ethash_params.block_reward;
|
||||
let fields = block.fields_mut();
|
||||
let reward = if fields.header.number() >= self.ethash_params.eip649_transition {
|
||||
self.ethash_params.eip649_reward.unwrap_or(self.ethash_params.block_reward)
|
||||
} else {
|
||||
self.ethash_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());
|
||||
|
||||
@ -455,7 +472,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");
|
||||
}
|
||||
@ -505,7 +522,11 @@ impl Ethash {
|
||||
target = 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 = max(min_difficulty, target + (U256::from(1) << (period - 2)));
|
||||
}
|
||||
|
@ -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 {
|
||||
@ -151,6 +154,6 @@ mod tests {
|
||||
new_eip161_test();
|
||||
new_transition_test();
|
||||
new_mainnet_like();
|
||||
new_metropolis_test();
|
||||
new_byzantium_test();
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ use evm::env_info::EnvInfo;
|
||||
use error::ExecutionError;
|
||||
use evm::{self, wasm, Factory, Ext, Finalize, CreateContractAddress, FinalizationResult, ReturnData, CleanDustMode};
|
||||
use externalities::*;
|
||||
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
|
||||
use trace::{self, FlatTrace, VMTrace, Tracer, VMTracer};
|
||||
use transaction::{Action, SignedTransaction};
|
||||
use crossbeam;
|
||||
pub use executed::{Executed, ExecutionResult};
|
||||
@ -64,24 +64,24 @@ pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address,
|
||||
}
|
||||
|
||||
/// Transaction execution options.
|
||||
#[derive(Default, Copy, Clone, PartialEq)]
|
||||
pub struct TransactOptions {
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct TransactOptions<T, V> {
|
||||
/// Enable call tracing.
|
||||
pub tracing: bool,
|
||||
pub tracer: T,
|
||||
/// Enable VM tracing.
|
||||
pub vm_tracing: bool,
|
||||
pub vm_tracer: V,
|
||||
/// Check transaction nonce before execution.
|
||||
pub check_nonce: bool,
|
||||
/// Records the output from init contract calls.
|
||||
pub output_from_init_contract: bool,
|
||||
}
|
||||
|
||||
impl TransactOptions {
|
||||
impl<T, V> TransactOptions<T, V> {
|
||||
/// Create new `TransactOptions` with given tracer and VM tracer.
|
||||
pub fn new(tracing: bool, vm_tracing: bool) -> Self {
|
||||
pub fn new(tracer: T, vm_tracer: V) -> Self {
|
||||
TransactOptions {
|
||||
tracing,
|
||||
vm_tracing,
|
||||
tracer,
|
||||
vm_tracer,
|
||||
check_nonce: true,
|
||||
output_from_init_contract: false,
|
||||
}
|
||||
@ -98,42 +98,50 @@ impl TransactOptions {
|
||||
self.output_from_init_contract = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactOptions<trace::ExecutiveTracer, trace::ExecutiveVMTracer> {
|
||||
/// Creates new `TransactOptions` with default tracing and VM tracing.
|
||||
pub fn with_tracing_and_vm_tracing() -> Self {
|
||||
TransactOptions {
|
||||
tracing: true,
|
||||
vm_tracing: true,
|
||||
tracer: trace::ExecutiveTracer::default(),
|
||||
vm_tracer: trace::ExecutiveVMTracer::toplevel(),
|
||||
check_nonce: true,
|
||||
output_from_init_contract: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactOptions<trace::ExecutiveTracer, trace::NoopVMTracer> {
|
||||
/// Creates new `TransactOptions` with default tracing and no VM tracing.
|
||||
pub fn with_tracing() -> Self {
|
||||
TransactOptions {
|
||||
tracing: true,
|
||||
vm_tracing: false,
|
||||
tracer: trace::ExecutiveTracer::default(),
|
||||
vm_tracer: trace::NoopVMTracer,
|
||||
check_nonce: true,
|
||||
output_from_init_contract: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactOptions<trace::NoopTracer, trace::ExecutiveVMTracer> {
|
||||
/// Creates new `TransactOptions` with no tracing and default VM tracing.
|
||||
pub fn with_vm_tracing() -> Self {
|
||||
TransactOptions {
|
||||
tracing: false,
|
||||
vm_tracing: true,
|
||||
tracer: trace::NoopTracer,
|
||||
vm_tracer: trace::ExecutiveVMTracer::toplevel(),
|
||||
check_nonce: true,
|
||||
output_from_init_contract: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactOptions<trace::NoopTracer, trace::NoopVMTracer> {
|
||||
/// Creates new `TransactOptions` without any tracing.
|
||||
pub fn with_no_tracing() -> Self {
|
||||
TransactOptions {
|
||||
tracing: false,
|
||||
vm_tracing: false,
|
||||
tracer: trace::NoopTracer,
|
||||
vm_tracer: trace::NoopVMTracer,
|
||||
check_nonce: true,
|
||||
output_from_init_contract: false,
|
||||
}
|
||||
@ -201,25 +209,18 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
}
|
||||
|
||||
/// This function should be used to execute transaction.
|
||||
pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result<Executed, ExecutionError> {
|
||||
let check = options.check_nonce;
|
||||
let output = options.output_from_init_contract;
|
||||
match options.tracing {
|
||||
true => match options.vm_tracing {
|
||||
true => self.transact_with_tracer(t, check, output, ExecutiveTracer::default(), ExecutiveVMTracer::toplevel()),
|
||||
false => self.transact_with_tracer(t, check, output, ExecutiveTracer::default(), NoopVMTracer),
|
||||
},
|
||||
false => match options.vm_tracing {
|
||||
true => self.transact_with_tracer(t, check, output, NoopTracer, ExecutiveVMTracer::toplevel()),
|
||||
false => self.transact_with_tracer(t, check, output, NoopTracer, NoopVMTracer),
|
||||
},
|
||||
}
|
||||
pub fn transact<T, V>(&'a mut self, t: &SignedTransaction, options: TransactOptions<T, V>)
|
||||
-> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer,
|
||||
{
|
||||
self.transact_with_tracer(t, options.check_nonce, options.output_from_init_contract, options.tracer, options.vm_tracer)
|
||||
}
|
||||
|
||||
/// Execute a transaction in a "virtual" context.
|
||||
/// This will ensure the caller has enough balance to execute the desired transaction.
|
||||
/// Used for extra-block executions for things like consensus contracts and RPCs
|
||||
pub fn transact_virtual(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result<Executed, ExecutionError> {
|
||||
pub fn transact_virtual<T, V>(&'a mut self, t: &SignedTransaction, options: TransactOptions<T, V>)
|
||||
-> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer,
|
||||
{
|
||||
let sender = t.sender();
|
||||
let balance = self.state.balance(&sender)?;
|
||||
let needed_balance = t.value.saturating_add(t.gas.saturating_mul(t.gas_price));
|
||||
@ -232,7 +233,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
}
|
||||
|
||||
/// Execute transaction/call with tracing enabled
|
||||
pub fn transact_with_tracer<T, V>(
|
||||
fn transact_with_tracer<T, V>(
|
||||
&'a mut self,
|
||||
t: &SignedTransaction,
|
||||
check_nonce: bool,
|
||||
@ -284,7 +285,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))?;
|
||||
@ -328,7 +329,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
};
|
||||
|
||||
// finalize here!
|
||||
Ok(self.finalize(t, substate, result, output, tracer.traces(), vm_tracer.drain())?)
|
||||
Ok(self.finalize(t, substate, result, output, tracer.drain(), vm_tracer.drain())?)
|
||||
}
|
||||
|
||||
fn exec_vm<T, V>(
|
||||
@ -376,12 +377,12 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
mut output: BytesRef,
|
||||
tracer: &mut T,
|
||||
vm_tracer: &mut V
|
||||
) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
|
||||
) -> evm::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(evm::Error::MutableCallInStaticContext);
|
||||
}
|
||||
@ -434,7 +435,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
|
||||
@ -466,7 +471,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
|
||||
trace!(target: "executive", "res={:?}", res);
|
||||
|
||||
let traces = subtracer.traces();
|
||||
let traces = subtracer.drain();
|
||||
match res {
|
||||
Ok(ref res) => tracer.trace_call(
|
||||
trace_info,
|
||||
@ -481,13 +486,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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -502,13 +511,18 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
output: &mut Option<Bytes>,
|
||||
tracer: &mut T,
|
||||
vm_tracer: &mut V,
|
||||
) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
|
||||
) -> evm::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(¶ms.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(¶ms.address)? {
|
||||
return Err(evm::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(¶ms);
|
||||
tracer.trace_failed_create(trace_info, vec![], evm::Error::MutableCallInStaticContext.into());
|
||||
@ -552,13 +566,13 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
gas - res.gas_left,
|
||||
trace_output.map(|data| output.as_ref().map(|out| out.to_vec()).unwrap_or(data)),
|
||||
created,
|
||||
subtracer.traces()
|
||||
subtracer.drain()
|
||||
),
|
||||
Err(ref e) => tracer.trace_failed_create(trace_info, subtracer.traces(), e.into())
|
||||
Err(ref e) => tracer.trace_failed_create(trace_info, subtracer.drain(), e.into())
|
||||
};
|
||||
|
||||
self.enact_result(&res, substate, unconfirmed_substate);
|
||||
res.map(|r| (r.gas_left, r.return_data))
|
||||
res
|
||||
}
|
||||
|
||||
/// Finalizes the transaction (does refunds and suicides).
|
||||
@ -566,7 +580,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
&mut self,
|
||||
t: &SignedTransaction,
|
||||
mut substate: Substate,
|
||||
result: evm::Result<(U256, ReturnData)>,
|
||||
result: evm::Result<FinalizationResult>,
|
||||
output: Bytes,
|
||||
trace: Vec<FlatTrace>,
|
||||
vm_trace: Option<VMTrace>
|
||||
@ -580,7 +594,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;
|
||||
|
||||
@ -624,9 +638,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(evm::Error::Reverted) },
|
||||
gas: t.gas,
|
||||
gas_used: gas_used,
|
||||
refunded: refunded,
|
||||
@ -652,6 +666,8 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
| Err(evm::Error::Wasm {..})
|
||||
| Err(evm::Error::OutOfStack {..})
|
||||
| Err(evm::Error::MutableCallInStaticContext)
|
||||
| Err(evm::Error::OutOfBounds)
|
||||
| Err(evm::Error::Reverted)
|
||||
| Ok(FinalizationResult { apply_state: false, .. }) => {
|
||||
self.state.revert_to_checkpoint();
|
||||
},
|
||||
@ -709,7 +725,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()
|
||||
};
|
||||
@ -767,7 +783,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()
|
||||
};
|
||||
@ -825,7 +841,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()
|
||||
@ -864,7 +880,7 @@ mod tests {
|
||||
}),
|
||||
}];
|
||||
|
||||
assert_eq!(tracer.traces(), expected_trace);
|
||||
assert_eq!(tracer.drain(), expected_trace);
|
||||
|
||||
let expected_vm_trace = VMTrace {
|
||||
parent_step: 0,
|
||||
@ -934,7 +950,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()
|
||||
};
|
||||
@ -957,7 +973,7 @@ mod tests {
|
||||
}),
|
||||
}];
|
||||
|
||||
assert_eq!(tracer.traces(), expected_trace);
|
||||
assert_eq!(tracer.drain(), expected_trace);
|
||||
|
||||
let expected_vm_trace = VMTrace {
|
||||
parent_step: 0,
|
||||
@ -1019,7 +1035,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()
|
||||
};
|
||||
@ -1130,7 +1146,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()
|
||||
};
|
||||
@ -1174,7 +1190,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()
|
||||
};
|
||||
@ -1208,7 +1224,7 @@ mod tests {
|
||||
|
||||
let executed = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false, output_from_init_contract: false };
|
||||
let opts = TransactOptions::with_no_tracing();
|
||||
ex.transact(&t, opts).unwrap()
|
||||
};
|
||||
|
||||
@ -1245,7 +1261,7 @@ mod tests {
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false, output_from_init_contract: false };
|
||||
let opts = TransactOptions::with_no_tracing();
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
|
||||
@ -1278,7 +1294,7 @@ mod tests {
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false, output_from_init_contract: false };
|
||||
let opts = TransactOptions::with_no_tracing();
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
|
||||
@ -1311,7 +1327,7 @@ mod tests {
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false, output_from_init_contract: false };
|
||||
let opts = TransactOptions::with_no_tracing();
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
|
||||
@ -1375,11 +1391,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()
|
||||
};
|
||||
|
@ -23,6 +23,7 @@ use evm::env_info::EnvInfo;
|
||||
use executive::*;
|
||||
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData};
|
||||
use evm::CallType;
|
||||
use evm::FinalizationResult;
|
||||
use transaction::UNSIGNED_SENDER;
|
||||
use trace::{Tracer, VMTracer};
|
||||
|
||||
@ -121,6 +122,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) -> evm::Result<bool> {
|
||||
self.state.exists(address).map_err(Into::into)
|
||||
}
|
||||
@ -210,21 +215,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(evm::Error::MutableCallInStaticContext) => ContractCreateResult::FailedInStaticCall,
|
||||
_ => ContractCreateResult::Failed,
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,7 +280,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
|
||||
}
|
||||
}
|
||||
@ -283,7 +295,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) -> evm::Result<U256>
|
||||
fn ret(mut self, gas: &U256, data: &ReturnData, apply_state: bool) -> evm::Result<U256>
|
||||
where Self: Sized {
|
||||
let handle_copy = |to: &mut Option<&mut Bytes>| {
|
||||
to.as_mut().map(|b| **b = data.to_vec());
|
||||
@ -303,7 +315,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 {
|
||||
@ -311,12 +323,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)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,17 +14,15 @@
|
||||
// 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::test_common::*;
|
||||
use client::{BlockChainClient, Client, ClientConfig};
|
||||
use std::sync::Arc;
|
||||
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"}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ use tests::helpers::*;
|
||||
use ethjson;
|
||||
use trace::{Tracer, NoopTracer};
|
||||
use trace::{VMTracer, NoopVMTracer};
|
||||
use rlp::RlpStream;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
struct CallCreate {
|
||||
@ -158,8 +159,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, evm::Error> {
|
||||
self.ext.ret(gas, data)
|
||||
fn ret(self, gas: &U256, data: &ReturnData, apply_state: bool) -> Result<U256, evm::Error> {
|
||||
self.ext.ret(gas, data, apply_state)
|
||||
}
|
||||
|
||||
fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> {
|
||||
@ -178,6 +179,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()
|
||||
}
|
||||
@ -251,6 +256,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);
|
||||
}
|
||||
&rlp.drain().sha3()
|
||||
};
|
||||
|
||||
match res {
|
||||
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
|
||||
Ok(res) => {
|
||||
@ -258,6 +271,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();
|
||||
@ -291,15 +305,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"}
|
||||
|
@ -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"}
|
@ -21,5 +21,4 @@ mod transaction;
|
||||
mod executive;
|
||||
mod state;
|
||||
mod chain;
|
||||
mod homestead_chain;
|
||||
mod trie;
|
||||
|
@ -15,23 +15,13 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::test_common::*;
|
||||
use tests::helpers::*;
|
||||
use pod_state::PodState;
|
||||
use ethereum;
|
||||
use spec::Spec;
|
||||
use trace;
|
||||
use client::{EvmTestClient, EvmTestError, TransactResult};
|
||||
use ethjson;
|
||||
use ethjson::state::test::ForkSpec;
|
||||
use transaction::SignedTransaction;
|
||||
use evm::env_info::EnvInfo;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref FRONTIER: Spec = ethereum::new_frontier_test();
|
||||
pub static ref HOMESTEAD: Spec = ethereum::new_homestead_test();
|
||||
pub static ref EIP150: Spec = ethereum::new_eip150_test();
|
||||
pub static ref EIP161: Spec = ethereum::new_eip161_test();
|
||||
pub static ref _METROPOLIS: Spec = ethereum::new_metropolis_test();
|
||||
}
|
||||
|
||||
pub fn json_chain_test(json_data: &[u8]) -> Vec<String> {
|
||||
::ethcore_logger::init_log();
|
||||
let tests = ethjson::state::test::Test::load(json_data).unwrap();
|
||||
@ -43,35 +33,49 @@ pub fn json_chain_test(json_data: &[u8]) -> Vec<String> {
|
||||
let env: EnvInfo = test.env.into();
|
||||
let pre: PodState = test.pre_state.into();
|
||||
|
||||
for (spec, states) in test.post_states {
|
||||
for (spec_name, states) in test.post_states {
|
||||
let total = states.len();
|
||||
let engine = match spec {
|
||||
ForkSpec::Frontier => &FRONTIER.engine,
|
||||
ForkSpec::Homestead => &HOMESTEAD.engine,
|
||||
ForkSpec::EIP150 => &EIP150.engine,
|
||||
ForkSpec::EIP158 => &EIP161.engine,
|
||||
ForkSpec::Metropolis => continue,
|
||||
let spec = match EvmTestClient::spec_from_json(&spec_name) {
|
||||
Some(spec) => spec,
|
||||
None => {
|
||||
println!(" - {} | {:?} Ignoring tests because of missing spec", name, spec_name);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
for (i, state) in states.into_iter().enumerate() {
|
||||
let info = format!(" - {} | {:?} ({}/{}) ...", name, spec, i + 1, total);
|
||||
let info = format!(" - {} | {:?} ({}/{}) ...", name, spec_name, i + 1, total);
|
||||
|
||||
let post_root: H256 = state.hash.into();
|
||||
let transaction: SignedTransaction = multitransaction.select(&state.indexes).into();
|
||||
let mut state = get_temp_state();
|
||||
state.populate_from(pre.clone());
|
||||
if transaction.verify_basic(true, None, env.number >= engine.params().eip86_transition).is_ok() {
|
||||
state.commit().expect(&format!("State test {} failed due to internal error.", name));
|
||||
let _res = state.apply(&env, &**engine, &transaction, false);
|
||||
} else {
|
||||
let _rest = state.commit();
|
||||
}
|
||||
if state.root() != &post_root {
|
||||
println!("{} !!! State mismatch (got: {}, expect: {}", info, state.root(), post_root);
|
||||
flushln!("{} fail", info);
|
||||
failed.push(name.clone());
|
||||
} else {
|
||||
flushln!("{} ok", info);
|
||||
|
||||
let result = || -> Result<_, EvmTestError> {
|
||||
Ok(EvmTestClient::from_pod_state(spec, pre.clone())?
|
||||
.transact(&env, transaction, trace::NoopVMTracer))
|
||||
};
|
||||
match result() {
|
||||
Err(err) => {
|
||||
println!("{} !!! Unexpected internal error: {:?}", info, err);
|
||||
flushln!("{} fail", info);
|
||||
failed.push(name.clone());
|
||||
},
|
||||
Ok(TransactResult::Ok { state_root, .. }) if state_root != post_root => {
|
||||
println!("{} !!! State mismatch (got: {}, expect: {}", info, state_root, post_root);
|
||||
flushln!("{} fail", info);
|
||||
failed.push(name.clone());
|
||||
},
|
||||
Ok(TransactResult::Err { state_root, ref error }) if state_root != post_root => {
|
||||
println!("{} !!! State mismatch (got: {}, expect: {}", info, state_root, post_root);
|
||||
println!("{} !!! Execution error: {:?}", info, error);
|
||||
flushln!("{} fail", info);
|
||||
failed.push(name.clone());
|
||||
},
|
||||
Ok(TransactResult::Err { error, .. }) => {
|
||||
flushln!("{} ok ({:?})", info, error);
|
||||
},
|
||||
Ok(_) => {
|
||||
flushln!("{} ok", info);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,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/"}
|
||||
@ -104,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/"}
|
||||
@ -117,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/"}
|
||||
}
|
||||
|
||||
|
@ -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_network_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"}
|
||||
|
@ -742,8 +742,12 @@ impl MinerService for Miner {
|
||||
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty)
|
||||
.map_err(ExecutionError::from)?;
|
||||
}
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false, output_from_init_contract: true };
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact(t, options)?;
|
||||
let mut ret = match (analytics.transaction_tracing, analytics.vm_tracing) {
|
||||
(true, true) => Executive::new(&mut state, &env_info, &*self.engine).transact(t, TransactOptions::with_tracing_and_vm_tracing())?,
|
||||
(true, false) => Executive::new(&mut state, &env_info, &*self.engine).transact(t, TransactOptions::with_tracing())?,
|
||||
(false, true) => Executive::new(&mut state, &env_info, &*self.engine).transact(t, TransactOptions::with_vm_tracing())?,
|
||||
(false, false) => Executive::new(&mut state, &env_info, &*self.engine).transact(t, TransactOptions::with_no_tracing())?,
|
||||
};
|
||||
|
||||
// TODO gav move this into Executive.
|
||||
if let Some(original) = original_state {
|
||||
|
@ -59,6 +59,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,
|
||||
/// Validate block receipts root.
|
||||
pub validate_receipts_transition: u64,
|
||||
/// Number of first block where EIP-86 (Metropolis) rules begin.
|
||||
@ -102,7 +104,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 {
|
||||
@ -135,6 +137,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),
|
||||
@ -187,7 +190,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();
|
||||
|
@ -28,7 +28,7 @@ use evm::env_info::EnvInfo;
|
||||
use error::Error;
|
||||
use executive::{Executive, TransactOptions};
|
||||
use factory::Factories;
|
||||
use trace::FlatTrace;
|
||||
use trace::{self, FlatTrace, VMTrace};
|
||||
use pod_account::*;
|
||||
use pod_state::{self, PodState};
|
||||
use types::basic_account::BasicAccount;
|
||||
@ -56,8 +56,12 @@ pub use self::substate::Substate;
|
||||
pub struct ApplyOutcome {
|
||||
/// The receipt for the applied transaction.
|
||||
pub receipt: Receipt,
|
||||
/// The trace for the applied transaction, if None if tracing is disabled.
|
||||
/// The output of the applied transaction.
|
||||
pub output: Bytes,
|
||||
/// The trace for the applied transaction, empty if tracing was not produced.
|
||||
pub trace: Vec<FlatTrace>,
|
||||
/// The VM trace for the applied transaction, None if tracing was not produced.
|
||||
pub vm_trace: Option<VMTrace>
|
||||
}
|
||||
|
||||
/// Result type for the execution ("application") of a transaction.
|
||||
@ -202,7 +206,7 @@ pub fn check_proof(
|
||||
Err(_) => return ProvedExecution::BadProof,
|
||||
};
|
||||
|
||||
match state.execute(env_info, engine, transaction, false, true) {
|
||||
match state.execute(env_info, engine, transaction, TransactOptions::with_no_tracing(), true) {
|
||||
Ok(executed) => ProvedExecution::Complete(executed),
|
||||
Err(ExecutionError::Internal(_)) => ProvedExecution::BadProof,
|
||||
Err(e) => ProvedExecution::Failed(e),
|
||||
@ -287,7 +291,7 @@ const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with v
|
||||
|
||||
impl<B: Backend> State<B> {
|
||||
/// Creates new state with empty state root
|
||||
#[cfg(test)]
|
||||
/// Used for tests.
|
||||
pub fn new(mut db: B, account_start_nonce: U256, factories: Factories) -> State<B> {
|
||||
let mut root = H256::new();
|
||||
{
|
||||
@ -451,9 +455,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() != SHA3_EMPTY || *a.nonce() != self.account_start_nonce))
|
||||
}
|
||||
|
||||
/// Get the balance of account `a`.
|
||||
@ -620,29 +625,68 @@ impl<B: Backend> State<B> {
|
||||
/// Execute a given transaction, producing a receipt and an optional trace.
|
||||
/// This will change the state accordingly.
|
||||
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool) -> ApplyResult {
|
||||
// let old = self.to_pod();
|
||||
if tracing {
|
||||
let options = TransactOptions::with_tracing();
|
||||
self.apply_with_tracing(env_info, engine, t, options.tracer, options.vm_tracer)
|
||||
} else {
|
||||
let options = TransactOptions::with_no_tracing();
|
||||
self.apply_with_tracing(env_info, engine, t, options.tracer, options.vm_tracer)
|
||||
}
|
||||
}
|
||||
|
||||
let e = self.execute(env_info, engine, t, tracing, false)?;
|
||||
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
|
||||
let state_root = if env_info.number < engine.params().eip98_transition || env_info.number < engine.params().validate_receipts_transition {
|
||||
/// Execute a given transaction with given tracer and VM tracer producing a receipt and an optional trace.
|
||||
/// This will change the state accordingly.
|
||||
pub fn apply_with_tracing<V, T>(
|
||||
&mut self,
|
||||
env_info: &EnvInfo,
|
||||
engine: &Engine,
|
||||
t: &SignedTransaction,
|
||||
tracer: T,
|
||||
vm_tracer: V,
|
||||
) -> ApplyResult where
|
||||
T: trace::Tracer,
|
||||
V: trace::VMTracer,
|
||||
{
|
||||
let options = TransactOptions::new(tracer, vm_tracer);
|
||||
let e = self.execute(env_info, engine, t, options, false)?;
|
||||
|
||||
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 receipt = Receipt::new(state_root, e.cumulative_gas_used, e.logs);
|
||||
|
||||
let output = e.output;
|
||||
let receipt = Receipt::new(state_root, status_byte, e.cumulative_gas_used, e.logs);
|
||||
trace!(target: "state", "Transaction receipt: {:?}", receipt);
|
||||
Ok(ApplyOutcome{receipt: receipt, trace: e.trace})
|
||||
|
||||
Ok(ApplyOutcome {
|
||||
receipt,
|
||||
output,
|
||||
trace: e.trace,
|
||||
vm_trace: e.vm_trace,
|
||||
})
|
||||
}
|
||||
|
||||
// Execute a given transaction without committing changes.
|
||||
//
|
||||
// `virt` signals that we are executing outside of a block set and restrictions like
|
||||
// gas limits and gas costs should be lifted.
|
||||
fn execute(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool, virt: bool)
|
||||
-> Result<Executed, ExecutionError>
|
||||
fn execute<T, V>(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, options: TransactOptions<T, V>, virt: bool)
|
||||
-> Result<Executed, ExecutionError> where T: trace::Tracer, V: trace::VMTracer,
|
||||
{
|
||||
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true, output_from_init_contract: true };
|
||||
let mut e = Executive::new(self, env_info, engine);
|
||||
|
||||
match virt {
|
||||
@ -727,9 +771,8 @@ impl<B: Backend> State<B> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "json-tests")]
|
||||
/// Populate the state from `accounts`.
|
||||
/// Used for tests.
|
||||
pub fn populate_from(&mut self, accounts: PodState) {
|
||||
assert!(self.checkpoints.borrow().is_empty());
|
||||
for (add, acc) in accounts.drain().into_iter() {
|
||||
|
@ -17,7 +17,7 @@
|
||||
use io::IoChannel;
|
||||
use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockId};
|
||||
use state::{self, State, CleanupMode};
|
||||
use executive::Executive;
|
||||
use executive::{Executive, TransactOptions};
|
||||
use ethereum;
|
||||
use block::IsBlock;
|
||||
use tests::helpers::*;
|
||||
@ -359,7 +359,7 @@ fn transaction_proof() {
|
||||
|
||||
let mut state = State::from_existing(backend, root, 0.into(), factories.clone()).unwrap();
|
||||
Executive::new(&mut state, &client.latest_env_info(), &*test_spec.engine)
|
||||
.transact(&transaction, Default::default()).unwrap();
|
||||
.transact(&transaction, TransactOptions::with_no_tracing().dont_check_nonce()).unwrap();
|
||||
|
||||
assert_eq!(state.balance(&Address::default()).unwrap(), 5.into());
|
||||
assert_eq!(state.balance(&address).unwrap(), 95.into());
|
||||
|
@ -22,7 +22,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 = blockhash_contract_code.sha3();
|
||||
let engine = TestEngine::new_metropolis();
|
||||
let engine = TestEngine::new_constantinople();
|
||||
let mut env_info = EnvInfo::default();
|
||||
|
||||
// populate state with 256 last hashes
|
||||
|
@ -36,15 +36,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,
|
||||
@ -58,9 +49,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,
|
||||
}
|
||||
}
|
||||
@ -425,5 +423,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,
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ impl Tracer for ExecutiveTracer {
|
||||
ExecutiveTracer::default()
|
||||
}
|
||||
|
||||
fn traces(self) -> Vec<FlatTrace> {
|
||||
fn drain(self) -> Vec<FlatTrace> {
|
||||
self.traces
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ pub trait Tracer: Send {
|
||||
fn subtracer(&self) -> Self where Self: Sized;
|
||||
|
||||
/// Consumes self and returns all traces.
|
||||
fn traces(self) -> Vec<FlatTrace>;
|
||||
fn drain(self) -> Vec<FlatTrace>;
|
||||
}
|
||||
|
||||
/// Used by executive to build VM traces.
|
||||
|
@ -62,7 +62,7 @@ impl Tracer for NoopTracer {
|
||||
NoopTracer
|
||||
}
|
||||
|
||||
fn traces(self) -> Vec<FlatTrace> {
|
||||
fn drain(self) -> Vec<FlatTrace> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
@ -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 EvmError> for Error {
|
||||
@ -57,6 +61,8 @@ impl<'a> From<&'a EvmError> for Error {
|
||||
EvmError::Wasm { .. } => Error::Wasm,
|
||||
EvmError::Internal(_) => Error::Internal,
|
||||
EvmError::MutableCallInStaticContext => Error::MutableCallInStaticContext,
|
||||
EvmError::OutOfBounds => Error::OutOfBounds,
|
||||
EvmError::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")),
|
||||
}
|
||||
}
|
||||
|
@ -34,23 +34,29 @@ pub struct Receipt {
|
||||
pub log_bloom: LogBloom,
|
||||
/// The logs stemming from this transaction.
|
||||
pub logs: Vec<LogEntry>,
|
||||
/// Status byte. Optional before EIP-658.
|
||||
pub status_code: Option<u8>,
|
||||
}
|
||||
|
||||
impl Receipt {
|
||||
/// Create a new receipt.
|
||||
pub fn new(state_root: Option<H256>, gas_used: U256, logs: Vec<LogEntry>) -> Receipt {
|
||||
pub fn new(state_root: Option<H256>, status_code: Option<u8>, gas_used: U256, logs: Vec<LogEntry>) -> Receipt {
|
||||
Receipt {
|
||||
state_root: state_root,
|
||||
gas_used: gas_used,
|
||||
log_bloom: logs.iter().fold(LogBloom::default(), |mut b, l| { b = &b | &l.bloom(); b }), //TODO: use |= operator
|
||||
logs: logs,
|
||||
status_code: status_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Receipt {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
if let Some(ref root) = self.state_root {
|
||||
if let Some(ref status) = self.status_code {
|
||||
s.begin_list(4);
|
||||
s.append(status);
|
||||
} else if let Some(ref root) = self.state_root {
|
||||
s.begin_list(4);
|
||||
s.append(root);
|
||||
} else {
|
||||
@ -67,17 +73,27 @@ impl Decodable for Receipt {
|
||||
if rlp.item_count()? == 3 {
|
||||
Ok(Receipt {
|
||||
state_root: None,
|
||||
status_code: None,
|
||||
gas_used: rlp.val_at(0)?,
|
||||
log_bloom: rlp.val_at(1)?,
|
||||
logs: rlp.list_at(2)?,
|
||||
})
|
||||
} else {
|
||||
Ok(Receipt {
|
||||
state_root: Some(rlp.val_at(0)?),
|
||||
let mut receipt = Receipt {
|
||||
gas_used: rlp.val_at(1)?,
|
||||
log_bloom: rlp.val_at(2)?,
|
||||
logs: rlp.list_at(3)?,
|
||||
})
|
||||
state_root: None,
|
||||
status_code: None,
|
||||
};
|
||||
|
||||
let first = rlp.at(0)?;
|
||||
if first.is_data() && first.data()?.len() == 1 {
|
||||
receipt.status_code = Some(first.as_val()?);
|
||||
} else {
|
||||
receipt.state_root = Some(first.as_val()?);
|
||||
}
|
||||
Ok(receipt)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -143,6 +159,7 @@ mod tests {
|
||||
fn test_no_state_root() {
|
||||
let expected = ::rustc_hex::FromHex::from_hex("f9014183040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let r = Receipt::new(
|
||||
None,
|
||||
None,
|
||||
0x40cae.into(),
|
||||
vec![LogEntry {
|
||||
@ -159,6 +176,7 @@ mod tests {
|
||||
let expected = ::rustc_hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let r = Receipt::new(
|
||||
Some("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into()),
|
||||
None,
|
||||
0x40cae.into(),
|
||||
vec![LogEntry {
|
||||
address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
|
||||
|
@ -14,6 +14,7 @@ docopt = "0.8"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
ethcore = { path = "../ethcore" }
|
||||
ethjson = { path = "../json" }
|
||||
ethcore-util = { path = "../util" }
|
||||
evm = { path = "../ethcore/evm" }
|
||||
|
||||
|
@ -30,10 +30,8 @@ pub struct Informant {
|
||||
depth: usize,
|
||||
pc: usize,
|
||||
instruction: u8,
|
||||
name: &'static str,
|
||||
gas_cost: U256,
|
||||
gas_used: U256,
|
||||
stack_pop: usize,
|
||||
stack: Vec<U256>,
|
||||
memory: Vec<u8>,
|
||||
storage: HashMap<H256, H256>,
|
||||
@ -58,11 +56,19 @@ impl Informant {
|
||||
}
|
||||
|
||||
impl vm::Informant for Informant {
|
||||
fn before_test(&self, name: &str, action: &str) {
|
||||
println!(
|
||||
"{{\"test\":\"{name}\",\"action\":\"{action}\"}}",
|
||||
name = name,
|
||||
action = action,
|
||||
);
|
||||
}
|
||||
|
||||
fn set_gas(&mut self, gas: U256) {
|
||||
self.gas_used = gas;
|
||||
}
|
||||
|
||||
fn finish(&mut self, result: Result<vm::Success, vm::Failure>) {
|
||||
fn finish(result: Result<vm::Success, vm::Failure>) {
|
||||
match result {
|
||||
Ok(success) => println!(
|
||||
"{{\"output\":\"0x{output}\",\"gasUsed\":\"{gas:x}\",\"time\":{time}}}",
|
||||
@ -112,7 +118,7 @@ impl trace::VMTracer for Informant {
|
||||
self.gas_used = gas_used;
|
||||
|
||||
let len = self.stack.len();
|
||||
self.stack.truncate(len - info.args);
|
||||
self.stack.truncate(if len > info.args { len - info.args } else { 0 });
|
||||
self.stack.extend_from_slice(stack_push);
|
||||
|
||||
if let Some((pos, data)) = mem_diff {
|
||||
|
@ -27,7 +27,11 @@ use vm;
|
||||
pub struct Informant;
|
||||
|
||||
impl vm::Informant for Informant {
|
||||
fn finish(&mut self, result: Result<vm::Success, vm::Failure>) {
|
||||
fn before_test(&self, name: &str, action: &str) {
|
||||
println!("Test: {} ({})", name, action);
|
||||
}
|
||||
|
||||
fn finish(result: Result<vm::Success, vm::Failure>) {
|
||||
match result {
|
||||
Ok(success) => {
|
||||
println!("Output: 0x{}", success.output.to_hex());
|
||||
|
@ -17,8 +17,9 @@
|
||||
//! Parity EVM interpreter binary.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
extern crate ethcore;
|
||||
extern crate ethjson;
|
||||
extern crate rustc_hex;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
@ -29,6 +30,7 @@ extern crate evm;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{fmt, fs};
|
||||
use std::path::PathBuf;
|
||||
use docopt::Docopt;
|
||||
use rustc_hex::FromHex;
|
||||
use util::{U256, Bytes, Address};
|
||||
@ -48,6 +50,7 @@ Usage:
|
||||
evmbin stats [options]
|
||||
evmbin [options]
|
||||
evmbin [-h | --help]
|
||||
evmbin state-test <file> [--json --only NAME --chain CHAIN]
|
||||
|
||||
Transaction options:
|
||||
--code CODE Contract code as hex (without 0x).
|
||||
@ -55,6 +58,10 @@ Transaction options:
|
||||
--input DATA Input data as hex (without 0x).
|
||||
--gas GAS Supplied gas as hex (without 0x).
|
||||
|
||||
State test options:
|
||||
--only NAME Runs only a single test matching the name.
|
||||
--chain CHAIN Run only tests from specific chain.
|
||||
|
||||
General options:
|
||||
--json Display verbose results in JSON.
|
||||
--chain CHAIN Chain spec file path.
|
||||
@ -65,14 +72,61 @@ General options:
|
||||
fn main() {
|
||||
let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize()).unwrap_or_else(|e| e.exit());
|
||||
|
||||
if args.flag_json {
|
||||
run(args, display::json::Informant::default())
|
||||
if args.cmd_state_test {
|
||||
run_state_test(args)
|
||||
} else if args.flag_json {
|
||||
run_call(args, display::json::Informant::default())
|
||||
} else {
|
||||
run(args, display::simple::Informant::default())
|
||||
run_call(args, display::simple::Informant::default())
|
||||
}
|
||||
}
|
||||
|
||||
fn run<T: Informant>(args: Args, mut informant: T) {
|
||||
fn run_state_test(args: Args) {
|
||||
use ethjson::state::test::Test;
|
||||
|
||||
let file = args.arg_file.expect("FILE is required");
|
||||
let mut file = match fs::File::open(&file) {
|
||||
Err(err) => die(format!("Unable to open: {:?}: {}", file, err)),
|
||||
Ok(file) => file,
|
||||
};
|
||||
let state_test = match Test::load(&mut file) {
|
||||
Err(err) => die(format!("Unable to load the test file: {}", err)),
|
||||
Ok(test) => test,
|
||||
};
|
||||
let only_test = args.flag_only.map(|s| s.to_lowercase());
|
||||
let only_chain = args.flag_chain.map(|s| s.to_lowercase());
|
||||
|
||||
for (name, test) in state_test {
|
||||
if let Some(false) = only_test.as_ref().map(|only_test| &name.to_lowercase() == only_test) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let multitransaction = test.transaction;
|
||||
let env_info = test.env.into();
|
||||
let pre = test.pre_state.into();
|
||||
|
||||
for (spec, states) in test.post_states {
|
||||
if let Some(false) = only_chain.as_ref().map(|only_chain| &format!("{:?}", spec).to_lowercase() == only_chain) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (idx, state) in states.into_iter().enumerate() {
|
||||
let post_root = state.hash.into();
|
||||
let transaction = multitransaction.select(&state.indexes).into();
|
||||
|
||||
if args.flag_json {
|
||||
let i = display::json::Informant::default();
|
||||
vm::run_transaction(&name, idx, &spec, &pre, post_root, &env_info, transaction, i)
|
||||
} else {
|
||||
let i = display::simple::Informant::default();
|
||||
vm::run_transaction(&name, idx, &spec, &pre, post_root, &env_info, transaction, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_call<T: Informant>(args: Args, mut informant: T) {
|
||||
let from = arg(args.from(), "--from");
|
||||
let code = arg(args.code(), "--code");
|
||||
let spec = arg(args.spec(), "--chain");
|
||||
@ -87,18 +141,24 @@ fn run<T: Informant>(args: Args, mut informant: T) {
|
||||
params.data = data;
|
||||
|
||||
informant.set_gas(gas);
|
||||
let result = vm::run(&mut informant, spec, params);
|
||||
informant.finish(result);
|
||||
let result = vm::run(&spec, gas, None, |mut client| {
|
||||
client.call(params, &mut informant).map(|r| (r.gas_left, r.return_data.to_vec()))
|
||||
});
|
||||
T::finish(result);
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Args {
|
||||
cmd_stats: bool,
|
||||
cmd_state_test: bool,
|
||||
arg_file: Option<PathBuf>,
|
||||
flag_only: Option<String>,
|
||||
flag_from: Option<String>,
|
||||
flag_code: Option<String>,
|
||||
flag_gas: Option<String>,
|
||||
flag_input: Option<String>,
|
||||
flag_spec: Option<String>,
|
||||
flag_chain: Option<String>,
|
||||
flag_json: bool,
|
||||
}
|
||||
|
||||
@ -156,3 +216,55 @@ fn die<T: fmt::Display>(msg: T) -> ! {
|
||||
println!("{}", msg);
|
||||
::std::process::exit(-1)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use docopt::Docopt;
|
||||
use super::{Args, USAGE};
|
||||
|
||||
fn run<T: AsRef<str>>(args: &[T]) -> Args {
|
||||
Docopt::new(USAGE).and_then(|d| d.argv(args.into_iter()).deserialize()).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_all_the_options() {
|
||||
let args = run(&[
|
||||
"parity-evm",
|
||||
"--json",
|
||||
"--gas", "1",
|
||||
"--gas-price", "2",
|
||||
"--from", "0000000000000000000000000000000000000003",
|
||||
"--to", "0000000000000000000000000000000000000004",
|
||||
"--code", "05",
|
||||
"--input", "06",
|
||||
"--chain", "./testfile",
|
||||
]);
|
||||
|
||||
assert_eq!(args.flag_json, true);
|
||||
assert_eq!(args.gas(), Ok(1.into()));
|
||||
assert_eq!(args.gas_price(), Ok(2.into()));
|
||||
assert_eq!(args.from(), Ok(3.into()));
|
||||
assert_eq!(args.to(), Ok(4.into()));
|
||||
assert_eq!(args.code(), Ok(Some(vec![05])));
|
||||
assert_eq!(args.data(), Ok(Some(vec![06])));
|
||||
assert_eq!(args.flag_chain, Some("./testfile".to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_state_test_command() {
|
||||
let args = run(&[
|
||||
"parity-evm",
|
||||
"state-test",
|
||||
"./file.json",
|
||||
"--chain", "homestead",
|
||||
"--only=add11",
|
||||
"--json",
|
||||
]);
|
||||
|
||||
assert_eq!(args.cmd_state_test, true);
|
||||
assert!(args.arg_file.is_some());
|
||||
assert_eq!(args.flag_json, true);
|
||||
assert_eq!(args.flag_chain, Some("homestead".to_owned()));
|
||||
assert_eq!(args.flag_only, Some("add11".to_owned()));
|
||||
}
|
||||
}
|
||||
|
@ -17,17 +17,19 @@
|
||||
//! VM runner.
|
||||
|
||||
use std::time::{Instant, Duration};
|
||||
use util::U256;
|
||||
use ethcore::{trace, spec};
|
||||
use ethcore::client::{EvmTestClient, EvmTestError};
|
||||
use evm::action_params::ActionParams;
|
||||
use util::{U256, H256};
|
||||
use ethcore::{trace, spec, transaction, pod_state};
|
||||
use ethcore::client::{self, EvmTestClient, EvmTestError, TransactResult};
|
||||
use ethjson;
|
||||
|
||||
/// VM execution informant
|
||||
pub trait Informant: trace::VMTracer {
|
||||
/// Display a single run init message
|
||||
fn before_test(&self, test: &str, action: &str);
|
||||
/// Set initial gas.
|
||||
fn set_gas(&mut self, _gas: U256) {}
|
||||
/// Display final result.
|
||||
fn finish(&mut self, result: Result<Success, Failure>);
|
||||
fn finish(result: Result<Success, Failure>);
|
||||
}
|
||||
|
||||
/// Execution finished correctly
|
||||
@ -50,17 +52,71 @@ pub struct Failure {
|
||||
pub time: Duration,
|
||||
}
|
||||
|
||||
/// Execute given Transaction and verify resulting state root.
|
||||
pub fn run_transaction<T: Informant>(
|
||||
name: &str,
|
||||
idx: usize,
|
||||
spec: ðjson::state::test::ForkSpec,
|
||||
pre_state: &pod_state::PodState,
|
||||
post_root: H256,
|
||||
env_info: &client::EnvInfo,
|
||||
transaction: transaction::SignedTransaction,
|
||||
mut informant: T,
|
||||
) {
|
||||
let spec_name = format!("{:?}", spec).to_lowercase();
|
||||
let spec = match EvmTestClient::spec_from_json(spec) {
|
||||
Some(spec) => {
|
||||
informant.before_test(&format!("{}:{}:{}", name, spec_name, idx), "starting");
|
||||
spec
|
||||
},
|
||||
None => {
|
||||
informant.before_test(&format!("{}:{}:{}", name, spec_name, idx), "skipping because of missing spec");
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
informant.set_gas(env_info.gas_limit);
|
||||
|
||||
let result = run(spec, env_info.gas_limit, pre_state, |mut client| {
|
||||
let result = client.transact(env_info, transaction, informant);
|
||||
match result {
|
||||
TransactResult::Ok { state_root, .. } if state_root != post_root => {
|
||||
Err(EvmTestError::PostCondition(format!(
|
||||
"State root mismatch (got: {}, expected: {})",
|
||||
state_root,
|
||||
post_root,
|
||||
)))
|
||||
},
|
||||
TransactResult::Ok { gas_left, output, .. } => {
|
||||
Ok((gas_left, output))
|
||||
},
|
||||
TransactResult::Err { error, .. } => {
|
||||
Err(EvmTestError::PostCondition(format!(
|
||||
"Unexpected execution error: {:?}", error
|
||||
)))
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
T::finish(result)
|
||||
}
|
||||
|
||||
/// Execute VM with given `ActionParams`
|
||||
pub fn run<T: trace::VMTracer>(vm_tracer: &mut T, spec: spec::Spec, params: ActionParams) -> Result<Success, Failure> {
|
||||
let mut test_client = EvmTestClient::new(spec).map_err(|error| Failure {
|
||||
pub fn run<'a, F, T>(spec: &'a spec::Spec, initial_gas: U256, pre_state: T, run: F) -> Result<Success, Failure> where
|
||||
F: FnOnce(EvmTestClient) -> Result<(U256, Vec<u8>), EvmTestError>,
|
||||
T: Into<Option<&'a pod_state::PodState>>,
|
||||
{
|
||||
let test_client = match pre_state.into() {
|
||||
Some(pre_state) => EvmTestClient::from_pod_state(spec, pre_state.clone()),
|
||||
None => EvmTestClient::new(spec),
|
||||
}.map_err(|error| Failure {
|
||||
gas_used: 0.into(),
|
||||
error,
|
||||
time: Duration::from_secs(0)
|
||||
})?;
|
||||
|
||||
let initial_gas = params.gas;
|
||||
let start = Instant::now();
|
||||
let result = test_client.call(params, vm_tracer);
|
||||
let result = run(test_client);
|
||||
let duration = start.elapsed();
|
||||
|
||||
match result {
|
||||
|
@ -21,6 +21,7 @@ use hash::H256;
|
||||
use blockchain::state::State;
|
||||
use blockchain::header::Header;
|
||||
use blockchain::block::Block;
|
||||
use state::test::ForkSpec;
|
||||
use spec::{Genesis, Seal, Ethereum};
|
||||
|
||||
/// Blockchain deserialization.
|
||||
@ -42,7 +43,9 @@ pub struct BlockChain {
|
||||
pub pre_state: State,
|
||||
/// Hash of best block.
|
||||
#[serde(rename="lastblockhash")]
|
||||
pub best_block: H256
|
||||
pub best_block: H256,
|
||||
/// Network.
|
||||
pub network: ForkSpec,
|
||||
}
|
||||
|
||||
impl BlockChain {
|
||||
@ -102,7 +105,7 @@ mod tests {
|
||||
"rlp" : "0xf90285f90219a0f052d217bd5275a5177a3c3b7debdfe2670f1c8394b2965ccd5c1883cc1a524da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefba82560b8456850c2ca00102030405060708091011121314151617181920212223242526272829303132a05266ca43e81d25925a9ba573c3e4f9180bc076d316d90e63c6f8708b272f5ce28859ba4daed1898e21f866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ca0ee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3a04e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21c0",
|
||||
"transactions" : [
|
||||
{
|
||||
"data" : "0x",
|
||||
"data" : "0x00",
|
||||
"gasLimit" : "0xc350",
|
||||
"gasPrice" : "0x0a",
|
||||
"nonce" : "0x00",
|
||||
@ -116,6 +119,7 @@ mod tests {
|
||||
"uncleHeaders" : [
|
||||
]
|
||||
}],
|
||||
"network" : "Frontier",
|
||||
"genesisBlockHeader" : {
|
||||
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1",
|
||||
|
@ -34,6 +34,15 @@ pub struct Modexp {
|
||||
pub divisor: usize,
|
||||
}
|
||||
|
||||
/// Pricing for alt_bn128_pairing.
|
||||
#[derive(Debug, PartialEq, Deserialize, Clone)]
|
||||
pub struct AltBn128Pairing {
|
||||
/// Base price.
|
||||
pub base: usize,
|
||||
/// Price per point pair.
|
||||
pub pair: usize,
|
||||
}
|
||||
|
||||
/// Pricing variants.
|
||||
#[derive(Debug, PartialEq, Deserialize, Clone)]
|
||||
pub enum Pricing {
|
||||
@ -43,6 +52,9 @@ pub enum Pricing {
|
||||
/// Pricing for modular exponentiation.
|
||||
#[serde(rename="modexp")]
|
||||
Modexp(Modexp),
|
||||
/// Pricing for alt_bn128_pairing exponentiation.
|
||||
#[serde(rename="alt_bn128_pairing")]
|
||||
AltBn128Pairing(AltBn128Pairing),
|
||||
}
|
||||
|
||||
/// Spec builtin.
|
||||
|
@ -123,6 +123,18 @@ pub struct EthashParams {
|
||||
/// See main EthashParams docs.
|
||||
#[serde(rename="minGasPrice")]
|
||||
pub min_gas_price: Option<Uint>,
|
||||
|
||||
/// EIP-649 transition block.
|
||||
#[serde(rename="eip649Transition")]
|
||||
pub eip649_transition: Option<Uint>,
|
||||
|
||||
/// EIP-649 bomb delay.
|
||||
#[serde(rename="eip649Delay")]
|
||||
pub eip649_delay: Option<Uint>,
|
||||
|
||||
/// EIP-649 base reward.
|
||||
#[serde(rename="eip649Reward")]
|
||||
pub eip649_reward: Option<Uint>,
|
||||
}
|
||||
|
||||
/// Ethash engine deserialization.
|
||||
@ -242,6 +254,9 @@ mod tests {
|
||||
max_gas_limit: None,
|
||||
min_gas_price_transition: None,
|
||||
min_gas_price: None,
|
||||
eip649_transition: None,
|
||||
eip649_delay: None,
|
||||
eip649_reward: None,
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -289,6 +304,9 @@ mod tests {
|
||||
max_gas_limit: None,
|
||||
min_gas_price_transition: None,
|
||||
min_gas_price: None,
|
||||
eip649_transition: None,
|
||||
eip649_delay: None,
|
||||
eip649_reward: None,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -82,6 +82,9 @@ pub struct Params {
|
||||
#[serde(rename="eip214Transition")]
|
||||
pub eip214_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="eip658Transition")]
|
||||
pub eip658_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="dustProtectionTransition")]
|
||||
pub dust_protection_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
|
@ -104,7 +104,12 @@ pub enum ForkSpec {
|
||||
EIP158,
|
||||
Frontier,
|
||||
Homestead,
|
||||
Metropolis,
|
||||
Byzantium,
|
||||
Constantinople,
|
||||
EIP158ToByzantiumAt5,
|
||||
FrontierToHomesteadAt5,
|
||||
HomesteadToDaoAt5,
|
||||
HomesteadToEIP150At5,
|
||||
}
|
||||
|
||||
/// State test indexes deserialization.
|
||||
@ -161,7 +166,7 @@ mod tests {
|
||||
"EIP150" : [
|
||||
{
|
||||
"hash" : "3e6dacc1575c6a8c76422255eca03529bbf4c0dda75dfc110b22d6dc4152396f",
|
||||
"indexes" : { "data" : 0, "gas" : 0, "value" : 0 }
|
||||
"indexes" : { "data" : 0, "gas" : 0, "value" : 0 }
|
||||
},
|
||||
{
|
||||
"hash" : "99a450d8ce5b987a71346d8a0a1203711f770745c7ef326912e46761f14cd764",
|
||||
|
@ -1,54 +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/>.
|
||||
|
||||
//! Vm log deserialization.
|
||||
|
||||
use hash::{Address, H256, Bloom};
|
||||
use bytes::Bytes;
|
||||
|
||||
/// Vm log deserialization.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
pub struct Log {
|
||||
/// Log address.
|
||||
pub address: Address,
|
||||
/// Log bloom.
|
||||
pub bloom: Bloom,
|
||||
/// Data.
|
||||
pub data: Bytes,
|
||||
/// Topics.
|
||||
pub topics: Vec<H256>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
use vm::Log;
|
||||
|
||||
#[test]
|
||||
fn log_deserialization() {
|
||||
let s = r#"{
|
||||
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
|
||||
"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000",
|
||||
"data" : "0xaabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd",
|
||||
"topics" : [
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
]
|
||||
}"#;
|
||||
let _deserialized: Log = serde_json::from_str(s).unwrap();
|
||||
// TODO: validate all fields
|
||||
}
|
||||
}
|
||||
|
@ -19,13 +19,11 @@
|
||||
pub mod env;
|
||||
pub mod transaction;
|
||||
pub mod vm;
|
||||
pub mod log;
|
||||
pub mod call;
|
||||
pub mod test;
|
||||
|
||||
pub use self::env::Env;
|
||||
pub use self::transaction::Transaction;
|
||||
pub use self::vm::Vm;
|
||||
pub use self::log::Log;
|
||||
pub use self::call::Call;
|
||||
pub use self::test::Test;
|
||||
|
@ -18,8 +18,9 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
use uint::Uint;
|
||||
use hash::H256;
|
||||
use blockchain::State;
|
||||
use vm::{Transaction, Log, Call, Env};
|
||||
use vm::{Transaction, Call, Env};
|
||||
|
||||
/// Reporesents vm execution environment before and after exeuction of transaction.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
@ -35,8 +36,8 @@ pub struct Vm {
|
||||
/// Gas left after transaction execution.
|
||||
#[serde(rename="gas")]
|
||||
pub gas_left: Option<Uint>,
|
||||
/// Logs created during execution of transaction.
|
||||
pub logs: Option<Vec<Log>>,
|
||||
/// Hash of logs created during execution of transaction.
|
||||
pub logs: Option<H256>,
|
||||
/// Transaction output.
|
||||
#[serde(rename="out")]
|
||||
pub output: Option<Bytes>,
|
||||
@ -83,9 +84,9 @@ mod tests {
|
||||
"value" : "0x0de0b6b3a7640000"
|
||||
},
|
||||
"gas" : "0x013874",
|
||||
"logs" : [
|
||||
],
|
||||
"logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
"out" : "0x",
|
||||
"network" : "Frontier",
|
||||
"post" : {
|
||||
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
|
||||
"balance" : "0x0de0b6b3a7640000",
|
||||
|
@ -28,6 +28,7 @@ use ethcore::ethereum;
|
||||
use ethcore::miner::{MinerOptions, Banning, GasPricer, MinerService, ExternalMiner, Miner, PendingSet, PrioritizationStrategy, GasLimit};
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethjson::blockchain::BlockChain;
|
||||
use ethjson::state::test::ForkSpec;
|
||||
use io::IoChannel;
|
||||
use util::{U256, H256, Address, Hashable};
|
||||
|
||||
@ -166,13 +167,13 @@ impl EthTester {
|
||||
|
||||
#[test]
|
||||
fn harness_works() {
|
||||
let chain: BlockChain = extract_chain!("BlockchainTests/bcUncleTest");
|
||||
let chain: BlockChain = extract_chain!("BlockchainTests/bcWalletTest/wallet2outOf3txs");
|
||||
let _ = EthTester::from_chain(&chain);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eth_get_balance() {
|
||||
let chain = extract_chain!("BlockchainTests/bcWalletTest", "wallet2outOf3txs");
|
||||
let chain = extract_chain!("BlockchainTests/bcWalletTest/wallet2outOf3txs");
|
||||
let tester = EthTester::from_chain(&chain);
|
||||
// final account state
|
||||
let req_latest = r#"{
|
||||
@ -198,7 +199,7 @@ fn eth_get_balance() {
|
||||
|
||||
#[test]
|
||||
fn eth_block_number() {
|
||||
let chain = extract_chain!("BlockchainTests/bcRPC_API_Test");
|
||||
let chain = extract_chain!("BlockchainTests/bcGasPricerTest/RPC_API_Test");
|
||||
let tester = EthTester::from_chain(&chain);
|
||||
let req_number = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
@ -213,11 +214,11 @@ fn eth_block_number() {
|
||||
|
||||
#[test]
|
||||
fn eth_get_block() {
|
||||
let chain = extract_chain!("BlockchainTests/bcRPC_API_Test");
|
||||
let chain = extract_chain!("BlockchainTests/bcGasPricerTest/RPC_API_Test");
|
||||
let tester = EthTester::from_chain(&chain);
|
||||
let req_block = r#"{"method":"eth_getBlockByNumber","params":["0x0",false],"id":1,"jsonrpc":"2.0"}"#;
|
||||
|
||||
let res_block = r#"{"jsonrpc":"2.0","result":{"author":"0x8888f1f195afa192cfee860698584c030f4c9db1","difficulty":"0x20000","extraData":"0x42","gasLimit":"0x2fefd8","gasUsed":"0x0","hash":"0x5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x8888f1f195afa192cfee860698584c030f4c9db1","mixHash":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","nonce":"0x0102030405060708","number":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sealFields":["0xa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","0x880102030405060708"],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x1ff","stateRoot":"0x7dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1","timestamp":"0x54c98c81","totalDifficulty":"0x20000","transactions":[],"transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","uncles":[]},"id":1}"#.to_owned();
|
||||
let res_block = r#"{"jsonrpc":"2.0","result":{"author":"0x8888f1f195afa192cfee860698584c030f4c9db1","difficulty":"0x20000","extraData":"0x42","gasLimit":"0x1df5d44","gasUsed":"0x0","hash":"0xcded1bc807465a72e2d54697076ab858f28b15d4beaae8faa47339c8eee386a3","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x8888f1f195afa192cfee860698584c030f4c9db1","mixHash":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","nonce":"0x0102030405060708","number":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sealFields":["0xa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","0x880102030405060708"],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x200","stateRoot":"0x7dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1","timestamp":"0x54c98c81","totalDifficulty":"0x20000","transactions":[],"transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","uncles":[]},"id":1}"#;
|
||||
assert_eq!(tester.handler.handle_request_sync(req_block).unwrap(), res_block);
|
||||
}
|
||||
|
||||
@ -463,6 +464,6 @@ fn starting_nonce_test() {
|
||||
assert_eq!(r#"{"jsonrpc":"2.0","result":"0x100","id":15}"#, &sample);
|
||||
}
|
||||
|
||||
register_test!(eth_transaction_count_1, verify_transaction_counts, "BlockchainTests/bcWalletTest");
|
||||
register_test!(eth_transaction_count_2, verify_transaction_counts, "BlockchainTests/bcTotalDifficultyTest");
|
||||
register_test!(eth_transaction_count_3, verify_transaction_counts, "BlockchainTests/bcGasPricerTest");
|
||||
register_test!(eth_transaction_count_1, verify_transaction_counts, "BlockchainTests/bcWalletTest/wallet2outOf3txs");
|
||||
register_test!(eth_transaction_count_2, verify_transaction_counts, "BlockchainTests/bcTotalDifficultyTest/sideChainWithMoreTransactions");
|
||||
register_test!(eth_transaction_count_3, verify_transaction_counts, "BlockchainTests/bcGasPricerTest/RPC_API_Test");
|
||||
|
@ -19,19 +19,8 @@ macro_rules! extract_chain {
|
||||
::ethjson::blockchain::Test::load(RAW_DATA).unwrap().into_iter()
|
||||
}};
|
||||
|
||||
($file:expr, $name:expr) => {{
|
||||
let mut chain = None;
|
||||
for (name, c) in extract_chain!(iter $file) {
|
||||
if name == $name {
|
||||
chain = Some(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
chain.unwrap()
|
||||
}};
|
||||
|
||||
($file:expr) => {{
|
||||
extract_chain!(iter $file).next().unwrap().1
|
||||
extract_chain!(iter $file).filter(|&(_, ref t)| t.network == ForkSpec::Frontier).next().unwrap().1
|
||||
}};
|
||||
}
|
||||
|
||||
@ -39,27 +28,7 @@ macro_rules! register_test {
|
||||
($name:ident, $cb:expr, $file:expr) => {
|
||||
#[test]
|
||||
fn $name() {
|
||||
for (name, chain) in extract_chain!(iter $file) {
|
||||
$cb(name, chain);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(heavy $name:ident, $cb:expr, $file:expr) => {
|
||||
#[test]
|
||||
#[cfg(feature = "test-heavy")]
|
||||
fn $name() {
|
||||
for (name, chain) in extract_chain!(iter $file) {
|
||||
$cb(name, chain);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(ignore $name:ident, $cb:expr, $file:expr) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $name() {
|
||||
for (name, chain) in extract_chain!(iter $file) {
|
||||
for (name, chain) in extract_chain!(iter $file).filter(|&(_, ref t)| t.network == ForkSpec::Frontier) {
|
||||
$cb(name, chain);
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ version = "0.1.3"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
bigint = "3.0"
|
||||
bigint = "4.0"
|
||||
rustc-hex = "1.0"
|
||||
rand = "0.3.12"
|
||||
libc = "0.2"
|
||||
|
Loading…
Reference in New Issue
Block a user