This commit is contained in:
Marek Kotewicz 2017-06-19 11:41:46 +02:00 committed by Gav Wood
parent c50dacff17
commit 575c51f5a0
23 changed files with 185 additions and 103 deletions

View File

@ -353,7 +353,7 @@ pub fn get_temp_state_db() -> GuardedTempResult<StateDB> {
impl MiningBlockChainClient for TestBlockChainClient { impl MiningBlockChainClient for TestBlockChainClient {
fn latest_schedule(&self) -> Schedule { fn latest_schedule(&self) -> Schedule {
Schedule::new_post_eip150(24576, true, true, true, true) Schedule::new_post_eip150(24576, true, true, true)
} }
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {

View File

@ -26,9 +26,8 @@ use account_provider::AccountProvider;
use block::*; use block::*;
use spec::CommonParams; use spec::CommonParams;
use engines::{Call, Engine, Seal, EngineError}; use engines::{Call, Engine, Seal, EngineError};
use header::{Header, BlockNumber}; use header::Header;
use error::{Error, TransactionError, BlockError}; use error::{Error, TransactionError, BlockError};
use evm::Schedule;
use ethjson; use ethjson;
use io::{IoContext, IoHandler, TimerToken, IoService}; use io::{IoContext, IoHandler, TimerToken, IoService};
use builtin::Builtin; use builtin::Builtin;
@ -296,11 +295,6 @@ impl Engine for AuthorityRound {
] ]
} }
fn schedule(&self, block_number: BlockNumber) -> Schedule {
let eip86 = block_number >= self.params.eip86_transition;
Schedule::new_post_eip150(usize::max_value(), true, true, true, eip86)
}
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) { fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
// Chain scoring: total weight is sqrt(U256::max_value())*height - step // Chain scoring: total weight is sqrt(U256::max_value())*height - step
let new_difficulty = U256::from(U128::max_value()) + header_step(parent).expect("Header has been verified; qed").into() - self.step.load().into(); let new_difficulty = U256::from(U128::max_value()) + header_step(parent).expect("Header has been verified; qed").into() - self.step.load().into();

View File

@ -19,9 +19,7 @@ use util::{Address, HashMap};
use builtin::Builtin; use builtin::Builtin;
use engines::{Engine, Seal}; use engines::{Engine, Seal};
use spec::CommonParams; use spec::CommonParams;
use evm::Schedule;
use block::ExecutedBlock; use block::ExecutedBlock;
use header::BlockNumber;
/// An engine which does not provide any consensus mechanism, just seals blocks internally. /// An engine which does not provide any consensus mechanism, just seals blocks internally.
pub struct InstantSeal { pub struct InstantSeal {
@ -58,11 +56,6 @@ impl Engine for InstantSeal {
&self.builtins &self.builtins
} }
fn schedule(&self, block_number: BlockNumber) -> Schedule {
let eip86 = block_number >= self.params.eip86_transition;
Schedule::new_post_eip150(usize::max_value(), true, true, true, eip86)
}
fn seals_internally(&self) -> Option<bool> { Some(true) } fn seals_internally(&self) -> Option<bool> { Some(true) }
fn generate_seal(&self, _block: &ExecutedBlock) -> Seal { fn generate_seal(&self, _block: &ExecutedBlock) -> Seal {

View File

@ -147,7 +147,9 @@ pub trait Engine : Sync + Send {
fn params(&self) -> &CommonParams; fn params(&self) -> &CommonParams;
/// Get the EVM schedule for the given `block_number`. /// Get the EVM schedule for the given `block_number`.
fn schedule(&self, block_number: BlockNumber) -> Schedule; fn schedule(&self, block_number: BlockNumber) -> Schedule {
Schedule::from_params(block_number, self.params())
}
/// Builtin-contracts we would like to see in the chain. /// Builtin-contracts we would like to see in the chain.
/// (In principle these are just hints for the engine since that has the last word on them.) /// (In principle these are just hints for the engine since that has the last word on them.)

View File

@ -38,7 +38,6 @@ use account_provider::AccountProvider;
use block::*; use block::*;
use spec::CommonParams; use spec::CommonParams;
use engines::{Engine, Seal, EngineError}; use engines::{Engine, Seal, EngineError};
use evm::Schedule;
use state::CleanupMode; use state::CleanupMode;
use io::IoService; use io::IoService;
use super::signer::EngineSigner; use super::signer::EngineSigner;
@ -404,11 +403,6 @@ impl Engine for Tendermint {
] ]
} }
fn schedule(&self, block_number: BlockNumber) -> Schedule {
let eip86 = block_number >= self.params.eip86_transition;
Schedule::new_post_eip150(usize::max_value(), true, true, true, eip86)
}
fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) { fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) {
// Chain scoring: total weight is sqrt(U256::max_value())*height - view // Chain scoring: total weight is sqrt(U256::max_value())*height - view
let new_difficulty = U256::from(U128::max_value()) + consensus_view(parent).expect("Header has been verified; qed").into() - self.view.load(AtomicOrdering::SeqCst).into(); let new_difficulty = U256::from(U128::max_value()) + consensus_view(parent).expect("Header has been verified; qed").into() - self.view.load(AtomicOrdering::SeqCst).into();

View File

@ -196,13 +196,13 @@ impl Engine for Arc<Ethash> {
} else if block_number < self.ethash_params.eip150_transition { } else if block_number < self.ethash_params.eip150_transition {
Schedule::new_homestead() Schedule::new_homestead()
} else { } else {
Schedule::new_post_eip150( let mut schedule = Schedule::new_post_eip150(
self.ethash_params.max_code_size as usize, self.ethash_params.max_code_size as usize,
block_number >= self.ethash_params.eip160_transition, block_number >= self.ethash_params.eip160_transition,
block_number >= self.ethash_params.eip161abc_transition, block_number >= self.ethash_params.eip161abc_transition,
block_number >= self.ethash_params.eip161d_transition, block_number >= self.ethash_params.eip161d_transition);
block_number >= self.params.eip86_transition schedule.apply_params(block_number, self.params());
) schedule
} }
} }

