Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

EIP-116 (214), #4833 #4851

Merged
merged 1 commit into from
Jun 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ethcore/res/ethereum/frontier_like_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"homesteadTransition": "0x118c30",
"daoHardforkTransition": "0x1d4c00",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
"daoHardforkAccounts": [
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
Expand Down
2 changes: 1 addition & 1 deletion ethcore/res/ethereum/transition_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"homesteadTransition": "0x5",
"daoHardforkTransition": "0x8",
"daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754",
"daoHardforkAccounts": [
"daoHardforkAccounts": [
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425",
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
Expand Down
4 changes: 2 additions & 2 deletions ethcore/src/client/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub struct TestBlockChainClient {
/// Blocks.
pub blocks: RwLock<HashMap<H256, Bytes>>,
/// Mapping of numbers to hashes.
pub numbers: RwLock<HashMap<usize, H256>>,
pub numbers: RwLock<HashMap<usize, H256>>,
/// Genesis block hash.
pub genesis_hash: H256,
/// Last block hash.
Expand Down Expand Up @@ -353,7 +353,7 @@ pub fn get_temp_state_db() -> GuardedTempResult<StateDB> {

impl MiningBlockChainClient for TestBlockChainClient {
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 {
Expand Down
8 changes: 1 addition & 7 deletions ethcore/src/engines/authority_round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ use account_provider::AccountProvider;
use block::*;
use spec::CommonParams;
use engines::{Call, Engine, Seal, EngineError};
use header::{Header, BlockNumber};
use header::Header;
use error::{Error, TransactionError, BlockError};
use evm::Schedule;
use ethjson;
use io::{IoContext, IoHandler, TimerToken, IoService};
use builtin::Builtin;
Expand Down Expand Up @@ -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) {
// 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();
Expand Down
7 changes: 0 additions & 7 deletions ethcore/src/engines/instant_seal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ use util::{Address, HashMap};
use builtin::Builtin;
use engines::{Engine, Seal};
use spec::CommonParams;
use evm::Schedule;
use block::ExecutedBlock;
use header::BlockNumber;

/// An engine which does not provide any consensus mechanism, just seals blocks internally.
pub struct InstantSeal {
Expand Down Expand Up @@ -58,11 +56,6 @@ impl Engine for InstantSeal {
&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 generate_seal(&self, _block: &ExecutedBlock) -> Seal {
Expand Down
4 changes: 3 additions & 1 deletion ethcore/src/engines/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@ pub trait Engine : Sync + Send {
fn params(&self) -> &CommonParams;

/// 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.
/// (In principle these are just hints for the engine since that has the last word on them.)
Expand Down
6 changes: 0 additions & 6 deletions ethcore/src/engines/tendermint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ use account_provider::AccountProvider;
use block::*;
use spec::CommonParams;
use engines::{Engine, Seal, EngineError};
use evm::Schedule;
use state::CleanupMode;
use io::IoService;
use super::signer::EngineSigner;
Expand Down Expand Up @@ -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) {
// 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();
Expand Down
8 changes: 4 additions & 4 deletions ethcore/src/ethereum/ethash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,13 @@ impl Engine for Arc<Ethash> {
} else if block_number < self.ethash_params.eip150_transition {
Schedule::new_homestead()
} else {
Schedule::new_post_eip150(
let mut schedule = Schedule::new_post_eip150(
self.ethash_params.max_code_size as usize,
block_number >= self.ethash_params.eip160_transition,
block_number >= self.ethash_params.eip161abc_transition,
block_number >= self.ethash_params.eip161d_transition,
block_number >= self.params.eip86_transition
)
block_number >= self.ethash_params.eip161d_transition);
schedule.apply_params(block_number, self.params());
schedule
}
}

Expand Down
4 changes: 3 additions & 1 deletion ethcore/src/evm/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ pub enum Error {
},
/// Built-in contract failed on given input
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.
Internal(String),
}
Expand Down Expand Up @@ -90,6 +91,7 @@ impl fmt::Display for Error {
OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit),
BuiltIn(name) => write!(f, "Built-in failed: {}", name),
Internal(ref msg) => write!(f, "Internal error: {}", msg),
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
}
}
}
Expand Down
21 changes: 10 additions & 11 deletions ethcore/src/evm/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,24 @@ pub enum CreateContractAddress {
}

/// Externalities interface for EVMs
// TODO: [rob] associated error type instead of `trie::Result`. Not all EVMs are trie powered.
pub trait Ext {
/// 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.
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.
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).
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.
fn origin_balance(&self) -> trie::Result<U256>;
fn origin_balance(&self) -> evm::Result<U256>;

/// 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.
fn blockhash(&mut self, number: &U256) -> H256;
Expand Down Expand Up @@ -99,21 +98,21 @@ pub trait Ext {
) -> MessageCallResult;

/// 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
fn extcodesize(&self, address: &Address) -> trie::Result<usize>;
fn extcodesize(&self, address: &Address) -> evm::Result<usize>;

/// 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.
/// Returns gas_left if cost of returning the data is not too high.
fn ret(self, gas: &U256, data: &ReturnData) -> evm::Result<U256>;

/// Should be called when contract commits suicide.
/// 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.
fn schedule(&self) -> &Schedule;
Expand Down
3 changes: 3 additions & 0 deletions ethcore/src/evm/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ lazy_static! {
arr[CALLCODE as usize] = InstructionInfo::new("CALLCODE", 7, 1, GasPriceTier::Special);
arr[RETURN as usize] = InstructionInfo::new("RETURN", 2, 0, GasPriceTier::Zero);
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[CREATE2 as usize] = InstructionInfo::new("CREATE2", 3, 1, GasPriceTier::Special);
arr[REVERT as usize] = InstructionInfo::new("REVERT", 2, 0, GasPriceTier::Zero);
Expand Down Expand Up @@ -584,6 +585,8 @@ pub const DELEGATECALL: Instruction = 0xf4;
pub const CREATE2: Instruction = 0xfb;
/// stop execution and revert state changes. Return output data.
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
pub const SUICIDE: Instruction = 0xff;

2 changes: 1 addition & 1 deletion ethcore/src/evm/interpreter/gasometer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ impl<Gas: CostType> Gasometer<Gas> {

Request::GasMemProvide(gas, mem, Some(requested))
},
instructions::DELEGATECALL => {
instructions::DELEGATECALL | instructions::STATICCALL => {
let gas = Gas::from(schedule.call_gas);
let mem = cmp::max(
mem_needed(stack.peek(4), stack.peek(5))?,
Expand Down
9 changes: 6 additions & 3 deletions ethcore/src/evm/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ impl<Cost: CostType> Interpreter<Cost> {

if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
(instruction == instructions::CREATE2 && !schedule.have_create2) ||
(instruction == instructions::STATICCALL && !schedule.have_static_call) ||
(instruction == instructions::REVERT && !schedule.have_revert) {

return Err(evm::Error::BadInstruction {
Expand Down Expand Up @@ -312,14 +313,15 @@ impl<Cost: CostType> Interpreter<Cost> {
}
};
},
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => {
instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that gas calculation for staticcall is not implemented (I suppose it should be the same as for CALL)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for pointing that out!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo, it actually should be the same as DELEGATECALL, since we are not creating new accounts, nor transfering value

assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible");

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 code_address = stack.pop_back();
let code_address = u256_to_address(&code_address);

let value = if instruction == instructions::DELEGATECALL {
let value = if instruction == instructions::DELEGATECALL || instruction == instructions::STATICCALL {
None
} else {
Some(stack.pop_back())
Expand Down Expand Up @@ -347,6 +349,7 @@ impl<Cost: CostType> Interpreter<Cost> {
(&params.address, &params.address, has_balance, CallType::CallCode)
},
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))
};

Expand Down Expand Up @@ -405,7 +408,7 @@ impl<Cost: CostType> Interpreter<Cost> {
.iter()
.map(H256::from)
.collect();
ext.log(topics, self.mem.read_slice(offset, size));
ext.log(topics, self.mem.read_slice(offset, size))?;
},
instructions::PUSH1...instructions::PUSH32 => {
let bytes = instructions::get_push_bytes(instruction);
Expand Down
37 changes: 32 additions & 5 deletions ethcore/src/evm/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

//! Cost schedule and other parameterisations for the EVM.
use spec::CommonParams;

/// Definition of the cost schedule and other parameterisations for the EVM.
pub struct Schedule {
Expand Down Expand Up @@ -105,6 +106,8 @@ pub struct Schedule {
pub kill_empty: bool,
/// Blockhash instruction gas cost.
pub blockhash_gas: usize,
/// Static Call opcode enabled.
pub have_static_call: bool,
}

impl Schedule {
Expand All @@ -119,12 +122,12 @@ impl Schedule {
}

/// 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 {
exceptional_failed_code_deposit: true,
have_delegate_call: true,
have_create2: have_metropolis_instructions,
have_revert: have_metropolis_instructions,
have_create2: false,
have_revert: false,
stack_limit: 1024,
max_depth: 1024,
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
Expand Down Expand Up @@ -163,13 +166,36 @@ impl Schedule {
sub_gas_cap_divisor: Some(64),
no_empty: no_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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, this is better than have_metropolis_instructions

if block_number >= params.eip210_transition {
self.blockhash_gas = 350;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, added to #5855

}
}

/// Schedule for the Metropolis of the Ethereum main net.
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 {
Expand Down Expand Up @@ -217,6 +243,7 @@ impl Schedule {
no_empty: false,
kill_empty: false,
blockhash_gas: 20,
have_static_call: false,
}
}
}
Expand Down
Loading