1use 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#[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
74pub fn test_finalize(res: Result<GasLeft>) -> Result<U256> {
76 match res {
77 Ok(GasLeft::Known(gas)) => Ok(gas),
78 Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), Err(e) => Err(e),
80 }
81}
82
83impl FakeExt {
84 pub fn new() -> Self {
86 FakeExt::default()
87 }
88
89 pub fn new_byzantium() -> Self {
91 let mut ext = FakeExt::default();
92 ext.schedule = Schedule::new_byzantium();
93 ext
94 }
95
96 pub fn new_constantinople() -> Self {
98 let mut ext = FakeExt::default();
99 ext.schedule = Schedule::new_constantinople();
100 ext
101 }
102
103 pub fn new_istanbul() -> Self {
105 let mut ext = FakeExt::default();
106 ext.schedule = Schedule::new_istanbul();
107 ext
108 }
109
110 pub fn with_wasm(mut self) -> Self {
112 self.schedule.wasm = Some(Default::default());
113 self
114 }
115
116 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 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 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}