View File

@ -62,7 +62,8 @@ pub enum Error {
}, },
/// Built-in contract failed on given input /// Built-in contract failed on given input
BuiltIn(&'static str), BuiltIn(&'static str),
/// Returned on evm internal error. Should never be ignored during development. /// When execution tries to modify the state in static context
MutableCallInStaticContext,
/// Likely to cause consensus issues. /// Likely to cause consensus issues.
Internal(String), Internal(String),
} }
@ -90,6 +91,7 @@ impl fmt::Display for Error {
OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit), OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit),
BuiltIn(name) => write!(f, "Built-in failed: {}", name), BuiltIn(name) => write!(f, "Built-in failed: {}", name),
Internal(ref msg) => write!(f, "Internal error: {}", msg), Internal(ref msg) => write!(f, "Internal error: {}", msg),
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
} }
} }
} }

View File

@ -53,25 +53,24 @@ pub enum CreateContractAddress {
} }
/// Externalities interface for EVMs /// Externalities interface for EVMs
// TODO: [rob] associated error type instead of `trie::Result`. Not all EVMs are trie powered.
pub trait Ext { pub trait Ext {
/// Returns a value for given key. /// Returns a value for given key.
fn storage_at(&self, key: &H256) -> trie::Result<H256>; fn storage_at(&self, key: &H256) -> evm::Result<H256>;
/// Stores a value for given key. /// Stores a value for given key.
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()>; fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()>;
/// Determine whether an account exists. /// Determine whether an account exists.
fn exists(&self, address: &Address) -> trie::Result<bool>; fn exists(&self, address: &Address) -> evm::Result<bool>;
/// Determine whether an account exists and is not null (zero balance/nonce, no code). /// Determine whether an account exists and is not null (zero balance/nonce, no code).
fn exists_and_not_null(&self, address: &Address) -> trie::Result<bool>; fn exists_and_not_null(&self, address: &Address) -> evm::Result<bool>;
/// Balance of the origin account. /// Balance of the origin account.
fn origin_balance(&self) -> trie::Result<U256>; fn origin_balance(&self) -> evm::Result<U256>;
/// Returns address balance. /// Returns address balance.
fn balance(&self, address: &Address) -> trie::Result<U256>; fn balance(&self, address: &Address) -> evm::Result<U256>;
/// Returns the hash of one of the 256 most recent complete blocks. /// Returns the hash of one of the 256 most recent complete blocks.
fn blockhash(&mut self, number: &U256) -> H256; fn blockhash(&mut self, number: &U256) -> H256;
@ -99,13 +98,13 @@ pub trait Ext {
) -> MessageCallResult; ) -> MessageCallResult;
/// Returns code at given address /// Returns code at given address
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>>; fn extcode(&self, address: &Address) -> evm::Result<Arc<Bytes>>;
/// Returns code size at given address /// Returns code size at given address
fn extcodesize(&self, address: &Address) -> trie::Result<usize>; fn extcodesize(&self, address: &Address) -> evm::Result<usize>;
/// Creates log entry with given topics and data /// Creates log entry with given topics and data
fn log(&mut self, topics: Vec<H256>, data: &[u8]); fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()>;
/// Should be called when transaction calls `RETURN` opcode. /// Should be called when transaction calls `RETURN` opcode.
/// Returns gas_left if cost of returning the data is not too high. /// Returns gas_left if cost of returning the data is not too high.
@ -113,7 +112,7 @@ pub trait Ext {
/// Should be called when contract commits suicide. /// Should be called when contract commits suicide.
/// Address to which funds should be refunded. /// Address to which funds should be refunded.
fn suicide(&mut self, refund_address: &Address) -> trie::Result<()> ; fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> ;
/// Returns schedule. /// Returns schedule.
fn schedule(&self) -> &Schedule; fn schedule(&self) -> &Schedule;

View File

@ -298,6 +298,7 @@ lazy_static! {
arr[CALLCODE as usize] = InstructionInfo::new("CALLCODE", 7, 1, GasPriceTier::Special); arr[CALLCODE as usize] = InstructionInfo::new("CALLCODE", 7, 1, GasPriceTier::Special);
arr[RETURN as usize] = InstructionInfo::new("RETURN", 2, 0, GasPriceTier::Zero); arr[RETURN as usize] = InstructionInfo::new("RETURN", 2, 0, GasPriceTier::Zero);
arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 6, 1, GasPriceTier::Special); arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 6, 1, GasPriceTier::Special);
arr[STATICCALL as usize] = InstructionInfo::new("STATICCALL", 6, 1, GasPriceTier::Special);
arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 1, 0, GasPriceTier::Special); arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 1, 0, GasPriceTier::Special);
arr[CREATE2 as usize] = InstructionInfo::new("CREATE2", 3, 1, GasPriceTier::Special); arr[CREATE2 as usize] = InstructionInfo::new("CREATE2", 3, 1, GasPriceTier::Special);
arr[REVERT as usize] = InstructionInfo::new("REVERT", 2, 0, GasPriceTier::Zero); arr[REVERT as usize] = InstructionInfo::new("REVERT", 2, 0, GasPriceTier::Zero);
@ -584,6 +585,8 @@ pub const DELEGATECALL: Instruction = 0xf4;
pub const CREATE2: Instruction = 0xfb; pub const CREATE2: Instruction = 0xfb;
/// stop execution and revert state changes. Return output data. /// stop execution and revert state changes. Return output data.
pub const REVERT: Instruction = 0xfd; pub const REVERT: Instruction = 0xfd;
/// like CALL but it does not take value, nor modify the state
pub const STATICCALL: Instruction = 0xfa;
/// halt execution and register account for later deletion /// halt execution and register account for later deletion
pub const SUICIDE: Instruction = 0xff; pub const SUICIDE: Instruction = 0xff;

