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::contract_address,
8    executive_observer::TracerTrait,
9    internal_contract::{
10        block_hash_slot, epoch_hash_slot, suicide as suicide_impl,
11        InternalRefContext,
12    },
13    machine::Machine,
14    return_if,
15    stack::{CallStackInfo, FrameLocal, RuntimeRes},
16    state::State,
17    substate::Substate,
18};
19use cfx_bytes::Bytes;
20use cfx_parameters::staking::{
21    code_collateral_units, DRIPS_PER_STORAGE_COLLATERAL_UNIT,
22};
23use cfx_types::{
24    Address, AddressSpaceUtil, AddressWithSpace, BigEndianHash, Space, H256,
25    U256,
26};
27use cfx_vm_types::{
28    self as vm, ActionParams, ActionValue, CallType, Context as ContextTrait,
29    ContractCreateResult, CreateContractAddress, CreateType, Env, Error,
30    MessageCallResult, 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: CreateContractAddress,
268    ) -> cfx_statedb::Result<
269        ::std::result::Result<ContractCreateResult, TrapKind>,
270    > {
271        let caller = AddressWithSpace {
272            address: self.origin.address,
273            space: self.space,
274        };
275
276        let create_type = CreateType::from_address_scheme(&address_scheme);
277        // create new contract address
278        let (address_with_space, code_hash) = self::contract_address(
279            address_scheme,
280            self.env.number.into(),
281            &caller,
282            &self.state.nonce(&caller)?,
283            &code,
284        );
285
286        let address = address_with_space.address;
287
288        // For a contract address already with code, we do not allow overlap the
289        // address. This should generally not happen. Unless we enable
290        // account dust in future. We add this check just in case it
291        // helps in future.
292        let conflict_address = if !self.spec.cip_c2_fix {
293            self.space == Space::Native
294                && self.state.is_contract_with_code(&address_with_space)?
295        } else {
296            !self.state.is_eip684_empty(&address_with_space)?
297        };
298
299        if conflict_address {
300            if self.spec.cip645.fix_eip684 {
301                self.state.inc_nonce(&caller)?;
302            }
303            debug!("Contract address conflict!");
304            let err = Error::ConflictAddress(address.clone());
305            return Ok(Ok(ContractCreateResult::Failed(err)));
306        }
307
308        // prepare the params
309        let params = ActionParams {
310            space: self.space,
311            code_address: address.clone(),
312            address: address.clone(),
313            sender: self.origin.address.clone(),
314            original_sender: self.origin.original_sender,
315            storage_owner: self.origin.storage_owner,
316            gas: *gas,
317            gas_price: self.origin.gas_price,
318            value: ActionValue::Transfer(*value),
319            code: Some(Arc::new(code.to_vec())),
320            code_hash,
321            data: None,
322            call_type: CallType::None,
323            create_type,
324            params_type: vm::ParamsType::Embedded,
325        };
326
327        if !self.is_static_or_reentrancy() {
328            let nonce_overflow = self.state.inc_nonce(&caller)?;
329            if nonce_overflow {
330                let err = Error::NonceOverflow(caller.address);
331                return Ok(Ok(ContractCreateResult::Failed(err)));
332            }
333        }
334
335        return Ok(Err(TrapKind::Create(params)));
336    }
337
338    fn call(
339        &mut self, gas: &U256, sender_address: &Address,
340        receive_address: &Address, value: Option<U256>, data: &[u8],
341        code_address: &Address, call_type: CallType,
342    ) -> cfx_statedb::Result<::std::result::Result<MessageCallResult, TrapKind>>
343    {
344        trace!(target: "context", "call");
345
346        let code_address_with_space = code_address.with_space(self.space);
347
348        let (code, code_hash) = if let Some(contract) = self
349            .machine
350            .internal_contracts()
351            .contract(&code_address_with_space, self.spec)
352        {
353            (Some(contract.code()), contract.code_hash())
354        } else {
355            self.state
356                .code_with_hash_on_call(&code_address_with_space)?
357        };
358
359        let mut params = ActionParams {
360            space: self.space,
361            sender: *sender_address,
362            address: *receive_address,
363            value: ActionValue::Apparent(self.origin.value),
364            code_address: *code_address,
365            original_sender: self.origin.original_sender,
366            storage_owner: self.origin.storage_owner,
367            gas: *gas,
368            gas_price: self.origin.gas_price,
369            code,
370            code_hash,
371            data: Some(data.to_vec()),
372            call_type,
373            create_type: CreateType::None,
374            params_type: vm::ParamsType::Separate,
375        };
376
377        if let Some(value) = value {
378            params.value = ActionValue::Transfer(value);
379        }
380
381        return Ok(Err(TrapKind::Call(params)));
382    }
383
384    fn extcode(&self, address: &Address) -> vm::Result<Option<Arc<Bytes>>> {
385        let address = address.with_space(self.space);
386        if let Some(contract) = self
387            .machine
388            .internal_contracts()
389            .contract(&address, self.spec)
390        {
391            Ok(Some(contract.code()))
392        } else {
393            Ok(self.state.code(&address)?)
394        }
395    }
396
397    fn extcodehash(&self, address: &Address) -> vm::Result<H256> {
398        let address = address.with_space(self.space);
399
400        if let Some(contract) = self
401            .machine
402            .internal_contracts()
403            .contract(&address, self.spec)
404        {
405            Ok(contract.code_hash())
406        } else {
407            if self.spec.cip645.fix_extcodehash
408                && self.state.is_eip158_empty(&address)?
409            {
410                Ok(H256::zero())
411            } else {
412                Ok(self.state.code_hash(&address)?)
413            }
414        }
415    }
416
417    fn extcodesize(&self, address: &Address) -> vm::Result<usize> {
418        let address = address.with_space(self.space);
419
420        if let Some(contract) = self
421            .machine
422            .internal_contracts()
423            .contract(&address, self.spec)
424        {
425            Ok(contract.code_size())
426        } else {
427            Ok(self.state.code_size(&address)?)
428        }
429    }
430
431    fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> vm::Result<()> {
432        use primitives::log_entry::LogEntry;
433
434        if self.is_static_or_reentrancy() {
435            return Err(vm::Error::MutableCallInStaticContext);
436        }
437
438        self.tracer.log(&self.origin.address, &topics, data);
439
440        let address = self.origin.address.clone();
441        self.substate.logs.push(LogEntry {
442            address,
443            topics,
444            data: data.to_vec(),
445            space: self.space,
446        });
447
448        Ok(())
449    }
450
451    fn refund(&mut self, refund_gas: i64) {
452        self.substate.refund_gas += refund_gas as i128;
453    }
454
455    fn ret(
456        mut self, gas: &U256, data: &ReturnData, apply_state: bool,
457    ) -> vm::Result<U256>
458    where Self: Sized {
459        let caller = self.origin.address.with_space(self.space);
460
461        if self.create_address.is_none() || !apply_state {
462            return Ok(*gas);
463        }
464
465        if self.spec.cip7702 && data.first().cloned() == Some(0xef) {
466            return Err(Error::CreateContractStartingWithEF);
467        }
468
469        self.insert_create_address_to_substate();
470
471        let create_data_gas = self.spec.create_data_gas
472            * match self.space {
473                Space::Native => 1,
474                Space::Ethereum => self.spec.evm_gas_ratio,
475            };
476        let return_cost = U256::from(data.len()) * create_data_gas;
477        if return_cost > *gas || data.len() > self.spec.create_data_limit {
478            return Err(vm::Error::OutOfGas);
479        }
480
481        if self.space == Space::Native {
482            let collateral_units_for_code = code_collateral_units(data.len());
483            let collateral_in_drips = U256::from(collateral_units_for_code)
484                * *DRIPS_PER_STORAGE_COLLATERAL_UNIT;
485            debug!("ret()  collateral_for_code={:?}", collateral_in_drips);
486            self.substate.record_storage_occupy(
487                &self.origin.storage_owner,
488                collateral_units_for_code,
489            );
490        }
491
492        let owner = if self.space == Space::Native {
493            self.origin.storage_owner
494        } else {
495            Address::zero()
496        };
497
498        let tx_hash = self.env.transaction_hash;
499        assert_ne!(tx_hash, H256::zero());
500        self.state
501            .init_code(&caller, data.to_vec(), owner, tx_hash)?;
502        Ok(*gas - return_cost)
503    }
504
505    fn suicide(&mut self, refund_address: &Address) -> vm::Result<()> {
506        if self.is_static_or_reentrancy() {
507            return Err(vm::Error::MutableCallInStaticContext);
508        }
509
510        let contract_address_with_space =
511            self.origin.address.with_space(self.space);
512
513        suicide_impl(
514            &contract_address_with_space,
515            &refund_address.with_space(self.space),
516            self.state,
517            &self.spec,
518            &mut self.substate,
519            self.env,
520            self.callstack
521                .creating_contract(&contract_address_with_space),
522            self.tracer,
523        )
524    }
525
526    fn spec(&self) -> &Spec { &self.spec }
527
528    fn env(&self) -> &Env { &self.env }
529
530    fn space(&self) -> Space { self.space }
531
532    fn chain_id(&self) -> u64 { self.env.chain_id[&self.space] as u64 }
533
534    fn depth(&self) -> usize { self.depth }
535
536    fn trace_step(&mut self, interpreter: &dyn vm::InterpreterInfo) {
537        self.tracer.step(interpreter);
538    }
539
540    fn trace_step_end(&mut self, interpreter: &dyn vm::InterpreterInfo) {
541        self.tracer.step_end(interpreter);
542    }
543
544    fn opcode_trace_enabled(&self) -> bool {
545        let mut enabled = false;
546        self.tracer.do_trace_opcode(&mut enabled);
547        enabled
548    }
549
550    fn is_static(&self) -> bool { self.static_flag }
551
552    fn is_static_or_reentrancy(&self) -> bool {
553        self.static_flag || self.callstack.in_reentrancy(self.spec)
554    }
555
556    fn blockhash_source(&self) -> vm::BlockHashSource {
557        let from_state = match self.space {
558            Space::Native => self.env.number >= self.spec.cip133_b,
559            Space::Ethereum => self.env.epoch_height >= self.spec.cip133_e,
560        };
561        if from_state {
562            BlockHashSource::State
563        } else {
564            BlockHashSource::Env
565        }
566    }
567
568    fn is_warm_account(&self, account: Address) -> bool {
569        let address_with_space = account.with_space(self.space);
570        let maybe_builtin = &account[..19] == &[0u8; 19];
571        if maybe_builtin
572            && self
573                .machine
574                .builtin(&address_with_space, self.env.number)
575                .is_some()
576        {
577            return true;
578        }
579
580        let maybe_internal = self.space == Space::Native
581            && &account[..2] == b"\x08\x88"
582            && &account[2..19] == &[0u8; 17];
583        if maybe_internal
584            && self
585                .machine
586                .internal_contracts()
587                .contract(&address_with_space, &self.spec)
588                .is_some()
589        {
590            return true;
591        }
592
593        if address_with_space == self.env.author.with_native_space() {
594            return true;
595        }
596
597        self.state.is_warm_account(&address_with_space)
598    }
599
600    fn is_warm_storage_entry(&self, key: &H256) -> vm::Result<bool> {
601        let receiver = AddressWithSpace {
602            address: self.origin.address,
603            space: self.space,
604        };
605        Ok(self.state.is_warm_storage_entry(&receiver, key)?)
606    }
607}
608
609impl<'a> Context<'a> {
610    pub fn internal_ref(&mut self) -> InternalRefContext<'_> {
611        InternalRefContext {
612            env: self.env,
613            spec: self.spec,
614            callstack: self.callstack,
615            state: self.state,
616            substate: &mut self.substate,
617            static_flag: self.static_flag,
618            depth: self.depth,
619            tracer: self.tracer,
620        }
621    }
622
623    pub fn insert_create_address_to_substate(&mut self) {
624        if let Some(create_address) = self.create_address {
625            self.substate
626                .record_contract_create(create_address.with_space(self.space));
627        }
628    }
629}
630
631/// TODO: Move this code to a seperated file. So we can distinguish function
632/// calls from test.
633#[cfg(test)]
634mod tests {
635    use super::{FrameLocal, OriginInfo};
636    use crate::{
637        machine::Machine,
638        stack::{CallStackInfo, OwnedRuntimeRes},
639        state::{get_state_for_genesis_write, State},
640        substate::Substate,
641        tests::MOCK_TX_HASH,
642    };
643    use cfx_parameters::consensus::TRANSACTION_DEFAULT_EPOCH_BOUND;
644    use cfx_types::{
645        address_util::AddressUtil, Address, AddressSpaceUtil, Space, H256, U256,
646    };
647    use cfx_vm_types::{Context as ContextTrait, Env, Spec};
648    use std::{collections::BTreeMap, str::FromStr};
649
650    fn get_test_origin() -> OriginInfo {
651        let mut sender = Address::zero();
652        sender.set_user_account_type_bits();
653        OriginInfo {
654            address: sender,
655            original_sender: sender,
656            storage_owner: Address::zero(),
657            gas_price: U256::zero(),
658            value: U256::zero(),
659        }
660    }
661
662    fn get_test_env() -> Env {
663        Env {
664            chain_id: BTreeMap::from([
665                (Space::Native, 0),
666                (Space::Ethereum, 0),
667            ]),
668            number: 100,
669            author: Address::from_low_u64_be(0),
670            timestamp: 0,
671            difficulty: 0.into(),
672            last_hash: H256::zero(),
673            accumulated_gas_used: 0.into(),
674            gas_limit: 0.into(),
675            epoch_height: 0,
676            pos_view: None,
677            finalized_epoch: None,
678            transaction_epoch_bound: TRANSACTION_DEFAULT_EPOCH_BOUND,
679            base_gas_price: Default::default(),
680            burnt_gas_price: Default::default(),
681            transaction_hash: MOCK_TX_HASH,
682            #[cfg(feature = "align_evm")]
683            blob_gas_fee: 0.into(),
684        }
685    }
686
687    // storage_manager is apparently unused but it must be held to keep the
688    // database directory.
689    #[allow(unused)]
690    struct TestSetup {
691        state: State,
692        machine: Machine,
693        spec: Spec,
694        substate: Substate,
695        env: Env,
696        callstack: CallStackInfo,
697    }
698
699    impl TestSetup {
700        fn new() -> Self {
701            let state = get_state_for_genesis_write();
702            let machine = Machine::new_with_builtin(
703                Default::default(),
704                Default::default(),
705            );
706            let env = get_test_env();
707            let spec = machine.spec_for_test(env.number);
708            let callstack = CallStackInfo::new();
709
710            let mut setup = Self {
711                // storage_manager,
712                state,
713                machine,
714                spec,
715                substate: Substate::new(),
716                env: env.clone(),
717                callstack,
718            };
719            setup
720                .state
721                .init_code(
722                    &Address::zero().with_native_space(),
723                    vec![],
724                    Address::zero(),
725                    env.transaction_hash,
726                )
727                .ok();
728
729            setup
730        }
731    }
732
733    #[test]
734    fn can_be_created() {
735        let mut setup = TestSetup::new();
736        let state = &mut setup.state;
737        let origin = get_test_origin();
738
739        let mut lctx = FrameLocal::new(
740            Space::Native,
741            &setup.env,
742            &setup.machine,
743            &setup.spec,
744            0, /* depth */
745            origin,
746            setup.substate,
747            None,
748            false, /* static_flag */
749        );
750        let mut owned_res = OwnedRuntimeRes::from(state);
751        let mut resources = owned_res.as_res();
752        let ctx = lctx.make_vm_context(&mut resources);
753
754        assert_eq!(ctx.env().number, 100);
755    }
756
757    #[test]
758    fn can_return_block_hash_no_env() {
759        let mut setup = TestSetup::new();
760        let state = &mut setup.state;
761        let origin = get_test_origin();
762
763        let mut lctx = FrameLocal::new(
764            Space::Native,
765            &setup.env,
766            &setup.machine,
767            &setup.spec,
768            0, /* depth */
769            origin,
770            setup.substate,
771            None,
772            false, /* static_flag */
773        );
774        let mut owned_res = OwnedRuntimeRes::from(state);
775        let mut resources = owned_res.as_res();
776        let mut ctx = lctx.make_vm_context(&mut resources);
777
778        let hash = ctx.blockhash(
779            &"0000000000000000000000000000000000000000000000000000000000120000"
780                .parse::<U256>()
781                .unwrap(),
782        ).unwrap();
783
784        assert_eq!(hash, H256::zero());
785    }
786
787    //    #[test]
788    //    fn can_return_block_hash() {
789    //        let test_hash = H256::from(
790    //
791    // "afafafafafafafafafafafbcbcbcbcbcbcbcbcbcbeeeeeeeeeeeeedddddddddd",
792    //        );
793    //        let test_env_number = 0x120001;
794    //
795    //        let mut setup = TestSetup::new();
796    //        {
797    //            let env = &mut setup.env;
798    //            env.number = test_env_number;
799    //            let mut last_hashes = (*env.last_hashes).clone();
800    //            last_hashes.push(test_hash.clone());
801    //            env.last_hashes = Arc::new(last_hashes);
802    //        }
803    //        let state = &mut setup.state;
804    //        let origin = get_test_origin();
805    //
806    //        let mut ctx = Context::new(
807    //            state,
808    //            &setup.env,
809    //            &setup.machine,
810    //            &setup.spec,
811    //            0,
812    //            0,
813    //            &origin,
814    //            &mut setup.substate,
815    //            OutputPolicy::InitContract,
816    //            false,
817    //        );
818    //
819    //        let hash = ctx.blockhash(
820    //
821    // &"0000000000000000000000000000000000000000000000000000000000120000"
822    //                .parse::<U256>()
823    //                .unwrap(),
824    //        );
825    //
826    //        assert_eq!(test_hash, hash);
827    //    }
828
829    // #[test]
830    // #[should_panic]
831    // fn can_call_fail_empty() {
832    //     let mut setup = TestSetup::new();
833    //     let state = &mut setup.state;
834    //     let origin = get_test_origin();
835    //     let mut callstack = CallStackInfo::default();
836    //
837    //     let mut lctx = LocalContext::new(
838    //         &setup.env,
839    //         &setup.machine,
840    //         &setup.spec,
841    //         0, /* depth */
842    //         0, /* stack_depth */
843    //         origin,
844    //         setup.substate,
845    //         true,  /* is_create */
846    //         false, /* static_flag */
847    //         &setup.internal_contract_map,
848    //     );
849    //     let mut ctx = lctx.activate(state, &mut callstack);
850    //
851    //     // this should panic because we have no balance on any account
852    //     ctx.call(
853    //     &"0000000000000000000000000000000000000000000000000000000000120000"
854    //         .parse::<U256>()
855    //         .unwrap(),
856    //     &Address::zero(),
857    //     &Address::zero(),
858    //     Some(
859    //         "0000000000000000000000000000000000000000000000000000000000150000"
860    //             .parse::<U256>()
861    //             .unwrap(),
862    //     ),
863    //     &[],
864    //     &Address::zero(),
865    //     CallType::Call,
866    //     false,
867    // )
868    //         .unwrap()
869    // .unwrap();
870    // }
871
872    #[test]
873    fn can_log() {
874        let log_data = vec![120u8, 110u8];
875        let log_topics = vec![H256::from_str(
876            "af0fa234a6af46afa23faf23bcbc1c1cb4bcb7bcbe7e7e7ee3ee2edddddddddd",
877        )
878        .unwrap()];
879
880        let mut setup = TestSetup::new();
881        let state = &mut setup.state;
882        let origin = get_test_origin();
883
884        {
885            let mut lctx = FrameLocal::new(
886                Space::Native,
887                &setup.env,
888                &setup.machine,
889                &setup.spec,
890                0, /* depth */
891                origin,
892                setup.substate,
893                None,
894                false, /* static_flag */
895            );
896
897            {
898                let mut owned_res = OwnedRuntimeRes::from(state);
899                let mut resources = owned_res.as_res();
900
901                let mut ctx = lctx.make_vm_context(&mut resources);
902                ctx.log(log_topics, &log_data).unwrap();
903            }
904
905            assert_eq!(lctx.substate.logs.len(), 1);
906        }
907    }
908
909    #[test]
910    fn can_suicide() {
911        let mut refund_account = Address::zero();
912        refund_account.set_user_account_type_bits();
913
914        let mut setup = TestSetup::new();
915        setup.spec.cip151 = false;
916        let state = &mut setup.state;
917        let mut origin = get_test_origin();
918
919        let mut contract_address = Address::zero();
920        contract_address.set_contract_type_bits();
921        origin.address = contract_address;
922        let contract_address_w_space = contract_address.with_native_space();
923        state
924            .new_contract_with_code(&contract_address_w_space, U256::zero())
925            .expect(&concat!(file!(), ":", line!(), ":", column!()));
926        state
927            .init_code(
928                &contract_address_w_space,
929                // Use empty code in test because we don't have storage
930                // collateral balance.
931                "".into(),
932                contract_address,
933                setup.env.transaction_hash,
934            )
935            .expect(&concat!(file!(), ":", line!(), ":", column!()));
936
937        {
938            let mut lctx = FrameLocal::new(
939                Space::Native,
940                &setup.env,
941                &setup.machine,
942                &setup.spec,
943                0, /* depth */
944                origin,
945                setup.substate,
946                None,
947                false, /* static_flag */
948            );
949            let mut owned_res = OwnedRuntimeRes::from(state);
950            let mut resources = owned_res.as_res();
951            let mut ctx = lctx.make_vm_context(&mut resources);
952            ctx.suicide(&refund_account).unwrap();
953            assert_eq!(lctx.substate.suicides.len(), 1);
954        }
955    }
956
957    //TODO: It seems create function only has non-trapped call in test. We
958    // remove non-trapped call.
959    /*
960    #[test]
961    fn can_create() {
962        use std::str::FromStr;
963
964        let mut setup = TestSetup::new();
965        let state = &mut setup.state;
966        let origin = get_test_origin();
967        let mut callstack = CallStackInfo::default();
968
969        let address = {
970            let mut lctx = LocalContext::new(
971                &setup.env,
972                &setup.machine,
973                &setup.spec,
974                0, /* depth */
975                0, /* stack_depth */
976                origin,
977                setup.substate,
978                true,  /* is_create */
979                false, /* static_flag */
980                &setup.internal_contract_map,
981            );
982            let mut ctx = lctx.activate(state, &mut callstack);
983            match ctx
984                .create(
985                    &U256::max_value(),
986                    &U256::zero(),
987                    &[],
988                    CreateContractAddress::FromSenderNonceAndCodeHash,
989                    false,
990                )
991                .expect("no db error")
992            {
993                Ok(ContractCreateResult::Created(address, _)) => address,
994                _ => panic!(
995                    "Test create failed; expected Created, got Failed/Reverted"
996                ),
997            }
998        };
999
1000        assert_eq!(
1001            address,
1002            Address::from_str("81dc73d9d80f5312901eb62cc4a3ed6ea4ca14e2")
1003                .unwrap()
1004        );
1005    }
1006
1007    #[test]
1008    fn can_create2() {
1009        use std::str::FromStr;
1010
1011        let mut setup = TestSetup::new();
1012        let state = &mut setup.state;
1013        let origin = get_test_origin();
1014        let mut callstack = CallStackInfo::default();
1015
1016        let address = {
1017            let mut lctx = LocalContext::new(
1018                &setup.env,
1019                &setup.machine,
1020                &setup.spec,
1021                0, /* depth */
1022                0, /* stack_depth */
1023                origin,
1024                setup.substate,
1025                true,  /* is_create */
1026                false, /* static_flag */
1027                &setup.internal_contract_map,
1028            );
1029            let mut ctx = lctx.activate(state, &mut callstack);
1030
1031            match ctx
1032                .create(
1033                    &U256::max_value(),
1034                    &U256::zero(),
1035                    &[],
1036                    CreateContractAddress::FromSenderSaltAndCodeHash(
1037                        H256::default(),
1038                    ),
1039                    false,
1040                )
1041                .expect("no db error")
1042            {
1043                Ok(ContractCreateResult::Created(address, _)) => address,
1044                _ => panic!(
1045                "Test create failed; expected Created, got Failed/Reverted."
1046            ),
1047            }
1048        };
1049
1050        assert_eq!(
1051            address,
1052            Address::from_str("84c100a15081f02b9efae8267a69f73bf15e75fa")
1053                .unwrap()
1054        );
1055    }*/
1056}