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

Commit

Permalink
Comply EIP-86 with the new definition (#9140)
Browse files Browse the repository at this point in the history
* Comply EIP-86 with the new CREATE2 opcode

* Fix rpc compile

* Fix interpreter CREATE/CREATE2 stack pop difference

* Add unreachable! to fix compile

* Fix instruction_info

* Fix gas check due to new stack item

* Add new tests in executive

* Fix have_create2 comment

* Remove all unused references of eip86_transition and block_number
  • Loading branch information
sorpaas authored and debris committed Aug 1, 2018
1 parent f0c0da8 commit 637883f
Show file tree
Hide file tree
Showing 17 changed files with 96 additions and 73 deletions.
2 changes: 1 addition & 1 deletion ethcore/evm/src/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ lazy_static! {
arr[DELEGATECALL as usize] = Some(InstructionInfo::new("DELEGATECALL", 6, 1, GasPriceTier::Special));
arr[STATICCALL as usize] = Some(InstructionInfo::new("STATICCALL", 6, 1, GasPriceTier::Special));
arr[SUICIDE as usize] = Some(InstructionInfo::new("SUICIDE", 1, 0, GasPriceTier::Special));
arr[CREATE2 as usize] = Some(InstructionInfo::new("CREATE2", 3, 1, GasPriceTier::Special));
arr[CREATE2 as usize] = Some(InstructionInfo::new("CREATE2", 4, 1, GasPriceTier::Special));
arr[REVERT as usize] = Some(InstructionInfo::new("REVERT", 2, 0, GasPriceTier::Zero));
arr
};
Expand Down
6 changes: 5 additions & 1 deletion ethcore/evm/src/interpreter/gasometer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,11 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
},
instructions::CREATE | instructions::CREATE2 => {
let gas = Gas::from(schedule.create_gas);
let mem = mem_needed(stack.peek(1), stack.peek(2))?;
let mem = match instruction {
instructions::CREATE => mem_needed(stack.peek(1), stack.peek(2))?,
instructions::CREATE2 => mem_needed(stack.peek(2), stack.peek(3))?,
_ => unreachable!("instruction can only be CREATE/CREATE2 checked above; qed"),
};

Request::GasMemProvide(gas, mem, None)
},
Expand Down
6 changes: 5 additions & 1 deletion ethcore/evm/src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,11 @@ impl<Cost: CostType> Interpreter<Cost> {
},
instructions::CREATE | instructions::CREATE2 => {
let endowment = stack.pop_back();
let address_scheme = match instruction {
instructions::CREATE => CreateContractAddress::FromSenderAndNonce,
instructions::CREATE2 => CreateContractAddress::FromSenderSaltAndCodeHash(stack.pop_back().into()),
_ => unreachable!("instruction can only be CREATE/CREATE2 checked above; qed"),
};
let init_off = stack.pop_back();
let init_size = stack.pop_back();

Expand All @@ -336,7 +341,6 @@ impl<Cost: CostType> Interpreter<Cost> {
}

let contract_code = self.mem.read_slice(init_off, init_size);
let address_scheme = if instruction == instructions::CREATE { CreateContractAddress::FromSenderAndNonce } else { CreateContractAddress::FromSenderAndCodeHash };

let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code, address_scheme);
return match create_result {
Expand Down
8 changes: 5 additions & 3 deletions ethcore/src/executive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address,
stream.append(nonce);
(From::from(keccak(stream.as_raw())), None)
},
CreateContractAddress::FromCodeHash => {
CreateContractAddress::FromSenderSaltAndCodeHash(salt) => {
let code_hash = keccak(code);
let mut buffer = [0xffu8; 20 + 32];
&mut buffer[20..].copy_from_slice(&code_hash[..]);
let mut buffer = [0u8; 20 + 32 + 32];
&mut buffer[0..20].copy_from_slice(&sender[..]);
&mut buffer[20..(20+32)].copy_from_slice(&salt[..]);
&mut buffer[(20+32)..].copy_from_slice(&code_hash[..]);
(From::from(keccak(&buffer[..])), Some(code_hash))
},
CreateContractAddress::FromSenderAndCodeHash => {
Expand Down
40 changes: 40 additions & 0 deletions ethcore/src/externalities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,4 +581,44 @@ mod tests {

assert_eq!(setup.sub_state.suicides.len(), 1);
}

#[test]
fn can_create() {
use std::str::FromStr;

let mut setup = TestSetup::new();
let state = &mut setup.state;
let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer;

let address = {
let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
match ext.create(&U256::max_value(), &U256::zero(), &[], CreateContractAddress::FromSenderAndNonce) {
ContractCreateResult::Created(address, _) => address,
_ => panic!("Test create failed; expected Created, got Failed/Reverted."),
}
};

assert_eq!(address, Address::from_str("bd770416a3345f91e4b34576cb804a576fa48eb1").unwrap());
}

#[test]
fn can_create2() {
use std::str::FromStr;

let mut setup = TestSetup::new();
let state = &mut setup.state;
let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer;

let address = {
let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
match ext.create(&U256::max_value(), &U256::zero(), &[], CreateContractAddress::FromSenderSaltAndCodeHash(H256::default())) {
ContractCreateResult::Created(address, _) => address,
_ => panic!("Test create failed; expected Created, got Failed/Reverted."),
}
};

assert_eq!(address, Address::from_str("b7c227636666831278bacdb8d7f52933b8698ab9").unwrap());
}
}
8 changes: 2 additions & 6 deletions ethcore/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,12 +310,8 @@ impl EthereumMachine {
}

/// Returns new contract address generation scheme at given block number.
pub fn create_address_scheme(&self, number: BlockNumber) -> CreateContractAddress {
if number >= self.params().eip86_transition {
CreateContractAddress::FromCodeHash
} else {
CreateContractAddress::FromSenderAndNonce
}
pub fn create_address_scheme(&self, _number: BlockNumber) -> CreateContractAddress {
CreateContractAddress::FromSenderAndNonce
}

/// Verify a particular transaction is valid, regardless of order.
Expand Down
8 changes: 4 additions & 4 deletions ethcore/vm/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ pub enum MessageCallResult {
/// Specifies how an address is calculated for a new contract.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum CreateContractAddress {
/// Address is calculated from nonce and sender. Pre EIP-86 (Metropolis)
/// Address is calculated from sender and nonce. Pre EIP-86 (Metropolis)
FromSenderAndNonce,
/// Address is calculated from code hash. Default since EIP-86
FromCodeHash,
/// Address is calculated from code hash and sender. Used by CREATE_P2SH instruction.
/// Address is calculated from sender, salt and code hash. EIP-86 CREATE2 scheme.
FromSenderSaltAndCodeHash(H256),
/// Address is calculated from code hash and sender. Used by pwasm create ext.
FromSenderAndCodeHash,
}

Expand Down
2 changes: 1 addition & 1 deletion ethcore/vm/src/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct Schedule {
pub exceptional_failed_code_deposit: bool,
/// Does it have a delegate cal
pub have_delegate_call: bool,
/// Does it have a CREATE_P2SH instruction
/// Does it have a CREATE2 instruction
pub have_create2: bool,
/// Does it have a REVERT instruction
pub have_revert: bool,
Expand Down
6 changes: 2 additions & 4 deletions rpc/src/v1/helpers/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,7 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
}

fn enrich(&self, signed_transaction: SignedTransaction) -> RpcRichRawTransaction {
let block_number = self.client.best_block_header().number();
RpcRichRawTransaction::from_signed(signed_transaction, block_number, self.client.eip86_transition())
RpcRichRawTransaction::from_signed(signed_transaction)
}

fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256> {
Expand Down Expand Up @@ -405,8 +404,7 @@ impl Dispatcher for LightDispatcher {
}

fn enrich(&self, signed_transaction: SignedTransaction) -> RpcRichRawTransaction {
let block_number = self.client.best_block_header().number();
RpcRichRawTransaction::from_signed(signed_transaction, block_number, self.client.eip86_transition())
RpcRichRawTransaction::from_signed(signed_transaction)
}

fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256> {
Expand Down
8 changes: 4 additions & 4 deletions rpc/src/v1/helpers/light_fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub struct LightFetch {
}

/// Extract a transaction at given index.
pub fn extract_transaction_at_index(block: encoded::Block, index: usize, eip86_transition: u64) -> Option<Transaction> {
pub fn extract_transaction_at_index(block: encoded::Block, index: usize) -> Option<Transaction> {
block.transactions().into_iter().nth(index)
// Verify if transaction signature is correct.
.and_then(|tx| SignedTransaction::new(tx).ok())
Expand All @@ -85,7 +85,7 @@ pub fn extract_transaction_at_index(block: encoded::Block, index: usize, eip86_t
cached_sender,
}
})
.map(|tx| Transaction::from_localized(tx, eip86_transition))
.map(|tx| Transaction::from_localized(tx))
}

// extract the header indicated by the given `HeaderRef` from the given responses.
Expand Down Expand Up @@ -365,7 +365,7 @@ impl LightFetch {

// Get a transaction by hash. also returns the index in the block.
// Only returns transactions in the canonical chain.
pub fn transaction_by_hash(&self, tx_hash: H256, eip86_transition: u64)
pub fn transaction_by_hash(&self, tx_hash: H256)
-> impl Future<Item = Option<(Transaction, usize)>, Error = Error> + Send
{
let params = (self.sync.clone(), self.on_demand.clone());
Expand Down Expand Up @@ -397,7 +397,7 @@ impl LightFetch {
}

let index = index.index as usize;
let transaction = extract_transaction_at_index(blk, index, eip86_transition);
let transaction = extract_transaction_at_index(blk, index);

if transaction.as_ref().map_or(true, |tx| tx.hash != tx_hash.into()) {
// index is actively wrong: indicated block has
Expand Down
11 changes: 4 additions & 7 deletions rpc/src/v1/impls/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ pub struct EthClient<C, SN: ?Sized, S: ?Sized, M, EM> where
external_miner: Arc<EM>,
seed_compute: Mutex<SeedHashCompute>,
options: EthClientOptions,
eip86_transition: u64,
}

#[derive(Debug)]
Expand Down Expand Up @@ -169,7 +168,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S
external_miner: em.clone(),
seed_compute: Mutex::new(SeedHashCompute::default()),
options: options,
eip86_transition: client.eip86_transition(),
}
}

Expand Down Expand Up @@ -254,7 +252,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S
seal_fields: view.seal().into_iter().map(Into::into).collect(),
uncles: block.uncle_hashes().into_iter().map(Into::into).collect(),
transactions: match include_txs {
true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(|t| Transaction::from_localized(t, self.eip86_transition)).collect()),
true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(|t| Transaction::from_localized(t)).collect()),
false => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()),
},
extra_data: Bytes::new(view.extra_data()),
Expand All @@ -268,7 +266,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S