View File

@ -213,7 +213,7 @@ impl<Gas: CostType> Gasometer<Gas> {
Request::GasMemProvide(gas, mem, Some(requested)) Request::GasMemProvide(gas, mem, Some(requested))
}, },
instructions::DELEGATECALL => { instructions::DELEGATECALL | instructions::STATICCALL => {
let gas = Gas::from(schedule.call_gas); let gas = Gas::from(schedule.call_gas);
let mem = cmp::max( let mem = cmp::max(
mem_needed(stack.peek(4), stack.peek(5))?, mem_needed(stack.peek(4), stack.peek(5))?,

View File

@ -199,6 +199,7 @@ impl<Cost: CostType> Interpreter<Cost> {
if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) || if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
(instruction == instructions::CREATE2 && !schedule.have_create2) || (instruction == instructions::CREATE2 && !schedule.have_create2) ||
(instruction == instructions::STATICCALL && !schedule.have_static_call) ||
(instruction == instructions::REVERT && !schedule.have_revert) { (instruction == instructions::REVERT && !schedule.have_revert) {
return Err(evm::Error::BadInstruction { return Err(evm::Error::BadInstruction {
@ -312,14 +313,15 @@ impl<Cost: CostType> Interpreter<Cost> {
} }
}; };
}, },
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => { instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => {
assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible"); assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible");
stack.pop_back(); stack.pop_back();
let call_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is one of `CALL`/`CALLCODE`/`DELEGATECALL`; qed"); let call_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is one of `CALL`/`CALLCODE`/`DELEGATECALL`; qed");
let code_address = stack.pop_back(); let code_address = stack.pop_back();
let code_address = u256_to_address(&code_address); let code_address = u256_to_address(&code_address);
let value = if instruction == instructions::DELEGATECALL { let value = if instruction == instructions::DELEGATECALL || instruction == instructions::STATICCALL {
None None
} else { } else {
Some(stack.pop_back()) Some(stack.pop_back())
@ -347,6 +349,7 @@ impl<Cost: CostType> Interpreter<Cost> {
(&params.address, &params.address, has_balance, CallType::CallCode) (&params.address, &params.address, has_balance, CallType::CallCode)
}, },
instructions::DELEGATECALL => (&params.sender, &params.address, true, CallType::DelegateCall), instructions::DELEGATECALL => (&params.sender, &params.address, true, CallType::DelegateCall),
instructions::STATICCALL => (&params.sender, &params.address, true, CallType::StaticCall),
_ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction)) _ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction))
}; };
@ -405,7 +408,7 @@ impl<Cost: CostType> Interpreter<Cost> {
.iter() .iter()
.map(H256::from) .map(H256::from)
.collect(); .collect();
ext.log(topics, self.mem.read_slice(offset, size)); ext.log(topics, self.mem.read_slice(offset, size))?;
}, },
instructions::PUSH1...instructions::PUSH32 => { instructions::PUSH1...instructions::PUSH32 => {
let bytes = instructions::get_push_bytes(instruction); let bytes = instructions::get_push_bytes(instruction);

View File

@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Cost schedule and other parameterisations for the EVM. //! Cost schedule and other parameterisations for the EVM.
use spec::CommonParams;
/// Definition of the cost schedule and other parameterisations for the EVM. /// Definition of the cost schedule and other parameterisations for the EVM.
pub struct Schedule { pub struct Schedule {
@ -105,6 +106,8 @@ pub struct Schedule {
pub kill_empty: bool, pub kill_empty: bool,
/// Blockhash instruction gas cost. /// Blockhash instruction gas cost.
pub blockhash_gas: usize, pub blockhash_gas: usize,
/// Static Call opcode enabled.
pub have_static_call: bool,
} }
impl Schedule { impl Schedule {
@ -119,12 +122,12 @@ impl Schedule {
} }
/// Schedule for the post-EIP-150-era of the Ethereum main net. /// Schedule for the post-EIP-150-era of the Ethereum main net.
pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool, have_metropolis_instructions: bool) -> Schedule { pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule {
Schedule { Schedule {
exceptional_failed_code_deposit: true, exceptional_failed_code_deposit: true,
have_delegate_call: true, have_delegate_call: true,
have_create2: have_metropolis_instructions, have_create2: false,
have_revert: have_metropolis_instructions, have_revert: false,
stack_limit: 1024, stack_limit: 1024,
max_depth: 1024, max_depth: 1024,
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
@ -163,13 +166,36 @@ impl Schedule {
sub_gas_cap_divisor: Some(64), sub_gas_cap_divisor: Some(64),
no_empty: no_empty, no_empty: no_empty,
kill_empty: kill_empty, kill_empty: kill_empty,
blockhash_gas: if have_metropolis_instructions { 350 } else { 20 }, blockhash_gas: 20,
have_static_call: false,
}
}
/// Schedule for the Metropolis era from common spec params.
pub fn from_params(block_number: u64, params: &CommonParams) -> Schedule {
let mut schedule = Schedule::new_post_eip150(usize::max_value(), true, true, true);
schedule.apply_params(block_number, params);
schedule
}
/// Apply common spec config parameters to the schedule.
pub fn apply_params(&mut self, block_number: u64, params: &CommonParams) {
self.have_create2 = block_number >= params.eip86_transition;
self.have_revert = block_number >= params.eip140_transition;
self.have_static_call = block_number >= params.eip214_transition;
if block_number >= params.eip210_transition {
self.blockhash_gas = 350;
} }
} }
/// Schedule for the Metropolis of the Ethereum main net. /// Schedule for the Metropolis of the Ethereum main net.
pub fn new_metropolis() -> Schedule { pub fn new_metropolis() -> Schedule {
Self::new_post_eip150(24576, true, true, true, true) 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.blockhash_gas = 350;
schedule
} }
fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule { fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule {
@ -217,6 +243,7 @@ impl Schedule {
no_empty: false, no_empty: false,
kill_empty: false, kill_empty: false,
blockhash_gas: 20, blockhash_gas: 20,
have_static_call: false,
} }
} }
} }

View File

@ -87,28 +87,28 @@ impl Default for Schedule {
} }
impl Ext for FakeExt { impl Ext for FakeExt {
fn storage_at(&self, key: &H256) -> trie::Result<H256> { fn storage_at(&self, key: &H256) -> evm::Result<H256> {
Ok(self.store.get(key).unwrap_or(&H256::new()).clone()) Ok(self.store.get(key).unwrap_or(&H256::new()).clone())
} }
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()> { fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> {
self.store.insert(key, value); self.store.insert(key, value);
Ok(()) Ok(())
} }
fn exists(&self, address: &Address) -> trie::Result<bool> { fn exists(&self, address: &Address) -> evm::Result<bool> {
Ok(self.balances.contains_key(address)) Ok(self.balances.contains_key(address))
} }
fn exists_and_not_null(&self, address: &Address) -> trie::Result<bool> { fn exists_and_not_null(&self, address: &Address) -> evm::Result<bool> {
Ok(self.balances.get(address).map_or(false, |b| !b.is_zero())) Ok(self.balances.get(address).map_or(false, |b| !b.is_zero()))
} }
fn origin_balance(&self) -> trie::Result<U256> { fn origin_balance(&self) -> evm::Result<U256> {
unimplemented!() unimplemented!()
} }
fn balance(&self, address: &Address) -> trie::Result<U256> { fn balance(&self, address: &Address) -> evm::Result<U256> {
Ok(self.balances[address]) Ok(self.balances[address])
} }
@ -152,26 +152,27 @@ impl Ext for FakeExt {
MessageCallResult::Success(*gas, ReturnData::empty()) MessageCallResult::Success(*gas, ReturnData::empty())
} }
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>> { fn extcode(&self, address: &Address) -> evm::Result<Arc<Bytes>> {
Ok(self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone()) Ok(self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone())
} }
fn extcodesize(&self, address: &Address) -> trie::Result<usize> { fn extcodesize(&self, address: &Address) -> evm::Result<usize> {
Ok(self.codes.get(address).map_or(0, |c| c.len())) Ok(self.codes.get(address).map_or(0, |c| c.len()))
} }
fn log(&mut self, topics: Vec<H256>, data: &[u8]) { fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()> {
self.logs.push(FakeLogEntry { self.logs.push(FakeLogEntry {
topics: topics, topics: topics,
data: data.to_vec() data: data.to_vec()
}); });
Ok(())
} }
fn ret(self, _gas: &U256, _data: &ReturnData) -> evm::Result<U256> { fn ret(self, _gas: &U256, _data: &ReturnData) -> evm::Result<U256> {
unimplemented!(); unimplemented!();
} }
fn suicide(&mut self, _refund_address: &Address) -> trie::Result<()> { fn suicide(&mut self, _refund_address: &Address) -> evm::Result<()> {
unimplemented!(); unimplemented!();
} }

View File

@ -76,6 +76,7 @@ pub struct Executive<'a, B: 'a + StateBackend, E: 'a + Engine + ?Sized> {
info: &'a EnvInfo, info: &'a EnvInfo,
engine: &'a E, engine: &'a E,
depth: usize, depth: usize,
static_flag: bool,
} }
impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
@ -86,16 +87,18 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
info: info, info: info,
engine: engine, engine: engine,
depth: 0, depth: 0,
static_flag: false,
} }
} }
/// Populates executive from parent properties. Increments executive depth. /// Populates executive from parent properties. Increments executive depth.
pub fn from_parent(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a E, parent_depth: usize) -> Self { pub fn from_parent(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a E, parent_depth: usize, static_flag: bool) -> Self {
Executive { Executive {
state: state, state: state,
info: info, info: info,
engine: engine, engine: engine,
depth: parent_depth + 1, depth: parent_depth + 1,
static_flag: static_flag,
} }
} }
@ -106,9 +109,11 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
substate: &'any mut Substate, substate: &'any mut Substate,
output: OutputPolicy<'any, 'any>, output: OutputPolicy<'any, 'any>,
tracer: &'any mut T, tracer: &'any mut T,
vm_tracer: &'any mut V vm_tracer: &'any mut V,
static_call: bool,
) -> Externalities<'any, T, V, B, E> where T: Tracer, V: VMTracer { ) -> Externalities<'any, T, V, B, E> where T: Tracer, V: VMTracer {
Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output, tracer, vm_tracer) let is_static = self.static_flag || static_call;
Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output, tracer, vm_tracer, is_static)
} }
/// This function should be used to execute transaction. /// This function should be used to execute transaction.
@ -246,11 +251,12 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
) -> evm::Result<FinalizationResult> where T: Tracer, V: VMTracer { ) -> evm::Result<FinalizationResult> where T: Tracer, V: VMTracer {
let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH); let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH);
let static_call = params.call_type == CallType::StaticCall;
// Ordinary execution - keep VM in same thread // Ordinary execution - keep VM in same thread
if (self.depth + 1) % depth_threshold != 0 { if (self.depth + 1) % depth_threshold != 0 {
let vm_factory = self.state.vm_factory(); let vm_factory = self.state.vm_factory();
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer); let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
return vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext); return vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext);
} }
@ -260,7 +266,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
// https://github.com/aturon/crossbeam/issues/16 // https://github.com/aturon/crossbeam/issues/16
crossbeam::scope(|scope| { crossbeam::scope(|scope| {
let vm_factory = self.state.vm_factory(); let vm_factory = self.state.vm_factory();
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer); let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
scope.spawn(move || { scope.spawn(move || {
vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext) vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext)
@ -280,6 +286,15 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
tracer: &mut T, tracer: &mut T,
vm_tracer: &mut V vm_tracer: &mut V
) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { ) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
if (params.call_type == CallType::StaticCall ||
((params.call_type == CallType::Call || params.call_type == CallType::DelegateCall) &&
self.static_flag))
&& params.value.value() > 0.into() {
return Err(evm::Error::MutableCallInStaticContext);
}
// backup used in case of running out of gas // backup used in case of running out of gas
self.state.checkpoint(); self.state.checkpoint();
@ -289,7 +304,6 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
if let ActionValue::Transfer(val) = params.value { if let ActionValue::Transfer(val) = params.value {
self.state.transfer_balance(&params.sender, &params.address, &val, substate.to_cleanup_mode(&schedule))?; self.state.transfer_balance(&params.sender, &params.address, &val, substate.to_cleanup_mode(&schedule))?;
} }
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
// if destination is builtin, try to execute it // if destination is builtin, try to execute it
if let Some(builtin) = self.engine.builtin(&params.code_address, self.info.number) { if let Some(builtin) = self.engine.builtin(&params.code_address, self.info.number) {
@ -403,6 +417,12 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
return Err(evm::Error::OutOfGas); return Err(evm::Error::OutOfGas);
} }
if params.call_type == CallType::StaticCall || self.static_flag {
let trace_info = tracer.prepare_trace_create(&params);
tracer.trace_failed_create(trace_info, vec![], evm::Error::MutableCallInStaticContext.into());
return Err(evm::Error::MutableCallInStaticContext);
}
// backup used in case of running out of gas // backup used in case of running out of gas
self.state.checkpoint(); self.state.checkpoint();
@ -541,6 +561,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
| Err(evm::Error::StackUnderflow {..}) | Err(evm::Error::StackUnderflow {..})
| Err(evm::Error::BuiltIn {..}) | Err(evm::Error::BuiltIn {..})
| Err(evm::Error::OutOfStack {..}) | Err(evm::Error::OutOfStack {..})
| Err(evm::Error::MutableCallInStaticContext)
| Ok(FinalizationResult { apply_state: false, .. }) => { | Ok(FinalizationResult { apply_state: false, .. }) => {
self.state.revert_to_checkpoint(); self.state.revert_to_checkpoint();
}, },

View File

@ -40,7 +40,7 @@ pub struct OriginInfo {
address: Address, address: Address,
origin: Address, origin: Address,
gas_price: U256, gas_price: U256,
value: U256 value: U256,
} }
impl OriginInfo { impl OriginInfo {
@ -52,7 +52,7 @@ impl OriginInfo {
gas_price: params.gas_price, gas_price: params.gas_price,
value: match params.value { value: match params.value {
ActionValue::Transfer(val) | ActionValue::Apparent(val) => val ActionValue::Transfer(val) | ActionValue::Apparent(val) => val
} },
} }
} }
} }
@ -71,6 +71,7 @@ pub struct Externalities<'a, T: 'a, V: 'a, B: 'a, E: 'a + Engine + ?Sized>
output: OutputPolicy<'a, 'a>, output: OutputPolicy<'a, 'a>,
tracer: &'a mut T, tracer: &'a mut T,
vm_tracer: &'a mut V, vm_tracer: &'a mut V,
static_flag: bool,
} }
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Externalities<'a, T, V, B, E> impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Externalities<'a, T, V, B, E>
@ -87,6 +88,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Externalities<'a, T, V, B, E>
output: OutputPolicy<'a, 'a>, output: OutputPolicy<'a, 'a>,
tracer: &'a mut T, tracer: &'a mut T,
vm_tracer: &'a mut V, vm_tracer: &'a mut V,
static_flag: bool,
) -> Self { ) -> Self {
Externalities { Externalities {
state: state, state: state,
@ -99,6 +101,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Externalities<'a, T, V, B, E>
output: output, output: output,
tracer: tracer, tracer: tracer,
vm_tracer: vm_tracer, vm_tracer: vm_tracer,
static_flag: static_flag,
} }
} }
} }
@ -106,26 +109,32 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Externalities<'a, T, V, B, E>
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
{ {
fn storage_at(&self, key: &H256) -> trie::Result<H256> { fn storage_at(&self, key: &H256) -> evm::Result<H256> {
self.state.storage_at(&self.origin_info.address, key) self.state.storage_at(&self.origin_info.address, key).map_err(Into::into)
} }
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()> { fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> {
self.state.set_storage(&self.origin_info.address, key, value) if self.static_flag {
Err(evm::Error::MutableCallInStaticContext)
} else {
self.state.set_storage(&self.origin_info.address, key, value).map_err(Into::into)
}
} }
fn exists(&self, address: &Address) -> trie::Result<bool> { fn exists(&self, address: &Address) -> evm::Result<bool> {
self.state.exists(address) self.state.exists(address).map_err(Into::into)
} }
fn exists_and_not_null(&self, address: &Address) -> trie::Result<bool> { fn exists_and_not_null(&self, address: &Address) -> evm::Result<bool> {
self.state.exists_and_not_null(address) self.state.exists_and_not_null(address).map_err(Into::into)
} }
fn origin_balance(&self) -> trie::Result<U256> { self.balance(&self.origin_info.address) } fn origin_balance(&self) -> evm::Result<U256> {
self.balance(&self.origin_info.address).map_err(Into::into)
}
fn balance(&self, address: &Address) -> trie::Result<U256> { fn balance(&self, address: &Address) -> evm::Result<U256> {
self.state.balance(address) self.state.balance(address).map_err(Into::into)
} }
fn blockhash(&mut self, number: &U256) -> H256 { fn blockhash(&mut self, number: &U256) -> H256 {
@ -208,7 +217,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
return ContractCreateResult::Failed return ContractCreateResult::Failed
} }
} }
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth, self.static_flag);
// TODO: handle internal error separately // TODO: handle internal error separately
match ex.create(params, self.substate, self.tracer, self.vm_tracer) { match ex.create(params, self.substate, self.tracer, self.vm_tracer) {
@ -258,7 +267,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
params.value = ActionValue::Transfer(value); params.value = ActionValue::Transfer(value);
} }
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); 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) { 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((gas_left, return_data)) => MessageCallResult::Success(gas_left, return_data),
@ -266,11 +275,11 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
} }
} }
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>> { fn extcode(&self, address: &Address) -> evm::Result<Arc<Bytes>> {
Ok(self.state.code(address)?.unwrap_or_else(|| Arc::new(vec![]))) Ok(self.state.code(address)?.unwrap_or_else(|| Arc::new(vec![])))
} }
fn extcodesize(&self, address: &Address) -> trie::Result<usize> { fn extcodesize(&self, address: &Address) -> evm::Result<usize> {
Ok(self.state.code_size(address)?.unwrap_or(0)) Ok(self.state.code_size(address)?.unwrap_or(0))
} }
@ -312,18 +321,28 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
} }
} }
fn log(&mut self, topics: Vec<H256>, data: &[u8]) { fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()> {
use log_entry::LogEntry; use log_entry::LogEntry;
if self.static_flag {
return Err(evm::Error::MutableCallInStaticContext);
}
let address = self.origin_info.address.clone(); let address = self.origin_info.address.clone();
self.substate.logs.push(LogEntry { self.substate.logs.push(LogEntry {
address: address, address: address,
topics: topics, topics: topics,
data: data.to_vec() data: data.to_vec()
}); });
Ok(())
}
fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> {
if self.static_flag {
return Err(evm::Error::MutableCallInStaticContext);
} }
fn suicide(&mut self, refund_address: &Address) -> trie::Result<()> {
let address = self.origin_info.address.clone(); let address = self.origin_info.address.clone();
let balance = self.balance(&address)?; let balance = self.balance(&address)?;
if &address == refund_address { if &address == refund_address {
@ -434,7 +453,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
assert_eq!(ext.env_info().number, 100); assert_eq!(ext.env_info().number, 100);
} }
@ -446,7 +465,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
@ -470,7 +489,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
@ -485,7 +504,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
let mut output = vec![]; let mut output = vec![];
@ -513,8 +532,8 @@ mod tests {
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
{ {
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
ext.log(log_topics, &log_data); ext.log(log_topics, &log_data).unwrap();
} }
assert_eq!(setup.sub_state.logs.len(), 1); assert_eq!(setup.sub_state.logs.len(), 1);
@ -530,7 +549,7 @@ mod tests {
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
{ {
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer); let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
ext.suicide(refund_account).unwrap(); ext.suicide(refund_account).unwrap();
} }

View File

@ -75,9 +75,10 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> TestExt<'a, T, V, B, E>
tracer: &'a mut T, tracer: &'a mut T,
vm_tracer: &'a mut V, vm_tracer: &'a mut V,
) -> trie::Result<Self> { ) -> trie::Result<Self> {
let static_call = false;
Ok(TestExt { Ok(TestExt {
nonce: state.nonce(&address)?, nonce: state.nonce(&address)?,
ext: Externalities::new(state, info, engine, depth, origin_info, substate, output, tracer, vm_tracer), ext: Externalities::new(state, info, engine, depth, origin_info, substate, output, tracer, vm_tracer, static_call),
callcreates: vec![], callcreates: vec![],
sender: address, sender: address,
}) })
@ -87,27 +88,27 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> TestExt<'a, T, V, B, E>
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E> impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
{ {
fn storage_at(&self, key: &H256) -> trie::Result<H256> { fn storage_at(&self, key: &H256) -> evm::Result<H256> {
self.ext.storage_at(key) self.ext.storage_at(key)
} }
fn set_storage(&mut self, key: H256, value: H256) -> trie::Result<()> { fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> {
self.ext.set_storage(key, value) self.ext.set_storage(key, value)
} }
fn exists(&self, address: &Address) -> trie::Result<bool> { fn exists(&self, address: &Address) -> evm::Result<bool> {
self.ext.exists(address) self.ext.exists(address)
} }
fn exists_and_not_null(&self, address: &Address) -> trie::Result<bool> { fn exists_and_not_null(&self, address: &Address) -> evm::Result<bool> {
self.ext.exists_and_not_null(address) self.ext.exists_and_not_null(address)
} }
fn balance(&self, address: &Address) -> trie::Result<U256> { fn balance(&self, address: &Address) -> evm::Result<U256> {
self.ext.balance(address) self.ext.balance(address)
} }
fn origin_balance(&self) -> trie::Result<U256> { fn origin_balance(&self) -> evm::Result<U256> {
self.ext.origin_balance() self.ext.origin_balance()
} }
@ -145,15 +146,15 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
MessageCallResult::Success(*gas, ReturnData::empty()) MessageCallResult::Success(*gas, ReturnData::empty())
} }
fn extcode(&self, address: &Address) -> trie::Result<Arc<Bytes>> { fn extcode(&self, address: &Address) -> evm::Result<Arc<Bytes>> {
self.ext.extcode(address) self.ext.extcode(address)
} }
fn extcodesize(&self, address: &Address) -> trie::Result<usize> { fn extcodesize(&self, address: &Address) -> evm::Result<usize> {
self.ext.extcodesize(address) self.ext.extcodesize(address)
} }
fn log(&mut self, topics: Vec<H256>, data: &[u8]) { fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()> {
self.ext.log(topics, data) self.ext.log(topics, data)
} }
@ -161,7 +162,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
self.ext.ret(gas, data) self.ext.ret(gas, data)
} }
fn suicide(&mut self, refund_address: &Address) -> trie::Result<()> { fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> {
self.ext.suicide(refund_address) self.ext.suicide(refund_address)
} }

View File

@ -74,6 +74,8 @@ pub struct CommonParams {
pub eip210_contract_gas: U256, pub eip210_contract_gas: U256,
/// Number of first block where EIP-211 (Metropolis: RETURNDATASIZE/RETURNDATACOPY) rules begin. /// Number of first block where EIP-211 (Metropolis: RETURNDATASIZE/RETURNDATACOPY) rules begin.
pub eip211_transition: BlockNumber, pub eip211_transition: BlockNumber,
/// Number of first block where EIP-214 rules begin.
pub eip214_transition: BlockNumber,
} }
impl From<ethjson::spec::Params> for CommonParams { impl From<ethjson::spec::Params> for CommonParams {
@ -97,6 +99,7 @@ impl From<ethjson::spec::Params> for CommonParams {
Into::into), Into::into),
eip210_contract_gas: p.eip210_contract_gas.map_or(1000000.into(), Into::into), 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), eip211_transition: p.eip211_transition.map_or(BlockNumber::max_value(), Into::into),
eip214_transition: p.eip214_transition.map_or(BlockNumber::max_value(), Into::into),
} }
} }
} }

