cfx_executor/machine/
mod.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
5mod vm_factory;
6
7use super::builtin::Builtin;
8use crate::{
9    builtin::{
10        build_bls12_builtin_map, builtin_factory, AltBn128PairingPricer,
11        Blake2FPricer, IfPricer, Linear, ModexpPricer, StaticPlan,
12    },
13    internal_contract::InternalContractMap,
14    spec::CommonParams,
15};
16use cfx_types::{Address, AddressWithSpace, Space, H256};
17use cfx_vm_types::Spec;
18use primitives::{block::BlockHeight, BlockNumber};
19use std::{collections::BTreeMap, sync::Arc};
20
21pub use vm_factory::VmFactory;
22pub type SpecCreationRules = dyn Fn(&mut Spec, BlockNumber) + Sync + Send;
23
24pub struct Machine {
25    params: CommonParams,
26    vm_factory: VmFactory,
27    builtins: Arc<BTreeMap<Address, Builtin>>,
28    builtins_evm: Arc<BTreeMap<Address, Builtin>>,
29    internal_contracts: Arc<InternalContractMap>,
30    #[cfg(test)]
31    max_depth: Option<usize>,
32}
33
34impl Machine {
35    pub fn new(params: CommonParams, vm_factory: VmFactory) -> Machine {
36        Machine {
37            params,
38            vm_factory,
39            builtins: Arc::new(BTreeMap::new()),
40            builtins_evm: Arc::new(Default::default()),
41            internal_contracts: Arc::new(InternalContractMap::default()),
42            #[cfg(test)]
43            max_depth: None,
44        }
45    }
46
47    pub fn new_with_builtin(
48        params: CommonParams, vm_factory: VmFactory,
49    ) -> Machine {
50        let builtin = new_builtin_map(&params, Space::Native);
51        let builtin_evm = new_builtin_map(&params, Space::Ethereum);
52
53        let internal_contracts = InternalContractMap::new(&params);
54        Machine {
55            params,
56            vm_factory,
57            builtins: Arc::new(builtin),
58            builtins_evm: Arc::new(builtin_evm),
59            internal_contracts: Arc::new(internal_contracts),
60            #[cfg(test)]
61            max_depth: None,
62        }
63    }
64
65    pub fn builtin(
66        &self, address: &AddressWithSpace, block_number: BlockNumber,
67    ) -> Option<&Builtin> {
68        let builtins = match address.space {
69            Space::Native => &self.builtins,
70            Space::Ethereum => &self.builtins_evm,
71        };
72        builtins.get(&address.address).and_then(|b| {
73            if b.is_active(block_number) {
74                Some(b)
75            } else {
76                None
77            }
78        })
79    }
80
81    /// Get the general parameters of the chain.
82    pub fn params(&self) -> &CommonParams { &self.params }
83
84    pub fn spec(&self, number: BlockNumber, height: BlockHeight) -> Spec {
85        self.params.spec(number, height)
86    }
87
88    #[cfg(test)]
89    pub fn set_max_depth(&mut self, max_depth: usize) {
90        self.max_depth = Some(max_depth)
91    }
92
93    #[cfg(test)]
94    pub fn spec_for_test(&self, number: u64) -> Spec {
95        let mut spec = self.spec(number, number);
96        if let Some(max_depth) = self.max_depth {
97            spec.max_depth = max_depth;
98        }
99        spec
100    }
101
102    /// Builtin-contracts for the chain..
103    pub fn builtins(&self) -> &BTreeMap<Address, Builtin> { &*self.builtins }
104
105    pub fn builtins_evm(&self) -> &BTreeMap<Address, Builtin> {
106        &*self.builtins_evm
107    }
108
109    /// Builtin-contracts for the chain..
110    pub fn internal_contracts(&self) -> &InternalContractMap {
111        &*self.internal_contracts
112    }
113
114    /// Get a VM factory that can execute on this state.
115    pub fn vm_factory(&self) -> VmFactory { self.vm_factory.clone() }
116
117    pub fn vm_factory_ref(&self) -> &VmFactory { &self.vm_factory }
118}
119
120fn new_builtin_map(
121    params: &CommonParams, space: Space,
122) -> BTreeMap<Address, Builtin> {
123    let mut btree = BTreeMap::new();
124
125    btree.insert(
126        Address::from(H256::from_low_u64_be(1)),
127        Builtin::new(
128            Box::new(StaticPlan(Linear::new(3000, 0))),
129            match space {
130                Space::Native => builtin_factory("ecrecover"),
131                Space::Ethereum => builtin_factory("ecrecover_evm"),
132            },
133            0,
134        ),
135    );
136    btree.insert(
137        Address::from(H256::from_low_u64_be(2)),
138        Builtin::new(
139            Box::new(StaticPlan(Linear::new(60, 12))),
140            builtin_factory("sha256"),
141            0,
142        ),
143    );
144    btree.insert(
145        Address::from(H256::from_low_u64_be(3)),
146        Builtin::new(
147            Box::new(StaticPlan(Linear::new(600, 120))),
148            builtin_factory("ripemd160"),
149            0,
150        ),
151    );
152    btree.insert(
153        Address::from(H256::from_low_u64_be(4)),
154        Builtin::new(
155            Box::new(StaticPlan(Linear::new(15, 3))),
156            builtin_factory("identity"),
157            0,
158        ),
159    );
160
161    // CIP-645e: EIP-2565
162    let mod_exp_pricer = IfPricer::new(
163        |spec| spec.cip645.eip2565,
164        ModexpPricer::new_berlin(200),
165        ModexpPricer::new_byzantium(20),
166    );
167    btree.insert(
168        Address::from(H256::from_low_u64_be(5)),
169        Builtin::new(
170            Box::new(mod_exp_pricer),
171            builtin_factory("modexp"),
172            params.transition_numbers.cip62,
173        ),
174    );
175
176    // CIP-645a: EIP-1108
177    let bn_add_pricer = IfPricer::new(
178        |spec| spec.cip645.eip1108,
179        Linear::new(150, 0),
180        Linear::new(500, 0),
181    );
182    btree.insert(
183        Address::from(H256::from_low_u64_be(6)),
184        Builtin::new(
185            Box::new(bn_add_pricer),
186            builtin_factory("alt_bn128_add"),
187            params.transition_numbers.cip62,
188        ),
189    );
190
191    // CIP-645a: EIP-1108
192    let bn_mul_pricer = IfPricer::new(
193        |spec| spec.cip645.eip1108,
194        Linear::new(6_000, 0),
195        Linear::new(40_000, 0),
196    );
197    btree.insert(
198        Address::from(H256::from_low_u64_be(7)),
199        Builtin::new(
200            Box::new(bn_mul_pricer),
201            builtin_factory("alt_bn128_mul"),
202            params.transition_numbers.cip62,
203        ),
204    );
205
206    // CIP-645a: EIP-1108
207    let bn_pair_pricer = IfPricer::new(
208        |spec| spec.cip645.eip1108,
209        AltBn128PairingPricer::new(45_000, 34_000),
210        AltBn128PairingPricer::new(100_000, 80_000),
211    );
212    btree.insert(
213        Address::from(H256::from_low_u64_be(8)),
214        Builtin::new(
215            Box::new(bn_pair_pricer),
216            builtin_factory("alt_bn128_pairing"),
217            params.transition_numbers.cip62,
218        ),
219    );
220    btree.insert(
221        Address::from(H256::from_low_u64_be(9)),
222        Builtin::new(
223            Box::new(StaticPlan(Blake2FPricer::new(1))),
224            builtin_factory("blake2_f"),
225            params.transition_numbers.cip92,
226        ),
227    );
228    btree.insert(
229        Address::from(H256::from_low_u64_be(10)),
230        Builtin::new(
231            Box::new(StaticPlan(Linear::new(50000, 0))),
232            builtin_factory("kzg_point_eval"),
233            params.transition_numbers.cip144,
234        ),
235    );
236    for (address, price_plan, bls12_impl) in build_bls12_builtin_map() {
237        btree.insert(
238            Address::from(H256::from_low_u64_be(address)),
239            Builtin::new(
240                price_plan,
241                bls12_impl,
242                params.transition_heights.eip2537,
243            ),
244        );
245    }
246    btree
247}