cfx_vm_interpreter/
factory.rs

1// Copyright 2015-2018 Parity Technologies (UK) Ltd.
2// This file is part of Parity.
3
4// Parity is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
16
17// Copyright 2019 Conflux Foundation. All rights reserved.
18// Conflux is free software and distributed under GNU General Public License.
19// See http://www.gnu.org/licenses/
20
21//! Evm factory.
22use super::{
23    interpreter::{Interpreter, SharedCache},
24    vmtype::VMType,
25};
26use cfx_types::U256;
27#[cfg(test)]
28use cfx_vm_types::CallType;
29use cfx_vm_types::{ActionParams, Exec, Spec};
30use std::sync::Arc;
31
32/// Evm factory. Creates appropriate Evm.
33#[derive(Clone)]
34pub struct Factory {
35    evm: VMType,
36    evm_cache: Arc<SharedCache<false>>,
37    evm_cache_cancun: Arc<SharedCache<true>>,
38}
39
40impl Factory {
41    /// Create fresh instance of VM
42    /// Might choose implementation depending on supplied gas.
43    pub fn create(
44        &self, params: ActionParams, spec: &Spec, depth: usize,
45    ) -> Box<dyn Exec> {
46        // Assert there is only one type. Parity Ethereum is dead and no more
47        // types will be added.
48        match self.evm {
49            VMType::Interpreter => {}
50        };
51
52        match (Self::can_fit_in_usize(&params.gas), spec.cancun_opcodes) {
53            (true, true) => Box::new(Interpreter::<usize, true>::new(
54                params,
55                self.evm_cache_cancun.clone(),
56                spec,
57                depth,
58            )),
59            (true, false) => Box::new(Interpreter::<usize, false>::new(
60                params,
61                self.evm_cache.clone(),
62                spec,
63                depth,
64            )),
65            (false, true) => Box::new(Interpreter::<U256, true>::new(
66                params,
67                self.evm_cache_cancun.clone(),
68                spec,
69                depth,
70            )),
71            (false, false) => Box::new(Interpreter::<U256, false>::new(
72                params,
73                self.evm_cache.clone(),
74                spec,
75                depth,
76            )),
77        }
78    }
79
80    /// Create new instance of specific `VMType` factory, with a size in bytes
81    /// for caching jump destinations.
82    pub fn new(evm: VMType, cache_size: usize) -> Self {
83        Factory {
84            evm,
85            evm_cache: Arc::new(SharedCache::new(cache_size)),
86            evm_cache_cancun: Arc::new(SharedCache::new(cache_size)),
87        }
88    }
89
90    fn can_fit_in_usize(gas: &U256) -> bool {
91        gas == &U256::from(gas.low_u64() as usize)
92    }
93}
94
95impl Default for Factory {
96    /// Returns native rust evm factory
97    fn default() -> Factory {
98        Factory {
99            evm: VMType::Interpreter,
100            evm_cache: Arc::new(SharedCache::default()),
101            evm_cache_cancun: Arc::new(SharedCache::default()),
102        }
103    }
104}
105
106#[test]
107fn test_create_vm() {
108    use cfx_bytes::Bytes;
109    use cfx_vm_types::{tests::MockContext, Context};
110
111    let mut params = ActionParams::default();
112    params.call_type = CallType::None;
113    params.code = Some(Arc::new(Bytes::default()));
114    let context = MockContext::new();
115    let _vm =
116        Factory::default().create(params, context.spec(), context.depth());
117}
118
119/// Create tests by injecting different VM factories
120#[macro_export]
121macro_rules! evm_test(
122	($name_test: ident: $name_int: ident) => {
123		#[test]
124		fn $name_int() {
125			$name_test(Factory::new(VMType::Interpreter, 1024 * 32));
126		}
127	}
128);
129
130/// Create ignored tests by injecting different VM factories
131#[macro_export]
132macro_rules! evm_test_ignore(
133	($name_test: ident: $name_int: ident) => {
134		#[test]
135		#[ignore]
136		#[cfg(feature = "ignored-tests")]
137		fn $name_int() {
138			$name_test(Factory::new(VMType::Interpreter, 1024 * 32));
139		}
140	}
141);