View File

@ -36,6 +36,8 @@ pub enum CallType {
CallCode, CallCode,
/// DELEGATECALL. /// DELEGATECALL.
DelegateCall, DelegateCall,
/// STATICCALL
StaticCall,
} }
impl Encodable for CallType { impl Encodable for CallType {
@ -45,6 +47,7 @@ impl Encodable for CallType {
CallType::Call => 1, CallType::Call => 1,
CallType::CallCode => 2, CallType::CallCode => 2,
CallType::DelegateCall => 3, CallType::DelegateCall => 3,
CallType::StaticCall => 4,
}; };
Encodable::rlp_append(&v, s); Encodable::rlp_append(&v, s);
} }
@ -57,6 +60,7 @@ impl Decodable for CallType {
1 => CallType::Call, 1 => CallType::Call,
2 => CallType::CallCode, 2 => CallType::CallCode,
3 => CallType::DelegateCall, 3 => CallType::DelegateCall,
4 => CallType::StaticCall,
_ => return Err(DecoderError::Custom("Invalid value of CallType item")), _ => return Err(DecoderError::Custom("Invalid value of CallType item")),
})) }))
} }
@ -145,6 +149,8 @@ pub enum ExecutionError {
/// Actual balance. /// Actual balance.
got: U512 got: U512
}, },
/// When execution tries to modify the state in static context
MutableCallInStaticContext,
/// Returned when internal evm error occurs. /// Returned when internal evm error occurs.
Internal(String), Internal(String),
/// Returned when generic transaction occurs /// Returned when generic transaction occurs
@ -172,6 +178,7 @@ impl fmt::Display for ExecutionError {
NotEnoughCash { ref required, ref got } => NotEnoughCash { ref required, ref got } =>
format!("Cost of transaction exceeds sender balance. {} is required \ format!("Cost of transaction exceeds sender balance. {} is required \
but the sender only has {}", required, got), but the sender only has {}", required, got),
MutableCallInStaticContext => "Mutable Call in static context".to_owned(),
Internal(ref msg) => msg.clone(), Internal(ref msg) => msg.clone(),
TransactionMalformed(ref err) => format!("Malformed transaction: {}", err), TransactionMalformed(ref err) => format!("Malformed transaction: {}", err),
}; };

