EIP-86 fixes (#5506)

This commit is contained in:
Arkadiy Paronyan 2017-05-05 16:00:40 +02:00 committed by Gav Wood
parent 8b9adb4d74
commit ed7c366b90
9 changed files with 32 additions and 26 deletions

View File

@ -1354,8 +1354,7 @@ impl BlockChainClient for Client {
.collect(); .collect();
match (transaction, previous_receipts) { match (transaction, previous_receipts) {
(Some(transaction), Some(previous_receipts)) => { (Some(transaction), Some(previous_receipts)) => {
let schedule = self.engine().schedule(block_number); Some(transaction_receipt(self.engine(), transaction, previous_receipts))
Some(transaction_receipt(&schedule, transaction, previous_receipts))
}, },
_ => None, _ => None,
} }
@ -1748,7 +1747,7 @@ impl Drop for Client {
/// Returns `LocalizedReceipt` given `LocalizedTransaction` /// Returns `LocalizedReceipt` given `LocalizedTransaction`
/// and a vector of receipts from given block up to transaction index. /// and a vector of receipts from given block up to transaction index.
fn transaction_receipt(schedule: &Schedule, mut tx: LocalizedTransaction, mut receipts: Vec<Receipt>) -> LocalizedReceipt { fn transaction_receipt(engine: &Engine, mut tx: LocalizedTransaction, mut receipts: Vec<Receipt>) -> LocalizedReceipt {
assert_eq!(receipts.len(), tx.transaction_index + 1, "All previous receipts are provided."); assert_eq!(receipts.len(), tx.transaction_index + 1, "All previous receipts are provided.");
let sender = tx.sender(); let sender = tx.sender();
@ -1772,7 +1771,7 @@ fn transaction_receipt(schedule: &Schedule, mut tx: LocalizedTransaction, mut re
gas_used: receipt.gas_used - prior_gas_used, gas_used: receipt.gas_used - prior_gas_used,
contract_address: match tx.action { contract_address: match tx.action {
Action::Call(_) => None, Action::Call(_) => None,
Action::Create => Some(contract_address(schedule.create_address, &sender, &tx.nonce, &tx.data.sha3())) Action::Create => Some(contract_address(engine.create_address_scheme(block_number), &sender, &tx.nonce, &tx.data.sha3()))
}, },
logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry { logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry {
entry: log, entry: log,
@ -1827,17 +1826,17 @@ mod tests {
#[test] #[test]
fn should_return_correct_log_index() { fn should_return_correct_log_index() {
use super::transaction_receipt; use super::transaction_receipt;
use evm::schedule::Schedule;
use ethkey::KeyPair; use ethkey::KeyPair;
use log_entry::{LogEntry, LocalizedLogEntry}; use log_entry::{LogEntry, LocalizedLogEntry};
use receipt::{Receipt, LocalizedReceipt}; use receipt::{Receipt, LocalizedReceipt};
use transaction::{Transaction, LocalizedTransaction, Action}; use transaction::{Transaction, LocalizedTransaction, Action};
use util::Hashable; use util::Hashable;
use tests::helpers::TestEngine;
// given // given
let key = KeyPair::from_secret_slice(&"test".sha3()).unwrap(); let key = KeyPair::from_secret_slice(&"test".sha3()).unwrap();
let secret = key.secret(); let secret = key.secret();
let schedule = Schedule::new_homestead(); let engine = TestEngine::new(0);
let block_number = 1; let block_number = 1;
let block_hash = 5.into(); let block_hash = 5.into();
@ -1881,7 +1880,7 @@ mod tests {
}]; }];
// when // when
let receipt = transaction_receipt(&schedule, transaction, receipts); let receipt = transaction_receipt(&engine, transaction, receipts);
// then // then
assert_eq!(receipt, LocalizedReceipt { assert_eq!(receipt, LocalizedReceipt {

View File

@ -48,6 +48,7 @@ use receipt::Receipt;
use snapshot::SnapshotComponents; use snapshot::SnapshotComponents;
use spec::CommonParams; use spec::CommonParams;
use transaction::{UnverifiedTransaction, SignedTransaction}; use transaction::{UnverifiedTransaction, SignedTransaction};
use evm::CreateContractAddress;
use ethkey::Signature; use ethkey::Signature;
use util::*; use util::*;
@ -294,4 +295,9 @@ pub trait Engine : Sync + Send {
fn snapshot_components(&self) -> Option<Box<SnapshotComponents>> { fn snapshot_components(&self) -> Option<Box<SnapshotComponents>> {
None None
} }
/// Returns new contract address generation scheme at given block number.
fn create_address_scheme(&self, number: BlockNumber) -> CreateContractAddress {
if number >= self.params().eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce }
}
} }

View File

@ -278,7 +278,7 @@ lazy_static! {
arr[RETURN as usize] = InstructionInfo::new("RETURN", 0, 2, 0, true, GasPriceTier::Zero); arr[RETURN as usize] = InstructionInfo::new("RETURN", 0, 2, 0, true, GasPriceTier::Zero);
arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special); arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special);
arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 0, 1, 0, true, GasPriceTier::Special); arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 0, 1, 0, true, GasPriceTier::Special);
arr[CREATE_P2SH as usize] = InstructionInfo::new("CREATE_P2SH", 0, 3, 1, true, GasPriceTier::Special); arr[CREATE2 as usize] = InstructionInfo::new("CREATE2", 0, 3, 1, true, GasPriceTier::Special);
arr arr
}; };
} }
@ -555,7 +555,7 @@ pub const RETURN: Instruction = 0xf3;
/// like CALLCODE but keeps caller's value and sender /// like CALLCODE but keeps caller's value and sender
pub const DELEGATECALL: Instruction = 0xf4; pub const DELEGATECALL: Instruction = 0xf4;
/// create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160 /// create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160
pub const CREATE_P2SH: Instruction = 0xfb; pub const CREATE2: Instruction = 0xfb;
/// 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

@ -223,7 +223,7 @@ impl<Gas: CostType> Gasometer<Gas> {
Request::GasMemProvide(gas, mem, Some(requested)) Request::GasMemProvide(gas, mem, Some(requested))
}, },
instructions::CREATE | instructions::CREATE_P2SH => { instructions::CREATE | instructions::CREATE2 => {
let gas = Gas::from(schedule.create_gas); let gas = Gas::from(schedule.create_gas);
let mem = mem_needed(stack.peek(1), stack.peek(2))?; let mem = mem_needed(stack.peek(1), stack.peek(2))?;

View File

@ -183,7 +183,7 @@ impl<Cost: CostType> Interpreter<Cost> {
let schedule = ext.schedule(); let schedule = ext.schedule();
if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) || if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
(instruction == instructions::CREATE_P2SH && !schedule.have_create_p2sh) { (instruction == instructions::CREATE2 && !schedule.have_create2) {
return Err(evm::Error::BadInstruction { return Err(evm::Error::BadInstruction {
instruction: instruction instruction: instruction
@ -268,12 +268,12 @@ impl<Cost: CostType> Interpreter<Cost> {
instructions::JUMPDEST => { instructions::JUMPDEST => {
// ignore // ignore
}, },
instructions::CREATE | instructions::CREATE_P2SH => { instructions::CREATE | instructions::CREATE2 => {
let endowment = stack.pop_back(); let endowment = stack.pop_back();
let init_off = stack.pop_back(); let init_off = stack.pop_back();
let init_size = stack.pop_back(); let init_size = stack.pop_back();
let address_scheme = if instruction == instructions::CREATE { ext.schedule().create_address } else { CreateContractAddress::FromSenderAndCodeHash }; let address_scheme = if instruction == instructions::CREATE { CreateContractAddress::FromSenderAndNonce } else { CreateContractAddress::FromSenderAndCodeHash };
let create_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 `CREATE`; qed"); let create_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 `CREATE`; qed");
let contract_code = self.mem.read_slice(init_off, init_size); let contract_code = self.mem.read_slice(init_off, init_size);

View File

@ -15,7 +15,6 @@
// 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 evm::CreateContractAddress;
/// 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 {
@ -24,7 +23,7 @@ pub struct Schedule {
/// Does it have a delegate cal /// Does it have a delegate cal
pub have_delegate_call: bool, pub have_delegate_call: bool,
/// Does it have a CREATE_P2SH instruction /// Does it have a CREATE_P2SH instruction
pub have_create_p2sh: bool, pub have_create2: bool,
/// VM stack limit /// VM stack limit
pub stack_limit: usize, pub stack_limit: usize,
/// Max number of nested calls/creates /// Max number of nested calls/creates
@ -102,8 +101,6 @@ pub struct Schedule {
pub no_empty: bool, pub no_empty: bool,
/// Kill empty accounts if touched. /// Kill empty accounts if touched.
pub kill_empty: bool, pub kill_empty: bool,
/// Contract address generation scheme
pub create_address: CreateContractAddress,
} }
impl Schedule { impl Schedule {
@ -118,11 +115,11 @@ 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_create_p2sh: bool) -> Schedule { pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool, have_metropolis_instructions: bool) -> Schedule {
Schedule { Schedule {
exceptional_failed_code_deposit: true, exceptional_failed_code_deposit: true,
have_delegate_call: true, have_delegate_call: true,
have_create_p2sh: have_create_p2sh, have_create2: have_metropolis_instructions,
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],
@ -161,7 +158,6 @@ 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,
create_address: if have_create_p2sh { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce },
} }
} }
@ -174,7 +170,7 @@ impl Schedule {
Schedule { Schedule {
exceptional_failed_code_deposit: efcd, exceptional_failed_code_deposit: efcd,
have_delegate_call: hdc, have_delegate_call: hdc,
have_create_p2sh: false, have_create2: 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],
@ -213,7 +209,6 @@ impl Schedule {
sub_gas_cap_divisor: None, sub_gas_cap_divisor: None,
no_empty: false, no_empty: false,
kill_empty: false, kill_empty: false,
create_address: CreateContractAddress::FromSenderAndNonce,
} }
} }
} }

View File

@ -185,7 +185,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
let (gas_left, output) = match t.action { let (gas_left, output) = match t.action {
Action::Create => { Action::Create => {
let code_hash = t.data.sha3(); let code_hash = t.data.sha3();
let new_address = contract_address(schedule.create_address, &sender, &nonce, &code_hash); let new_address = contract_address(self.engine.create_address_scheme(self.info.number), &sender, &nonce, &code_hash);
let params = ActionParams { let params = ActionParams {
code_address: new_address.clone(), code_address: new_address.clone(),
code_hash: code_hash, code_hash: code_hash,
@ -386,8 +386,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
vm_tracer: &mut V, vm_tracer: &mut V,
) -> evm::Result<U256> where T: Tracer, V: VMTracer { ) -> evm::Result<U256> where T: Tracer, V: VMTracer {
let schedule = self.engine.schedule(self.info.number); let scheme = self.engine.create_address_scheme(self.info.number);
if schedule.create_address != CreateContractAddress::FromSenderAndNonce && self.state.exists(&params.address)? { if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(&params.address)? {
return Err(evm::Error::OutOfGas); return Err(evm::Error::OutOfGas);
} }
@ -398,6 +398,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
let mut unconfirmed_substate = Substate::new(); let mut unconfirmed_substate = Substate::new();
// create contract and transfer value to it if necessary // create contract and transfer value to it if necessary
let schedule = self.engine.schedule(self.info.number);
let nonce_offset = if schedule.no_empty {1} else {0}.into(); let nonce_offset = if schedule.no_empty {1} else {0}.into();
let prev_bal = self.state.balance(&params.address)?; let prev_bal = self.state.balance(&params.address)?;
if let ActionValue::Transfer(val) = params.value { if let ActionValue::Transfer(val) = params.value {

View File

@ -1048,7 +1048,7 @@ impl MinerService for Miner {
Action::Call(_) => None, Action::Call(_) => None,
Action::Create => { Action::Create => {
let sender = tx.sender(); let sender = tx.sender();
Some(contract_address(self.engine.schedule(pending.header().number()).create_address, &sender, &tx.nonce, &tx.data.sha3())) Some(contract_address(self.engine.create_address_scheme(pending.header().number()), &sender, &tx.nonce, &tx.data.sha3()))
} }
}, },
logs: receipt.logs.clone(), logs: receipt.logs.clone(),

View File

@ -433,6 +433,11 @@ impl<B: Backend> State<B> {
self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null())) 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)))
}
/// Get the balance of account `a`. /// Get the balance of account `a`.
pub fn balance(&self, a: &Address) -> trie::Result<U256> { pub fn balance(&self, a: &Address) -> trie::Result<U256> {
self.ensure_cached(a, RequireCache::None, true, self.ensure_cached(a, RequireCache::None, true,