EIP-86 fixes (#5506)
This commit is contained in:
parent
8b9adb4d74
commit
ed7c366b90
@ -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 {
|
||||||
|
@ -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 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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))?;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(¶ms.address)? {
|
if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(¶ms.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(¶ms.address)?;
|
let prev_bal = self.state.balance(¶ms.address)?;
|
||||||
if let ActionValue::Transfer(val) = params.value {
|
if let ActionValue::Transfer(val) = params.value {
|
||||||
|
@ -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(),
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user