View File

@ -40,6 +40,8 @@ pub enum Error {
/// Returned on evm internal error. Should never be ignored during development. /// Returned on evm internal error. Should never be ignored during development.
/// Likely to cause consensus issues. /// Likely to cause consensus issues.
Internal, Internal,
/// When execution tries to modify the state in static context
MutableCallInStaticContext,
} }
impl<'a> From<&'a EvmError> for Error { impl<'a> From<&'a EvmError> for Error {
@ -52,6 +54,7 @@ impl<'a> From<&'a EvmError> for Error {
EvmError::OutOfStack { .. } => Error::OutOfStack, EvmError::OutOfStack { .. } => Error::OutOfStack,
EvmError::BuiltIn { .. } => Error::BuiltIn, EvmError::BuiltIn { .. } => Error::BuiltIn,
EvmError::Internal(_) => Error::Internal, EvmError::Internal(_) => Error::Internal,
EvmError::MutableCallInStaticContext => Error::MutableCallInStaticContext,
} }
} }
} }
@ -73,6 +76,7 @@ impl fmt::Display for Error {
OutOfStack => "Out of stack", OutOfStack => "Out of stack",
BuiltIn => "Built-in failed", BuiltIn => "Built-in failed",
Internal => "Internal error", Internal => "Internal error",
MutableCallInStaticContext => "Mutable Call In Static Context",
}; };
message.fmt(f) message.fmt(f)
} }
@ -89,6 +93,7 @@ impl Encodable for Error {
OutOfStack => 4, OutOfStack => 4,
Internal => 5, Internal => 5,
BuiltIn => 6, BuiltIn => 6,
MutableCallInStaticContext => 7,
}; };
s.append_internal(&value); s.append_internal(&value);
@ -107,6 +112,7 @@ impl Decodable for Error {
4 => Ok(OutOfStack), 4 => Ok(OutOfStack),
5 => Ok(Internal), 5 => Ok(Internal),
6 => Ok(BuiltIn), 6 => Ok(BuiltIn),
7 => Ok(MutableCallInStaticContext),
_ => Err(DecoderError::Custom("Invalid error type")), _ => Err(DecoderError::Custom("Invalid error type")),
} }
} }

