1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use crate::{
    executive_observer::TracerTrait, stack::CallStackInfo, state::State,
    substate::Substate,
};
use cfx_statedb::Result as DbResult;
use cfx_types::{
    address_util::AddressUtil, Address, AddressSpaceUtil, H256, U256,
};
use cfx_vm_types::{self as vm, ActionParams, Env, Spec};

/// The internal contracts need to access the context parameter directly, e.g.,
/// `foo(env, spec)`. But `foo(context.env(), context.spec())` will incur
/// lifetime issue. The `InternalRefContext` contains the parameters required by
/// the internal contracts.
pub struct InternalRefContext<'a> {
    pub env: &'a Env,
    pub spec: &'a Spec,
    pub callstack: &'a mut CallStackInfo,
    pub state: &'a mut State,
    pub substate: &'a mut Substate,
    pub tracer: &'a mut dyn TracerTrait,
    pub static_flag: bool,
    pub depth: usize,
}

// The following implementation is copied from `executive/context.rs`. I know
// it is not a good idea to implement the context interface again. We put it
// here temporarily.
impl<'a> InternalRefContext<'a> {
    pub fn log(
        &mut self, params: &ActionParams, spec: &Spec, topics: Vec<H256>,
        data: Vec<u8>,
    ) -> vm::Result<()> {
        use primitives::log_entry::LogEntry;

        if self.static_flag || self.callstack.in_reentrancy(spec) {
            return Err(vm::Error::MutableCallInStaticContext);
        }

        let address = params.address;
        self.substate.logs.push(LogEntry {
            address,
            topics,
            data,
            space: params.space,
        });

        Ok(())
    }

    pub fn set_storage(
        &mut self, params: &ActionParams, key: Vec<u8>, value: U256,
    ) -> vm::Result<()> {
        let receiver = params.address.with_space(params.space);
        self.state
            .set_storage(
                &receiver,
                key,
                value,
                params.storage_owner,
                self.substate,
            )
            .map_err(|e| e.into())
    }

    pub fn storage_at(
        &mut self, params: &ActionParams, key: &[u8],
    ) -> DbResult<U256> {
        let receiver = params.address.with_space(params.space);
        self.state.storage_at(&receiver, key).map_err(|e| e.into())
    }

    pub fn is_contract_address(&self, address: &Address) -> vm::Result<bool> {
        Ok(address.is_contract_address())
    }
}