Comply EIP-86 with the new definition (#9140)

* 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
This commit is contained in:
Wei Tang 2018-08-01 19:17:04 +08:00 committed by Marek Kotewicz
parent f0c0da8551
commit 637883f52b
17 changed files with 96 additions and 73 deletions

View File

@ -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
};

View File

@ -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)
},

View File

@ -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();
@ -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 {

View File

@ -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 => {

View File

@ -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());
}
}

View File

@ -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.

View File

@ -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,
}

View File

@ -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,

View File

@ -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> {
@ -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> {

View File

@ -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())
@ -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.
@ -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());
@ -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

View File

@ -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)]
@ -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(),
}
}
@ -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()),
@ -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),
};
@ -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)
}
@ -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))

View File

@ -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>| {
@ -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()),
@ -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.

View File

@ -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,
}
@ -80,7 +79,6 @@ impl ParityClient {
settings,
signer,
ws_address,
eip86_transition: client.eip86_transition(),
client,
gas_price_percentile,
}
@ -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<_>>()
)
}
@ -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<_>>()
)
}
@ -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<_>>()
)
}

View File

@ -62,7 +62,6 @@ pub struct ParityClient<C, M, U> {
settings: Arc<NetworkSettings>,
signer: Option<Arc<SignerService>>,
ws_address: Option<Host>,
eip86_transition: u64,
}
impl<C, M, U> ParityClient<C, M, U> where
@ -81,7 +80,6 @@ impl<C, M, U> ParityClient<C, M, U> where
signer: Option<Arc<SignerService>>,
ws_address: Option<Host>,
) -> Self {
let eip86_transition = client.eip86_transition();
ParityClient {
client,
miner,
@ -93,7 +91,6 @@ impl<C, M, U> ParityClient<C, M, U> where
settings,
signer,
ws_address,
eip86_transition,
}
}
}
@ -296,7 +293,6 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
}
fn pending_transactions(&self, limit: Trailing<usize>) -> Result<Vec<Transaction>> {
let block_number = self.client.chain_info().best_block_number;
let ready_transactions = self.miner.ready_transactions(
&*self.client,
limit.unwrap_or_else(usize::max_value),
@ -305,18 +301,17 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
Ok(ready_transactions
.into_iter()
.map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition))
.map(|t| Transaction::from_pending(t.pending().clone()))
.collect()
)
}
fn all_transactions(&self) -> Result<Vec<Transaction>> {
let block_number = self.client.chain_info().best_block_number;
let all_transactions = self.miner.queued_transactions();
Ok(all_transactions
.into_iter()
.map(|t| Transaction::from_pending(t.pending().clone(), block_number, self.eip86_transition))
.map(|t| Transaction::from_pending(t.pending().clone()))
.collect()
)
}
@ -335,10 +330,9 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
fn local_transactions(&self) -> Result<BTreeMap<H256, LocalTransactionStatus>> {
let transactions = self.miner.local_transactions();
let block_number = self.client.chain_info().best_block_number;
Ok(transactions
.into_iter()
.map(|(hash, status)| (hash.into(), LocalTransactionStatus::from(status, block_number, self.eip86_transition)))
.map(|(hash, status)| (hash.into(), LocalTransactionStatus::from(status)))
.collect()
)
}

View File

@ -41,7 +41,6 @@ pub struct ParitySetClient<C, M, U, F = fetch::Client> {
net: Arc<ManageNetwork>,
fetch: F,
pool: CpuPool,
eip86_transition: u64,
}
impl<C, M, U, F> ParitySetClient<C, M, U, F>
@ -63,7 +62,6 @@ impl<C, M, U, F> ParitySetClient<C, M, U, F>
net: net.clone(),
fetch: fetch,
pool: pool,
eip86_transition: client.eip86_transition(),
}
}
}
@ -191,11 +189,10 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
}
fn remove_transaction(&self, hash: H256) -> Result<Option<Transaction>> {
let block_number = self.client.chain_info().best_block_number;
let hash = hash.into();
Ok(self.miner.remove_transaction(&hash)
.map(|t| Transaction::from_pending(t.pending().clone(), block_number + 1, self.eip86_transition))
.map(|t| Transaction::from_pending(t.pending().clone()))
)
}
}

View File

@ -339,7 +339,7 @@ fn should_add_sign_transaction_to_the_queue() {
// respond
let sender = signer.take(&1.into()).unwrap();
signer.request_confirmed(sender, Ok(ConfirmationResponse::SignTransaction(
RichRawTransaction::from_signed(t.into(), 0x0, u64::max_value())
RichRawTransaction::from_signed(t.into())
)));
break
}

View File

@ -161,8 +161,8 @@ pub struct RichRawTransaction {
impl RichRawTransaction {
/// Creates new `RichRawTransaction` from `SignedTransaction`.
pub fn from_signed(tx: SignedTransaction, block_number: u64, eip86_transition: u64) -> Self {
let tx = Transaction::from_signed(tx, block_number, eip86_transition);
pub fn from_signed(tx: SignedTransaction) -> Self {
let tx = Transaction::from_signed(tx);
RichRawTransaction {
raw: tx.raw.clone(),
transaction: tx,
@ -172,9 +172,9 @@ impl RichRawTransaction {
impl Transaction {
/// Convert `LocalizedTransaction` into RPC Transaction.
pub fn from_localized(mut t: LocalizedTransaction, eip86_transition: u64) -> Transaction {
pub fn from_localized(mut t: LocalizedTransaction) -> Transaction {
let signature = t.signature();
let scheme = if t.block_number >= eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce };
let scheme = CreateContractAddress::FromSenderAndNonce;
Transaction {
hash: t.hash().into(),
nonce: t.nonce.into(),
@ -206,9 +206,9 @@ impl Transaction {
}
/// Convert `SignedTransaction` into RPC Transaction.
pub fn from_signed(t: SignedTransaction, block_number: u64, eip86_transition: u64) -> Transaction {
pub fn from_signed(t: SignedTransaction) -> Transaction {
let signature = t.signature();
let scheme = if block_number >= eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce };
let scheme = CreateContractAddress::FromSenderAndNonce;
Transaction {
hash: t.hash().into(),
nonce: t.nonce.into(),
@ -240,8 +240,8 @@ impl Transaction {
}
/// Convert `PendingTransaction` into RPC Transaction.
pub fn from_pending(t: PendingTransaction, block_number: u64, eip86_transition: u64) -> Transaction {
let mut r = Transaction::from_signed(t.transaction, block_number, eip86_transition);
pub fn from_pending(t: PendingTransaction) -> Transaction {
let mut r = Transaction::from_signed(t.transaction);
r.condition = t.condition.map(|b| b.into());
r
}
@ -249,9 +249,9 @@ impl Transaction {
impl LocalTransactionStatus {
/// Convert `LocalTransactionStatus` into RPC `LocalTransactionStatus`.
pub fn from(s: miner::pool::local_transactions::Status, block_number: u64, eip86_transition: u64) -> Self {
pub fn from(s: miner::pool::local_transactions::Status) -> Self {
let convert = |tx: Arc<miner::pool::VerifiedTransaction>| {
Transaction::from_signed(tx.signed().clone(), block_number, eip86_transition)
Transaction::from_signed(tx.signed().clone())
};
use miner::pool::local_transactions::Status::*;
match s {