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