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