EIP-86 fixes (#5506)
This commit is contained in:
parent
8b9adb4d74
commit
ed7c366b90
@ -1354,8 +1354,7 @@ impl BlockChainClient for Client {
|
||||
.collect();
|
||||
match (transaction, previous_receipts) {
|
||||
(Some(transaction), Some(previous_receipts)) => {
|
||||
let schedule = self.engine().schedule(block_number);
|
||||
Some(transaction_receipt(&schedule, transaction, previous_receipts))
|
||||
Some(transaction_receipt(self.engine(), transaction, previous_receipts))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
@ -1748,7 +1747,7 @@ impl Drop for Client {
|
||||
|
||||
/// Returns `LocalizedReceipt` given `LocalizedTransaction`
|
||||
/// 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.");
|
||||
|
||||
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,
|
||||
contract_address: match tx.action {
|
||||
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 {
|
||||
entry: log,
|
||||
@ -1827,17 +1826,17 @@ mod tests {
|
||||
#[test]
|
||||
fn should_return_correct_log_index() {
|
||||
use super::transaction_receipt;
|
||||
use evm::schedule::Schedule;
|
||||
use ethkey::KeyPair;
|
||||
use log_entry::{LogEntry, LocalizedLogEntry};
|
||||
use receipt::{Receipt, LocalizedReceipt};
|
||||
use transaction::{Transaction, LocalizedTransaction, Action};
|
||||
use util::Hashable;
|
||||
use tests::helpers::TestEngine;
|
||||
|
||||
// given
|
||||
let key = KeyPair::from_secret_slice(&"test".sha3()).unwrap();
|
||||
let secret = key.secret();
|
||||
let schedule = Schedule::new_homestead();
|
||||
let engine = TestEngine::new(0);
|
||||
|
||||
let block_number = 1;
|
||||
let block_hash = 5.into();
|
||||
@ -1881,7 +1880,7 @@ mod tests {
|
||||
}];
|
||||
|
||||
// when
|
||||
let receipt = transaction_receipt(&schedule, transaction, receipts);
|
||||
let receipt = transaction_receipt(&engine, transaction, receipts);
|
||||
|
||||
// then
|
||||
assert_eq!(receipt, LocalizedReceipt {
|
||||
|
@ -48,6 +48,7 @@ use receipt::Receipt;
|
||||
use snapshot::SnapshotComponents;
|
||||
use spec::CommonParams;
|
||||
use transaction::{UnverifiedTransaction, SignedTransaction};
|
||||
use evm::CreateContractAddress;
|
||||
|
||||
use ethkey::Signature;
|
||||
use util::*;
|
||||
@ -294,4 +295,9 @@ pub trait Engine : Sync + Send {
|
||||
fn snapshot_components(&self) -> Option<Box<SnapshotComponents>> {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ lazy_static! {
|
||||
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[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
|
||||
};
|
||||
}
|
||||
@ -555,7 +555,7 @@ pub const RETURN: Instruction = 0xf3;
|
||||
/// like CALLCODE but keeps caller's value and sender
|
||||
pub const DELEGATECALL: Instruction = 0xf4;
|
||||
/// 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
|
||||
pub const SUICIDE: Instruction = 0xff;
|
||||
|
||||
|
@ -223,7 +223,7 @@ impl<Gas: CostType> Gasometer<Gas> {
|
||||
|
||||
Request::GasMemProvide(gas, mem, Some(requested))
|
||||
},
|
||||
instructions::CREATE | instructions::CREATE_P2SH => {
|
||||
instructions::CREATE | instructions::CREATE2 => {
|
||||
let gas = Gas::from(schedule.create_gas);
|
||||
let mem = mem_needed(stack.peek(1), stack.peek(2))?;
|
||||
|
||||
|
@ -183,7 +183,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
let schedule = ext.schedule();
|
||||
|
||||
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 {
|
||||
instruction: instruction
|
||||
@ -268,12 +268,12 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
instructions::JUMPDEST => {
|
||||
// ignore
|
||||
},
|
||||
instructions::CREATE | instructions::CREATE_P2SH => {
|
||||
instructions::CREATE | instructions::CREATE2 => {
|
||||
let endowment = stack.pop_back();
|
||||
let init_off = 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 contract_code = self.mem.read_slice(init_off, init_size);
|
||||
|
@ -15,7 +15,6 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Cost schedule and other parameterisations for the EVM.
|
||||
use evm::CreateContractAddress;
|
||||
|
||||
/// Definition of the cost schedule and other parameterisations for the EVM.
|
||||
pub struct Schedule {
|
||||
@ -24,7 +23,7 @@ pub struct Schedule {
|
||||
/// Does it have a delegate cal
|
||||
pub have_delegate_call: bool,
|
||||
/// Does it have a CREATE_P2SH instruction
|
||||
pub have_create_p2sh: bool,
|
||||
pub have_create2: bool,
|
||||
/// VM stack limit
|
||||
pub stack_limit: usize,
|
||||
/// Max number of nested calls/creates
|
||||
@ -102,8 +101,6 @@ pub struct Schedule {
|
||||
pub no_empty: bool,
|
||||
/// Kill empty accounts if touched.
|
||||
pub kill_empty: bool,
|
||||
/// Contract address generation scheme
|
||||
pub create_address: CreateContractAddress,
|
||||
}
|
||||
|
||||
impl Schedule {
|
||||
@ -118,11 +115,11 @@ 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_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 {
|
||||
exceptional_failed_code_deposit: true,
|
||||
have_delegate_call: true,
|
||||
have_create_p2sh: have_create_p2sh,
|
||||
have_create2: have_metropolis_instructions,
|
||||
stack_limit: 1024,
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
@ -161,7 +158,6 @@ impl Schedule {
|
||||
sub_gas_cap_divisor: Some(64),
|
||||
no_empty: no_empty,
|
||||
kill_empty: kill_empty,
|
||||
create_address: if have_create_p2sh { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce },
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +170,7 @@ impl Schedule {
|
||||
Schedule {
|
||||
exceptional_failed_code_deposit: efcd,
|
||||
have_delegate_call: hdc,
|
||||
have_create_p2sh: false,
|
||||
have_create2: false,
|
||||
stack_limit: 1024,
|
||||
max_depth: 1024,
|
||||
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
|
||||
@ -213,7 +209,6 @@ impl Schedule {
|
||||
sub_gas_cap_divisor: None,
|
||||
no_empty: false,
|
||||
kill_empty: false,
|
||||
create_address: CreateContractAddress::FromSenderAndNonce,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
let (gas_left, output) = match t.action {
|
||||
Action::Create => {
|
||||
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 {
|
||||
code_address: new_address.clone(),
|
||||
code_hash: code_hash,
|
||||
@ -386,8 +386,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
vm_tracer: &mut V,
|
||||
) -> evm::Result<U256> where T: Tracer, V: VMTracer {
|
||||
|
||||
let schedule = self.engine.schedule(self.info.number);
|
||||
if schedule.create_address != CreateContractAddress::FromSenderAndNonce && self.state.exists(¶ms.address)? {
|
||||
let scheme = self.engine.create_address_scheme(self.info.number);
|
||||
if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(¶ms.address)? {
|
||||
return Err(evm::Error::OutOfGas);
|
||||
}
|
||||
|
||||
@ -398,6 +398,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
let mut unconfirmed_substate = Substate::new();
|
||||
|
||||
// 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 prev_bal = self.state.balance(¶ms.address)?;
|
||||
if let ActionValue::Transfer(val) = params.value {
|
||||
|
@ -1048,7 +1048,7 @@ impl MinerService for Miner {
|
||||
Action::Call(_) => None,
|
||||
Action::Create => {
|
||||
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(),
|
||||
|
@ -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()))
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
pub fn balance(&self, a: &Address) -> trie::Result<U256> {
|
||||
self.ensure_cached(a, RequireCache::None, true,
|
||||
|
Loading…
Reference in New Issue
Block a user