1mod 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(¶ms, Space::Native);
51 let builtin_evm = new_builtin_map(¶ms, Space::Ethereum);
52
53 let internal_contracts = InternalContractMap::new(¶ms);
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 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 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 pub fn internal_contracts(&self) -> &InternalContractMap {
111 &*self.internal_contracts
112 }
113
114 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 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 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 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 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}