cfx_executor/
context.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5// Transaction execution environment.
6use crate::{
7    executive_observer::TracerTrait,
8    internal_contract::{
9        block_hash_slot, epoch_hash_slot, suicide as suicide_impl,
10        InternalRefContext,
11    },
12    machine::Machine,
13    return_if,
14    stack::{CallStackInfo, FrameLocal, RuntimeRes},
15    state::State,
16    substate::Substate,
17};
18use cfx_bytes::Bytes;
19use cfx_parameters::staking::{
20    code_collateral_units, DRIPS_PER_STORAGE_COLLATERAL_UNIT,
21};
22use cfx_types::{
23    cal_contract_address_with_space, Address, AddressSpaceUtil,
24    AddressWithSpace, BigEndianHash, CreateContractAddressType, Space, H256,
25    U256,
26};
27use cfx_vm_types::{
28    self as vm, ActionParams, ActionValue, CallType, Context as ContextTrait,
29    ContractCreateResult, CreateType, Env, Error, MessageCallResult,
30    ReturnData, Spec, TrapKind,
31};
32use std::sync::Arc;
33use vm::BlockHashSource;
34
35/// Transaction properties that externalities need to know about.
36#[derive(Debug)]
37pub struct OriginInfo {
38    address: Address,
39    /// This is the address of original sender of the transaction.
40    original_sender: Address,
41    /// This is the address of account who will pay collateral for storage in
42    /// the whole execution.
43    storage_owner: Address,
44    gas_price: U256,
45    value: U256,
46}
47
48impl OriginInfo {
49    /// Populates origin info from action params.
50    pub fn from(params: &ActionParams) -> Self {
51        OriginInfo {
52            address: params.address,
53            original_sender: params.original_sender,
54            storage_owner: params.storage_owner,
55            gas_price: params.gas_price,
56            value: match params.value {
57                ActionValue::Transfer(val) | ActionValue::Apparent(val) => val,
58            },
59        }
60    }
61
62    pub fn recipient(&self) -> &Address { &self.address }
63}
64
65pub struct Context<'a> {
66    space: Space,
67    env: &'a Env,
68    depth: usize,
69    create_address: &'a Option<Address>,
70    origin: &'a OriginInfo,
71    substate: &'a mut Substate,
72    machine: &'a Machine,
73    spec: &'a Spec,
74    static_flag: bool,
75
76    state: &'a mut State,
77    callstack: &'a mut CallStackInfo,
78    tracer: &'a mut dyn TracerTrait,
79}
80
81impl<'a> Context<'a> {
82    pub fn new<'b, 'c>(
83        frame_local: &'a mut FrameLocal<'b>,
84        runtime_resources: &'a mut RuntimeRes<'c>,
85    ) -> Self {
86        let space = frame_local.space;
87        let env = &frame_local.env;
88        let depth = frame_local.depth;
89        let create_address = &frame_local.create_address;
90        let origin = &frame_local.origin;
91        let substate = &mut frame_local.substate;
92        let machine = frame_local.machine;
93        let spec = frame_local.spec;
94        let static_flag = frame_local.static_flag;
95
96        let state = &mut *runtime_resources.state;
97        let callstack = &mut *runtime_resources.callstack;
98        let tracer = &mut *runtime_resources.tracer;
99        Context {
100            space,
101            env,
102            depth,
103            create_address,
104            origin,
105            substate,
106            machine,
107            spec,
108            static_flag,
109            state,
110            callstack,
111            tracer,
112        }
113    }
114
115    fn blockhash_from_env(&self, number: &U256) -> H256 {
116        if self.space == Space::Ethereum && self.spec.cip98 {
117            return if U256::from(self.env().epoch_height) == number + 1 {
118                self.env().last_hash.clone()
119            } else {
120                H256::default()
121            };
122        }
123
124        // In Conflux, we only maintain the block hash of the previous block.
125        // For other block numbers, it always returns zero.
126        if U256::from(self.env().number) == number + 1 {
127            self.env().last_hash.clone()
128        } else {
129            H256::default()
130        }
131    }
132
133    fn blockhash_from_state(&self, number: &U256) -> vm::Result<H256> {
134        return_if!(number > &U256::from(u64::MAX));
135
136        let number = number.as_u64();
137
138        let state_res = match self.space {
139            Space::Native => {
140                return_if!(number < self.spec.cip133_b);
141                return_if!(number > self.env.number);
142                return_if!(number
143                    .checked_add(65536)
144                    .map_or(false, |n| n <= self.env.number));
145                self.state.get_system_storage(&block_hash_slot(number))?
146            }
147            Space::Ethereum => {
148                return_if!(number < self.spec.cip133_e);
149                return_if!(number > self.env.epoch_height);
150                return_if!(number
151                    .checked_add(65536)
152                    .map_or(false, |n| n <= self.env.epoch_height));
153                if self.spec.align_evm {
154                    return_if!(number >= self.env.epoch_height);
155                    return_if!(number + 256 < self.env.epoch_height);
156                }
157                self.state.get_system_storage(&epoch_hash_slot(number))?
158            }
159        };
160
161        Ok(BigEndianHash::from_uint(&state_res))
162    }
163}
164
165impl<'a> ContextTrait for Context<'a> {
166    fn storage_at(&self, key: &[u8]) -> vm::Result<U256> {
167        let receiver = AddressWithSpace {
168            address: self.origin.address,
169            space: self.space,
170        };
171        self.state.storage_at(&receiver, key).map_err(Into::into)
172    }
173
174    fn origin_storage_at(&self, key: &[u8]) -> vm::Result<Option<U256>> {
175        let receiver = AddressWithSpace {
176            address: self.origin.address,
177            space: self.space,
178        };
179        self.state
180            .origin_storage_at(&receiver, key)
181            .map_err(Into::into)
182    }
183
184    fn set_storage(&mut self, key: Vec<u8>, value: U256) -> vm::Result<()> {
185        let receiver = AddressWithSpace {
186            address: self.origin.address,
187            space: self.space,
188        };
189        if self.is_static_or_reentrancy() {
190            Err(vm::Error::MutableCallInStaticContext)
191        } else {
192            self.state
193                .set_storage(
194                    &receiver,
195                    key,
196                    value,
197                    self.origin.storage_owner,
198                    &mut self.substate,
199                )
200                .map_err(Into::into)
201        }
202    }
203
204    fn transient_storage_at(&self, key: &Vec<u8>) -> vm::Result<U256> {
205        let receiver = AddressWithSpace {
206            address: self.origin.address,
207            space: self.space,
208        };
209        self.state
210            .transient_storage_at(&receiver, key)
211            .map_err(Into::into)
212    }
213
214    fn transient_set_storage(
215        &mut self, key: Vec<u8>, value: U256,
216    ) -> vm::Result<()> {
217        let receiver = AddressWithSpace {
218            address: self.origin.address,
219            space: self.space,
220        };
221        if self.is_static_or_reentrancy() {
222            Err(vm::Error::MutableCallInStaticContext)
223        } else {
224            self.state
225                .transient_set_storage(&receiver, key, value)
226                .map_err(Into::into)
227        }
228    }
229
230    fn exists(&self, address: &Address) -> vm::Result<bool> {
231        let address = AddressWithSpace {
232            address: *address,
233            space: self.space,
234        };
235        self.state.exists(&address).map_err(Into::into)
236    }
237
238    fn exists_and_not_null(&self, address: &Address) -> vm::Result<bool> {
239        let address = AddressWithSpace {
240            address: *address,
241            space: self.space,
242        };
243        self.state.exists_and_not_null(&address).map_err(Into::into)
244    }
245
246    fn origin_balance(&self) -> vm::Result<U256> {
247        self.balance(&self.origin.address).map_err(Into::into)
248    }
249
250    fn balance(&self, address: &Address) -> vm::Result<U256> {
251        let address = AddressWithSpace {
252            address: *address,
253            space: self.space,
254        };
255        self.state.balance(&address).map_err(Into::into)
256    }
257
258    fn blockhash(&mut self, number: &U256) -> vm::Result<H256> {
259        match self.blockhash_source() {
260            BlockHashSource::Env => Ok(self.blockhash_from_env(number)),
261            BlockHashSource::State => self.blockhash_from_state(number),
262        }
263    }
264
265    fn create(
266        &mut self, gas: &U256, value: &U256, code: &[u8],
267        address_scheme: CreateContractAddressType,
268    ) -> cfx_statedb::Result<std::result::Result<ContractCreateResult, TrapKind>>
269    {
270        let caller = AddressWithSpace {
271            address: self.origin.address,
272            space: self.space,
273        };
274
275        let create_type = CreateType::from_address_scheme(&address_scheme);
276        // create new contract address
277        let (address_with_space, code_hash) = cal_contract_address_with_space(
278            address_scheme,
279            &caller,
280            &self.state.nonce(&caller)?,
281            &code,
282        );
283
284        let address = address_with_space.address;
285
286        // For a contract address already with code, we do not allow overlap the
287        // address. This should generally not happen. Unless we enable
288        // account dust in future. We add this check just in case it
289        // helps in future.
290        let conflict_address = if !self.spec.cip_c2_fix {
291            self.space == Space::Native
292                && self.state.is_contract_with_code(&address_with_space)?
293        } else {
294            !self.state.is_eip684_empty(&address_with_space)?
295        };
296
297        if conflict_address {
298            if self.spec.cip645.fix_eip684 {
299                self.state.inc_nonce(&caller)?;
300            }
301            debug!("Contract address conflict!");
302            let err = Error::ConflictAddress(address.clone());
303            return Ok(Ok(ContractCreateResult::Failed(err)));
304        }
305
306        // prepare the params
307        let params = ActionParams {
308            space: self.space,
309            code_address: address.clone(),
310            address: address.clone(),
311            sender: self.origin.address.clone(),
312            original_sender: self.origin.original_sender,
313            storage_owner: self.origin.storage_owner,
314            gas: *gas,
315            gas_price: self.origin.gas_price,
316            value: ActionValue::Transfer(*value),
317            code: Some(Arc::new(code.to_vec())),
318            code_hash,
319            data: None,
320            call_type: CallType::None,
321            create_type,
322            params_type: vm::ParamsType::Embedded,
323        };
324
325        if !self.is_static_or_reentrancy() {
326            let nonce_overflow = self.state.inc_nonce(&caller)?;
327            if nonce_overflow {
328                let err = Error::NonceOverflow(caller.address);
329                return Ok(Ok(ContractCreateResult::Failed(err)));
330            }
331        }
332
333        return Ok(Err(TrapKind::Create(params)));
334    }
335
336    fn call(
337        &mut self, gas: &U256, sender_address: &Address,
338        receive_address: &Address, value: Option<U256>, data: &[u8],
339        code_address: &Address, call_type: CallType,
340    ) -> cfx_statedb::Result<std::result::Result<MessageCallResult, TrapKind>>
341    {
342        trace!(target: "context", "call");
343
344        let code_address_with_space = code_address.with_space(self.space);
345
346        let (code, code_hash) = if let Some(contract) = self
347            .machine
348            .internal_contracts()
349            .contract(&code_address_with_space, self.spec)
350        {
351            (Some(contract.code()), contract.code_hash())
352        } else {
353            self.state
354                .code_with_hash_on_call(&code_address_with_space)?
355        };
356
357        let mut params = ActionParams {
358            space: self.space,
359            sender: *sender_address,
360            address: *receive_address,
361            value: ActionValue::Apparent(self.origin.value),
362            code_address: *code_address,
363            original_sender: self.origin.original_sender,
364            storage_owner: self.origin.storage_owner,
365            gas: *gas,
366            gas_price: self.origin.gas_price,
367            code,
368            code_hash,
369            data: Some(data.to_vec()),
370            call_type,
371            create_type: CreateType::None,
372            params_type: vm::ParamsType::Separate,
373        };
374
375        if let Some(value) = value {
376            params.value = ActionValue::Transfer(value);
377        }
378
379        return Ok(Err(TrapKind::Call(params)));
380    }
381
382    fn extcode(&self, address: &Address) -> vm::Result<Option<Arc<Bytes>>> {
383        let address = address.with_space(self.space);
384        if let Some(contract) = self
385            .machine
386            .internal_contracts()
387            .contract(&address, self.spec)
388        {
389            Ok(Some(contract.code()))
390        } else {
391            Ok(self.state.code(&address)?)
392        }
393    }
394
395    fn extcodehash(&self, address: &Address) -> vm::Result<H256> {
396        let address = address.with_space(self.space);
397
398        if let Some(contract) = self
399            .machine
400            .internal_contracts()
401            .contract(&address, self.spec)
402        {
403            Ok(contract.code_hash())
404        } else {
405            if self.spec.cip645.fix_extcodehash
406                && self.state.is_eip158_empty(&address)?
407            {
408                Ok(H256::zero())
409            } else {
410                Ok(self.state.code_hash(&address)?)
411            }
412        }
413    }
414
415    fn extcodesize(&self, address: &Address) -> vm::Result<usize> {
416        let address = address.with_space(self.space);
417
418        if let Some(contract) = self
419            .machine
420            .internal_contracts()
421            .contract(&address, self.spec)
422        {
423            Ok(contract.code_size())
424        } else {
425            Ok(self.state.code_size(&address)?)
426        }
427    }
428
429    fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> vm::Result<()> {
430        use primitives::log_entry::LogEntry;
431
432        if self.is_static_or_reentrancy() {
433            return Err(vm::Error::MutableCallInStaticContext);
434        }
435
436        self.tracer.log(&self.origin.address, &topics, data);
437
438        let address = self.origin.address.clone();
439        self.substate.logs.push(LogEntry {
440            address,
441            topics,
442            data: data.to_vec(),
443            space: self.space,
444        });
445
446        Ok(())
447    }
448
449    fn refund(&mut self, refund_gas: i64) {
450        self.substate.refund_gas += refund_gas as i128;
451    }
452
453    fn ret(
454        mut self, gas: &U256, data: &ReturnData, apply_state: bool,
455    ) -> vm::Result<U256>
456    where Self: Sized {
457        let caller = self.origin.address.with_space(self.space);
458
459        if self.create_address.is_none() || !apply_state {
460            return Ok(*gas);
461        }
462
463        if self.spec.cip7702 && data.first().cloned() == Some(0xef) {
464            return Err(Error::CreateContractStartingWithEF);
465        }
466
467        self.insert_create_address_to_substate();
468
469        let create_data_gas = self.spec.create_data_gas
470            * match self.space {
471                Space::Native => 1,
472                Space::Ethereum => self.spec.evm_gas_ratio,
473            };
474        let return_cost = U256::from(data.len()) * create_data_gas;
475        if return_cost > *gas || data.len() > self.spec.create_data_limit {
476            return Err(vm::Error::OutOfGas);
477        }
478
479        if self.space == Space::Native {
480            let collateral_units_for_code = code_collateral_units(data.len());
481            let collateral_in_drips = U256::from(collateral_units_for_code)
482                * *DRIPS_PER_STORAGE_COLLATERAL_UNIT;
483            debug!("ret()  collateral_for_code={:?}", collateral_in_drips);
484            self.substate.record_storage_occupy(
485                &self.origin.storage_owner,
486                collateral_units_for_code,
487            );
488        }
489
490        let owner = if self.space == Space::Native {
491            self.origin.storage_owner
492        } else {
493            Address::zero()
494        };
495
496        let tx_hash = self.env.transaction_hash;
497        assert_ne!(tx_hash, H256::zero());
498        self.state
499            .init_code(&caller, data.to_vec(), owner, tx_hash)?;
500        Ok(*gas - return_cost)
501    }
502
503    fn suicide(&mut self, refund_address: &Address) -> vm::Result<()> {
504        if self.is_static_or_reentrancy() {
505            return Err(vm::Error::MutableCallInStaticContext);
506        }
507
508        let contract_address_with_space =
509            self.origin.address.with_space(self.space);
510
511        suicide_impl(
512            &contract_address_with_space,
513            &refund_address.with_space(self.space),
514            self.state,
515            &self.spec,
516            &mut self.substate,
517            self.env,
518            self.callstack
519                .creating_contract(&contract_address_with_space),
520            self.tracer,
521        )
522    }
523
524    fn spec(&self) -> &Spec { &self.spec }
525
526    fn env(&self) -> &Env { &self.env }
527
528    fn space(&self) -> Space { self.space }
529
530    fn chain_id(&self) -> u64 { self.env.chain_id[&self.space] as u64 }
531
532    fn depth(&self) -> usize { self.depth }
533
534    fn trace_step(&mut self, interpreter: &dyn vm::InterpreterInfo) {
535        self.tracer.step(interpreter);
536    }
537
538    fn trace_step_end(&mut self, interpreter: &dyn vm::InterpreterInfo) {
539        self.tracer.step_end(interpreter);
540    }
541
542    fn opcode_trace_enabled(&self) -> bool {
543        let mut enabled = false;
544        self.tracer.do_trace_opcode(&mut enabled);
545        enabled
546    }
547
548    fn is_static(&self) -> bool { self.static_flag }
549
550    fn is_static_or_reentrancy(&self) -> bool {
551        self.static_flag || self.callstack.in_reentrancy(self.spec)
552    }
553
554    fn blockhash_source(&self) -> vm::BlockHashSource {
555        let from_state = match self.space {
556            Space::Native => self.env.number >= self.spec.cip133_b,
557            Space::Ethereum => self.env.epoch_height >= self.spec.cip133_e,
558        };
559        if from_state {
560            BlockHashSource::State
561        } else {
562            BlockHashSource::Env
563        }
564    }
565
566    fn is_warm_account(&self, account: Address) -> bool {
567        let address_with_space = account.with_space(self.space);
568        let maybe_builtin = &account[..19] == &[0u8; 19];
569        if maybe_builtin
570            && self
571                .machine
572                .builtin(
573                    &address_with_space,
574                    self.env.number,
575                    self.env.epoch_height,
576                )
577                .is_some()
578        {
579            return true;
580        }
581
582        let maybe_internal = self.space == Space::Native
583            && &account[..2] == b"\x08\x88"
584            && &account[2..19] == &[0u8; 17];
585        if maybe_internal
586            && self
587                .machine
588                .internal_contracts()
589                .contract(&address_with_space, &self.spec)
590                .is_some()
591        {
592            return true;
593        }
594
595        if address_with_space == self.env.author.with_native_space() {
596            return true;
597        }
598
599        self.state.is_warm_account(&address_with_space)
600    }
601
602    fn is_warm_storage_entry(&self, key: &H256) -> vm::Result<bool> {
603        let receiver = AddressWithSpace {
604            address: self.origin.address,
605            space: self.space,
606        };
607        Ok(self.state.is_warm_storage_entry(&receiver, key)?)
608    }
609}
610
611impl<'a> Context<'a> {
612    pub fn internal_ref(&mut self) -> InternalRefContext<'_> {
613        InternalRefContext {
614            env: self.env,
615            spec: self.spec,
616            callstack: self.callstack,
617            state: self.state,
618            substate: &mut self.substate,
619            static_flag: self.static_flag,
620            depth: self.depth,
621            tracer: self.tracer,
622        }
623    }
624
625    pub fn insert_create_address_to_substate(&mut self) {
626        if let Some(create_address) = self.create_address {
627            self.substate
628                .record_contract_create(create_address.with_space(self.space));
629        }
630    }
631}
632
633/// TODO: Move this code to a seperated file. So we can distinguish function
634/// calls from test.
635#[cfg(test)]
636mod tests {
637    use super::{FrameLocal, OriginInfo};
638    use crate::{
639        machine::Machine,
640        stack::{CallStackInfo, OwnedRuntimeRes},
641        state::{get_state_for_genesis_write, State},
642        substate::Substate,
643        tests::MOCK_TX_HASH,
644    };
645    use cfx_parameters::consensus::TRANSACTION_DEFAULT_EPOCH_BOUND;
646    use cfx_types::{
647        address_util::AddressUtil, Address, AddressSpaceUtil, Space, H256, U256,
648    };
649    use cfx_vm_types::{Context as ContextTrait, Env, Spec};
650    use std::{collections::BTreeMap, str::FromStr};
651
652    fn get_test_origin() -> OriginInfo {
653        let mut sender = Address::zero();
654        sender.set_user_account_type_bits();
655        OriginInfo {
656            address: sender,
657            original_sender: sender,
658            storage_owner: Address::zero(),
659            gas_price: U256::zero(),
660            value: U256::zero(),
661        }
662    }
663
664    fn get_test_env() -> Env {
665        Env {
666            chain_id: BTreeMap::from([
667                (Space::Native, 0),
668                (Space::Ethereum, 0),
669            ]),
670            number: 100,
671            author: Address::from_low_u64_be(0),
672            timestamp: 0,
673            difficulty: 0.into(),
674            last_hash: H256::zero(),
675            accumulated_gas_used: 0.into(),
676            gas_limit: 0.into(),
677            epoch_height: 0,
678            pos_view: None,
679            finalized_epoch: None,
680            transaction_epoch_bound: TRANSACTION_DEFAULT_EPOCH_BOUND,
681            base_gas_price: Default::default(),
682            burnt_gas_price: Default::default(),
683            transaction_hash: MOCK_TX_HASH,
684            #[cfg(feature = "align_evm")]
685            blob_gas_fee: 0.into(),
686        }
687    }
688
689    // storage_manager is apparently unused but it must be held to keep the
690    // database directory.
691    #[allow(unused)]
692    struct TestSetup {
693        state: State,
694        machine: Machine,
695        spec: Spec,
696        substate: Substate,
697        env: Env,
698        callstack: CallStackInfo,
699    }
700
701    impl TestSetup {
702        fn new() -> Self {
703            let state = get_state_for_genesis_write();
704            let machine = Machine::new_with_builtin(
705                Default::default(),
706                Default::default(),
707            );
708            let env = get_test_env();
709            let spec = machine.spec_for_test(env.number);
710            let callstack = CallStackInfo::new();
711
712            let mut setup = Self {
713                // storage_manager,
714                state,
715                machine,
716                spec,
717                substate: Substate::new(),
718                env: env.clone(),
719                callstack,
720            };
721            setup
722                .state
723                .init_code(
724                    &Address::zero().with_native_space(),
725                    vec![],
726                    Address::zero(),
727                    env.transaction_hash,
728                )
729                .ok();
730
731            setup
732        }
733    }
734
735    #[test]
736    fn can_be_created() {
737        let mut setup = TestSetup::new();
738        let state = &mut setup.state;
739        let origin = get_test_origin();
740
741        let mut lctx = FrameLocal::new(
742            Space::Native,
743            &setup.env,
744            &setup.machine,
745            &setup.spec,
746            0, /* depth */
747            origin,
748            setup.substate,
749            None,
750            false, /* static_flag */
751        );
752        let mut owned_res = OwnedRuntimeRes::from(state);
753        let mut resources = owned_res.as_res();
754        let ctx = lctx.make_vm_context(&mut resources);
755
756        assert_eq!(ctx.env().number, 100);
757    }
758
759    #[test]
760    fn can_return_block_hash_no_env() {
761        let mut setup = TestSetup::new();
762        let state = &mut setup.state;
763        let origin = get_test_origin();
764
765        let mut lctx = FrameLocal::new(
766            Space::Native,
767            &setup.env,
768            &setup.machine,
769            &setup.spec,
770            0, /* depth */
771            origin,
772            setup.substate,
773            None,
774            false, /* static_flag */
775        );
776        let mut owned_res = OwnedRuntimeRes::from(state);
777        let mut resources = owned_res.as_res();
778        let mut ctx = lctx.make_vm_context(&mut resources);
779
780        let hash = ctx.blockhash(
781            &"0000000000000000000000000000000000000000000000000000000000120000"
782                .parse::<U256>()
783                .unwrap(),
784        ).unwrap();
785
786        assert_eq!(hash, H256::zero());
787    }
788
789    //    #[test]
790    //    fn can_return_block_hash() {
791    //        let test_hash = H256::from(
792    //
793    // "afafafafafafafafafafafbcbcbcbcbcbcbcbcbcbeeeeeeeeeeeeedddddddddd",
794    //        );
795    //        let test_env_number = 0x120001;
796    //
797    //        let mut setup = TestSetup::new();
798    //        {
799    //            let env = &mut setup.env;
800    //            env.number = test_env_number;
801    //            let mut last_hashes = (*env.last_hashes).clone();
802    //            last_hashes.push(test_hash.clone());
803    //            env.last_hashes = Arc::new(last_hashes);
804    //        }
805    //        let state = &mut setup.state;
806    //        let origin = get_test_origin();
807    //
808    //        let mut ctx = Context::new(
809    //            state,
810    //            &setup.env,
811    //            &setup.machine,
812    //            &setup.spec,
813    //            0,
814    //            0,
815    //            &origin,
816    //            &mut setup.substate,
817    //            OutputPolicy::InitContract,
818    //            false,
819    //        );
820    //
821    //        let hash = ctx.blockhash(
822    //
823    // &"0000000000000000000000000000000000000000000000000000000000120000"
824    //                .parse::<U256>()
825    //                .unwrap(),
826    //        );
827    //
828    //        assert_eq!(test_hash, hash);
829    //    }
830
831    // #[test]
832    // #[should_panic]
833    // fn can_call_fail_empty() {
834    //     let mut setup = TestSetup::new();
835    //     let state = &mut setup.state;
836    //     let origin = get_test_origin();
837    //     let mut callstack = CallStackInfo::default();
838    //
839    //     let mut lctx = LocalContext::new(
840    //         &setup.env,
841    //         &setup.machine,
842    //         &setup.spec,
843    //         0, /* depth */
844    //         0, /* stack_depth */
845    //         origin,
846    //         setup.substate,
847    //         true,  /* is_create */
848    //         false, /* static_flag */
849    //         &setup.internal_contract_map,
850    //     );
851    //     let mut ctx = lctx.activate(state, &mut callstack);
852    //
853    //     // this should panic because we have no balance on any account
854    //     ctx.call(
855    //     &"0000000000000000000000000000000000000000000000000000000000120000"
856    //         .parse::<U256>()
857    //         .unwrap(),
858    //     &Address::zero(),
859    //     &Address::zero(),
860    //     Some(
861    //         "0000000000000000000000000000000000000000000000000000000000150000"
862    //             .parse::<U256>()
863    //             .unwrap(),
864    //     ),
865    //     &[],
866    //     &Address::zero(),
867    //     CallType::Call,
868    //     false,
869    // )
870    //         .unwrap()
871    // .unwrap();
872    // }
873
874    #[test]
875    fn can_log() {
876        let log_data = vec![120u8, 110u8];
877        let log_topics = vec![H256::from_str(
878            "af0fa234a6af46afa23faf23bcbc1c1cb4bcb7bcbe7e7e7ee3ee2edddddddddd",
879        )
880        .unwrap()];
881
882        let mut setup = TestSetup::new();
883        let state = &mut setup.state;
884        let origin = get_test_origin();
885
886        {
887            let mut lctx = FrameLocal::new(
888                Space::Native,
889                &setup.env,
890                &setup.machine,
891                &setup.spec,
892                0, /* depth */
893                origin,
894                setup.substate,
895                None,
896                false, /* static_flag */
897            );
898
899            {
900                let mut owned_res = OwnedRuntimeRes::from(state);
901                let mut resources = owned_res.as_res();
902
903                let mut ctx = lctx.make_vm_context(&mut resources);
904                ctx.log(log_topics, &log_data).unwrap();
905            }
906
907            assert_eq!(lctx.substate.logs.len(), 1);
908        }
909    }
910
911    #[test]
912    fn can_suicide() {
913        let mut refund_account = Address::zero();
914        refund_account.set_user_account_type_bits();
915
916        let mut setup = TestSetup::new();
917        setup.spec.cip151 = false;
918        let state = &mut setup.state;
919        let mut origin = get_test_origin();
920
921        let mut contract_address = Address::zero();
922        contract_address.set_contract_type_bits();
923        origin.address = contract_address;
924        let contract_address_w_space = contract_address.with_native_space();
925        state
926            .new_contract_with_code(&contract_address_w_space, U256::zero())
927            .expect(&concat!(file!(), ":", line!(), ":", column!()));
928        state
929            .init_code(
930                &contract_address_w_space,
931                // Use empty code in test because we don't have storage
932                // collateral balance.
933                "".into(),
934                contract_address,
935                setup.env.transaction_hash,
936            )
937            .expect(&concat!(file!(), ":", line!(), ":", column!()));
938
939        {
940            let mut lctx = FrameLocal::new(
941                Space::Native,
942                &setup.env,
943                &setup.machine,
944                &setup.spec,
945                0, /* depth */
946                origin,
947                setup.substate,
948                None,
949                false, /* static_flag */
950            );
951            let mut owned_res = OwnedRuntimeRes::from(state);
952            let mut resources = owned_res.as_res();
953            let mut ctx = lctx.make_vm_context(&mut resources);
954            ctx.suicide(&refund_account).unwrap();
955            assert_eq!(lctx.substate.suicides.len(), 1);
956        }
957    }
958
959    //TODO: It seems create function only has non-trapped call in test. We
960    // remove non-trapped call.
961    /*
962    #[test]
963    fn can_create() {
964        use std::str::FromStr;
965
966        let mut setup = TestSetup::new();
967        let state = &mut setup.state;
968        let origin = get_test_origin();
969        let mut callstack = CallStackInfo::default();
970
971        let address = {
972            let mut lctx = LocalContext::new(
973                &setup.env,
974                &setup.machine,
975                &setup.spec,
976                0, /* depth */
977                0, /* stack_depth */
978                origin,
979                setup.substate,
980                true,  /* is_create */
981                false, /* static_flag */
982                &setup.internal_contract_map,
983            );
984            let mut ctx = lctx.activate(state, &mut callstack);
985            match ctx
986                .create(
987                    &U256::max_value(),
988                    &U256::zero(),
989                    &[],
990                    CreateContractAddress::FromSenderNonceAndCodeHash,
991                    false,
992                )
993                .expect("no db error")
994            {
995                Ok(ContractCreateResult::Created(address, _)) => address,
996                _ => panic!(
997                    "Test create failed; expected Created, got Failed/Reverted"
998                ),
999            }
1000        };
1001
1002        assert_eq!(
1003            address,
1004            Address::from_str("81dc73d9d80f5312901eb62cc4a3ed6ea4ca14e2")
1005                .unwrap()
1006        );
1007    }
1008
1009    #[test]
1010    fn can_create2() {
1011        use std::str::FromStr;
1012
1013        let mut setup = TestSetup::new();
1014        let state = &mut setup.state;
1015        let origin = get_test_origin();
1016        let mut callstack = CallStackInfo::default();
1017
1018        let address = {
1019            let mut lctx = LocalContext::new(
1020                &setup.env,
1021                &setup.machine,
1022                &setup.spec,
1023                0, /* depth */
1024                0, /* stack_depth */
1025                origin,
1026                setup.substate,
1027                true,  /* is_create */
1028                false, /* static_flag */
1029                &setup.internal_contract_map,
1030            );
1031            let mut ctx = lctx.activate(state, &mut callstack);
1032
1033            match ctx
1034                .create(
1035                    &U256::max_value(),
1036                    &U256::zero(),
1037                    &[],
1038                    CreateContractAddress::FromSenderSaltAndCodeHash(
1039                        H256::default(),
1040                    ),
1041                    false,
1042                )
1043                .expect("no db error")
1044            {
1045                Ok(ContractCreateResult::Created(address, _)) => address,
1046                _ => panic!(
1047                "Test create failed; expected Created, got Failed/Reverted."
1048            ),
1049            }
1050        };
1051
1052        assert_eq!(
1053            address,
1054            Address::from_str("84c100a15081f02b9efae8267a69f73bf15e75fa")
1055                .unwrap()
1056        );
1057    }*/
1058}