fn transaction(&self, id: PendingTransactionId) -> Result<Option<Transaction>> {
let client_transaction = |id| match self.client.transaction(id) {
Some(t) => Ok(Some(Transaction::from_localized(t, self.eip86_transition))),
Some(t) => Ok(Some(Transaction::from_localized(t))),
None => Ok(None),
};

Expand Down Expand Up @@ -305,7 +303,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S
cached_sender,
}
})
.map(|tx| Transaction::from_localized(tx, self.eip86_transition));
.map(|tx| Transaction::from_localized(tx));

Ok(transaction)
}
Expand Down Expand Up @@ -658,10 +656,9 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<

fn transaction_by_hash(&self, hash: RpcH256) -> BoxFuture<Option<Transaction>> {
let hash: H256 = hash.into();
let block_number = self.client.chain_info().best_block_number;
let tx = try_bf!(self.transaction(PendingTransactionId::Hash(hash))).or_else(|| {
self.miner.transaction(&hash)
.map(|t| Transaction::from_pending(t.pending().clone(), block_number + 1, self.eip86_transition))
.map(|t| Transaction::from_pending(t.pending().clone()))
});

Box::new(future::ok(tx))
Expand Down
17 changes: 5 additions & 12 deletions rpc/src/v1/impls/light/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ impl<T: LightChainClient + 'static> EthClient<T> {
fn rich_block(&self, id: BlockId, include_txs: bool) -> BoxFuture<RichBlock> {
let (on_demand, sync) = (self.on_demand.clone(), self.sync.clone());
let (client, engine) = (self.client.clone(), self.client.engine().clone());
let eip86_transition = self.client.eip86_transition();

// helper for filling out a rich block once we've got a block and a score.
let fill_rich = move |block: encoded::Block, score: Option<U256>| {
Expand All @@ -169,7 +168,7 @@ impl<T: LightChainClient + 'static> EthClient<T> {
seal_fields: header.seal().into_iter().cloned().map(Into::into).collect(),
uncles: block.uncle_hashes().into_iter().map(Into::into).collect(),
transactions: match include_txs {
true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(|t| Transaction::from_localized(t, eip86_transition)).collect()),
true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(|t| Transaction::from_localized(t)).collect()),
_ => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()),
},
extra_data: Bytes::new(header.extra_data().clone()),
Expand Down Expand Up @@ -419,40 +418,34 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {

fn transaction_by_hash(&self, hash: RpcH256) -> BoxFuture<Option<Transaction>> {
let hash = hash.into();
let eip86 = self.client.eip86_transition();

{
let tx_queue = self.transaction_queue.read();
if let Some(tx) = tx_queue.get(&hash) {
return Box::new(future::ok(Some(Transaction::from_pending(
tx.clone(),
self.client.chain_info().best_block_number,
eip86,
))));
}
}

Box::new(self.fetcher().transaction_by_hash(hash, eip86).map(|x| x.map(|(tx, _)| tx)))
Box::new(self.fetcher().transaction_by_hash(hash).map(|x| x.map(|(tx, _)| tx)))
}

fn transaction_by_block_hash_and_index(&self, hash: RpcH256, idx: Index) -> BoxFuture<Option<Transaction>> {
let eip86 = self.client.eip86_transition();
Box::new(self.fetcher().block(BlockId::Hash(hash.into())).map(move |block| {
light_fetch::extract_transaction_at_index(block, idx.value(), eip86)
light_fetch::extract_transaction_at_index(block, idx.value())
}))
}

fn transaction_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture<Option<Transaction>> {
let eip86 = self.client.eip86_transition();
Box::new(self.fetcher().block(Self::num_to_id(num)).map(move |block| {
light_fetch::extract_transaction_at_index(block, idx.value(), eip86)
light_fetch::extract_transaction_at_index(block, idx.value())
}))
}

fn transaction_receipt(&self, hash: RpcH256) -> BoxFuture<Option<Receipt>> {
let eip86 = self.client.eip86_transition();
let fetcher = self.fetcher();
Box::new(fetcher.transaction_by_hash(hash.clone().into(), eip86).and_then(move |tx| {
Box::new(fetcher.transaction_by_hash(hash.clone().into()).and_then(move |tx| {
// the block hash included in the transaction object here has
// already been checked for canonicality and whether it contains
// the transaction.
Expand Down
8 changes: 3 additions & 5 deletions rpc/src/v1/impls/light/parity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ pub struct ParityClient {
settings: Arc<NetworkSettings>,
signer: Option<Arc<SignerService>>,
ws_address: Option<Host>,
eip86_transition: u64,
gas_price_percentile: usize,
}

Expand All @@ -80,7 +79,6 @@ impl ParityClient {
settings,
signer,
ws_address,
eip86_transition: client.eip86_transition(),
client,
gas_price_percentile,
}
Expand Down Expand Up @@ -264,7 +262,7 @@ impl Parity for ParityClient {
txq.ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp)
.into_iter()
.take(limit.unwrap_or_else(usize::max_value))
.map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition))
.map(|tx| Transaction::from_pending(tx))
.collect::<Vec<_>>()
)
}
Expand All @@ -279,7 +277,7 @@ impl Parity for ParityClient {
current
.into_iter()
.chain(future.into_iter())
.map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition))
.map(|tx| Transaction::from_pending(tx))
.collect::<Vec<_>>()
)
}
Expand All @@ -290,7 +288,7 @@ impl Parity for ParityClient {
Ok(
txq.future_transactions(chain_info.best_block_number, chain_info.best_block_timestamp)
.into_iter()
.map(|tx| Transaction::from_pending(tx, chain_info.best_block_number, self.eip86_transition))
.map(|tx| Transaction::from_pending(tx))
.collect::<Vec<_>>()
)
}
Expand Down
Loading

0 comments on commit 637883f

Please sign in to comment.