mep_vm/
tests.rs

1// Copyright 2015-2020 Parity Technologies (UK) Ltd.
2// This file is part of Parity Ethereum.
3
4// Parity Ethereum is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Ethereum is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Ethereum.  If not, see <http://www.gnu.org/licenses/>.
16
17use std::sync::Arc;
18use std::collections::{HashMap, HashSet};
19
20use ethereum_types::{U256, H256, Address};
21use bytes::Bytes;
22use {
23	ActionType, Schedule, EnvInfo,
24	ReturnData, Ext, ContractCreateResult, MessageCallResult,
25	CreateContractAddress, Result, GasLeft,
26};
27use hash::keccak;
28use error::TrapKind;
29
30pub struct FakeLogEntry {
31	pub topics: Vec<H256>,
32	pub data: Bytes
33}
34
35#[derive(PartialEq, Eq, Hash, Debug)]
36pub enum FakeCallType {
37	Call, Create
38}
39
40#[derive(PartialEq, Eq, Hash, Debug)]
41pub struct FakeCall {
42	pub call_type: FakeCallType,
43	pub create_scheme: Option<CreateContractAddress>,
44	pub gas: U256,
45	pub sender_address: Option<Address>,
46	pub receive_address: Option<Address>,
47	pub value: Option<U256>,
48	pub data: Bytes,
49	pub code_address: Option<Address>,
50}
51
52/// Fake externalities test structure.
53///
54/// Can't do recursive calls.
55#[derive(Default)]
56pub struct FakeExt {
57	pub store: HashMap<H256, H256>,
58	pub suicides: HashSet<Address>,
59	pub calls: HashSet<FakeCall>,
60	pub sstore_clears: i128,
61	pub depth: usize,
62	pub blockhashes: HashMap<U256, H256>,
63	pub codes: HashMap<Address, Arc<Bytes>>,
64	pub logs: Vec<FakeLogEntry>,
65	pub info: EnvInfo,
66	pub schedule: Schedule,
67	pub balances: HashMap<Address, U256>,
68	pub tracing: bool,
69	pub is_static: bool,
70
71	chain_id: u64,
72}
73
74// similar to the normal `finalize` function, but ignoring NeedsReturn.
75pub fn test_finalize(res: Result<GasLeft>) -> Result<U256> {
76	match res {
77		Ok(GasLeft::Known(gas)) => Ok(gas),
78		Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented.
79		Err(e) => Err(e),
80	}
81}
82
83impl FakeExt {
84	/// New fake externalities
85	pub fn new() -> Self {
86		FakeExt::default()
87	}
88
89	/// New fake externalities with byzantium schedule rules
90	pub fn new_byzantium() -> Self {
91		let mut ext = FakeExt::default();
92		ext.schedule = Schedule::new_byzantium();
93		ext
94	}
95
96	/// New fake externalities with constantinople schedule rules
97	pub fn new_constantinople() -> Self {
98		let mut ext = FakeExt::default();
99		ext.schedule = Schedule::new_constantinople();
100		ext
101	}
102
103	/// New fake externalities with Istanbul schedule rules
104	pub fn new_istanbul() -> Self {
105		let mut ext = FakeExt::default();
106		ext.schedule = Schedule::new_istanbul();
107		ext
108	}
109
110	/// Alter fake externalities to allow wasm
111	pub fn with_wasm(mut self) -> Self {
112		self.schedule.wasm = Some(Default::default());
113		self
114	}
115
116	/// Set chain ID
117	pub fn with_chain_id(mut self, chain_id: u64) -> Self {
118		self.chain_id = chain_id;
119		self
120	}
121}
122
123impl Ext for FakeExt {
124	fn initial_storage_at(&self, _key: &H256) -> Result<H256> {
125		Ok(H256::zero())
126	}
127
128	fn storage_at(&self, key: &H256) -> Result<H256> {
129		Ok(self.store.get(key).unwrap_or(&H256::zero()).clone())
130	}
131
132	fn set_storage(&mut self, key: H256, value: H256) -> Result<()> {
133		self.store.insert(key, value);
134		Ok(())
135	}
136
137	fn exists(&self, address: &Address) -> Result<bool> {
138		Ok(self.balances.contains_key(address))
139	}
140
141	fn exists_and_not_null(&self, address: &Address) -> Result<bool> {
142		Ok(self.balances.get(address).map_or(false, |b| !b.is_zero()))
143	}
144
145	fn origin_balance(&self) -> Result<U256> {
146		unimplemented!()
147	}
148
149	fn balance(&self, address: &Address) -> Result<U256> {
150		Ok(self.balances[address])
151	}
152
153	fn blockhash(&mut self, number: &U256) -> H256 {
154		self.blockhashes.get(number).unwrap_or(&H256::zero()).clone()
155	}
156
157	fn create(
158		&mut self,
159		gas: &U256,
160		value: &U256,
161		code: &[u8],
162		_parent_version: &U256,
163		address: CreateContractAddress,
164		_trap: bool,
165	) -> ::std::result::Result<ContractCreateResult, TrapKind> {
166		self.calls.insert(FakeCall {
167			call_type: FakeCallType::Create,
168			create_scheme: Some(address),
169			gas: *gas,
170			sender_address: None,
171			receive_address: None,
172			value: Some(*value),
173			data: code.to_vec(),
174			code_address: None
175		});
176		// TODO: support traps in testing.
177		Ok(ContractCreateResult::Failed)
178	}
179
180	fn call(
181		&mut self,
182		gas: &U256,
183		sender_address: &Address,
184		receive_address: &Address,
185		value: Option<U256>,
186		data: &[u8],
187		code_address: &Address,
188		_call_type: ActionType,
189		_trap: bool,
190	) -> ::std::result::Result<MessageCallResult, TrapKind> {
191		self.calls.insert(FakeCall {
192			call_type: FakeCallType::Call,
193			create_scheme: None,
194			gas: *gas,
195			sender_address: Some(sender_address.clone()),
196			receive_address: Some(receive_address.clone()),
197			value: value,
198			data: data.to_vec(),
199			code_address: Some(code_address.clone())
200		});
201		// TODO: support traps in testing.
202		Ok(MessageCallResult::Success(*gas, ReturnData::empty()))
203	}
204
205	fn extcode(&self, address: &Address) -> Result<Option<Arc<Bytes>>> {
206		Ok(self.codes.get(address).cloned())
207	}
208
209	fn extcodesize(&self, address: &Address) -> Result<Option<usize>> {
210		Ok(self.codes.get(address).map(|c| c.len()))
211	}
212
213	fn extcodehash(&self, address: &Address) -> Result<Option<H256>> {
214		Ok(self.codes.get(address).map(|c| keccak(c.as_ref())))
215	}
216
217	fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> Result<()> {
218		self.logs.push(FakeLogEntry {
219			topics,
220			data: data.to_vec()
221		});
222		Ok(())
223	}
224
225	fn ret(self, _gas: &U256, _data: &ReturnData, _apply_state: bool) -> Result<U256> {
226		unimplemented!();
227	}
228
229	fn suicide(&mut self, refund_address: &Address) -> Result<()> {
230		self.suicides.insert(refund_address.clone());
231		Ok(())
232	}
233
234	fn schedule(&self) -> &Schedule {
235		&self.schedule
236	}
237
238	fn env_info(&self) -> &EnvInfo {
239		&self.info
240	}
241
242	fn chain_id(&self) -> u64 {
243		self.chain_id
244	}
245
246	fn depth(&self) -> usize {
247		self.depth
248	}
249
250	fn is_static(&self) -> bool {
251		self.is_static
252	}
253
254	fn add_sstore_refund(&mut self, value: usize) {
255		self.sstore_clears += value as i128;
256	}
257
258	fn sub_sstore_refund(&mut self, value: usize) {
259		self.sstore_clears -= value as i128;
260	}
261
262	fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _gas: U256) -> bool {
263		self.tracing
264	}
265}