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
77
78
79
80
81
82
use std::collections::BTreeMap;

use cfx_types::{Address, AddressWithSpace, Space};
use cfx_vm_types::Spec;
use primitives::BlockNumber;

use super::{super::contracts::all_internal_contracts, InternalContractTrait};
use crate::spec::CommonParams;

#[derive(Default)]
pub struct InternalContractMap {
    builtin: BTreeMap<Address, Box<dyn InternalContractTrait>>,
    activation_info: BTreeMap<BlockNumber, Vec<Address>>,
}

impl std::ops::Deref for InternalContractMap {
    type Target = BTreeMap<Address, Box<dyn InternalContractTrait>>;

    fn deref(&self) -> &Self::Target { &self.builtin }
}

impl InternalContractMap {
    pub fn new(params: &CommonParams) -> Self {
        let mut builtin = BTreeMap::new();
        let mut activation_info = BTreeMap::new();
        // We should initialize all the internal contracts here. Even if not all
        // of them are activated at the genesis block. The activation of the
        // internal contracts are controlled by the `CommonParams` and
        // `vm::Spec`.
        let mut internal_contracts = all_internal_contracts();

        while let Some(contract) = internal_contracts.pop() {
            let address = *contract.address();
            let transition_block = if params.early_set_internal_contracts_states
            {
                0
            } else {
                contract.initialize_block(params)
            };

            builtin.insert(*contract.address(), contract);
            activation_info
                .entry(transition_block)
                .or_insert(vec![])
                .push(address);
        }

        Self {
            builtin,
            activation_info,
        }
    }

    #[cfg(test)]
    pub fn initialize_for_test() -> Vec<Address> {
        all_internal_contracts()
            .iter()
            .map(|contract| *contract.address())
            .collect()
    }

    pub fn initialized_at_genesis(&self) -> &[Address] {
        self.initialized_at(0)
    }

    pub fn initialized_at(&self, number: BlockNumber) -> &[Address] {
        self.activation_info
            .get(&number)
            .map_or(&[], |vec| vec.as_slice())
    }

    pub fn contract(
        &self, address: &AddressWithSpace, spec: &Spec,
    ) -> Option<&Box<dyn InternalContractTrait>> {
        if address.space != Space::Native {
            return None;
        }
        self.builtin
            .get(&address.address)
            .filter(|&contract| contract.is_active(spec))
    }
}