View File

@ -78,6 +78,9 @@ pub struct Params {
/// See `CommonParams` docs. /// See `CommonParams` docs.
#[serde(rename="eip211Transition")] #[serde(rename="eip211Transition")]
pub eip211_transition: Option<Uint>, pub eip211_transition: Option<Uint>,
/// See `CommonParams` docs.
#[serde(rename="eip214Transition")]
pub eip214_transition: Option<Uint>,
} }
#[cfg(test)] #[cfg(test)]

View File

@ -251,6 +251,9 @@ pub enum CallType {
/// Delegate call /// Delegate call
#[serde(rename="delegatecall")] #[serde(rename="delegatecall")]
DelegateCall, DelegateCall,
/// Static call
#[serde(rename="staticcall")]
StaticCall,
} }
impl From<executed::CallType> for CallType { impl From<executed::CallType> for CallType {
@ -260,6 +263,7 @@ impl From<executed::CallType> for CallType {
executed::CallType::Call => CallType::Call, executed::CallType::Call => CallType::Call,
executed::CallType::CallCode => CallType::CallCode, executed::CallType::CallCode => CallType::CallCode,
executed::CallType::DelegateCall => CallType::DelegateCall, executed::CallType::DelegateCall => CallType::DelegateCall,
executed::CallType::StaticCall => CallType::StaticCall,
} }
} }
} }