[Beta] Backports (#7945)
* ECIP 1041 - Remove Difficulty Bomb (#7905) Enable difficulty bomb defusion at block: - 5900000 on Ethereum Classic mainnet, - 2300000 on morden testnet. Reference: https://github.com/ethereumproject/ECIPs/blob/master/ECIPs/ECIP-1041.md * spec: Validate required divisor fields are not 0 (#7933) * Add validate_non_zero function It's used to validate that a Spec's uint field used as a divisor is not zero. * Add deserialize_with to gas_limit_bound_divisor Prevents panics due to divide-by-zero on the gas_limit_bound_divisor field. * Add deserialize_with to difficulty_bound_divisor Prevents panics due to divide-by-zero on the difficulty_bound_divisor field. * Add validate_optional_non_zero function Used to validate Option<Uint> divisor fields. * Use deserialize_with on optional divisor fields. * Add #[serde(default)] attribute to divisor fields When using `#[serde(deserialize_with)]`, `#[serde(default)]` must be specified so that missing fields can be deserialized with the deserializer for `None`. * Kovan WASM fork code (#7849) * kovan fork code * introduce ethcore level vm_factory and let it fail * fix json tests * wasmcosts as option * review changes * wasm costs in parser * fix evm tests * review fixes * fix test * remove redundant json field
This commit is contained in:
@@ -50,9 +50,9 @@ use encoded;
|
||||
use engines::{EthEngine, EpochTransition};
|
||||
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
|
||||
use vm::{EnvInfo, LastHashes};
|
||||
use evm::{Factory as EvmFactory, Schedule};
|
||||
use evm::Schedule;
|
||||
use executive::{Executive, Executed, TransactOptions, contract_address};
|
||||
use factory::Factories;
|
||||
use factory::{Factories, VmFactory};
|
||||
use futures::{future, Future};
|
||||
use header::{BlockNumber, Header};
|
||||
use io::*;
|
||||
@@ -189,7 +189,7 @@ impl Client {
|
||||
|
||||
let trie_factory = TrieFactory::new(trie_spec);
|
||||
let factories = Factories {
|
||||
vm: EvmFactory::new(config.vm_type.clone(), config.jump_table_size),
|
||||
vm: VmFactory::new(config.vm_type.clone(), config.jump_table_size),
|
||||
trie: trie_factory,
|
||||
accountdb: Default::default(),
|
||||
};
|
||||
@@ -1910,7 +1910,7 @@ impl MiningBlockChainClient for Client {
|
||||
block
|
||||
}
|
||||
|
||||
fn vm_factory(&self) -> &EvmFactory {
|
||||
fn vm_factory(&self) -> &VmFactory {
|
||||
&self.factories.vm
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,11 @@ use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use bigint::prelude::U256;
|
||||
use bigint::hash::H256;
|
||||
use journaldb;
|
||||
use {trie, kvdb_memorydb, bytes};
|
||||
use {factory, journaldb, trie, kvdb_memorydb, bytes};
|
||||
use kvdb::{self, KeyValueDB};
|
||||
use {state, state_db, client, executive, trace, transaction, db, spec, pod_state};
|
||||
use factory::Factories;
|
||||
use evm::{self, VMType, FinalizationResult};
|
||||
use evm::{VMType, FinalizationResult};
|
||||
use vm::{self, ActionParams};
|
||||
|
||||
/// EVM test Error.
|
||||
@@ -120,7 +119,7 @@ impl<'a> EvmTestClient<'a> {
|
||||
|
||||
fn factories() -> Factories {
|
||||
Factories {
|
||||
vm: evm::Factory::new(VMType::Interpreter, 5 * 1024),
|
||||
vm: factory::VmFactory::new(VMType::Interpreter, 5 * 1024),
|
||||
trie: trie::TrieFactory::new(trie::TrieSpec::Secure),
|
||||
accountdb: Default::default(),
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@ use log_entry::LocalizedLogEntry;
|
||||
use receipt::{Receipt, LocalizedReceipt, TransactionOutcome};
|
||||
use blockchain::extras::BlockReceipts;
|
||||
use error::{ImportResult, Error as EthcoreError};
|
||||
use evm::{Factory as EvmFactory, VMType};
|
||||
use evm::VMType;
|
||||
use factory::VmFactory;
|
||||
use vm::Schedule;
|
||||
use miner::{Miner, MinerService, TransactionImportResult};
|
||||
use spec::Spec;
|
||||
@@ -98,7 +99,7 @@ pub struct TestBlockChainClient {
|
||||
/// Spec
|
||||
pub spec: Spec,
|
||||
/// VM Factory
|
||||
pub vm_factory: EvmFactory,
|
||||
pub vm_factory: VmFactory,
|
||||
/// Timestamp assigned to latest sealed block
|
||||
pub latest_block_timestamp: RwLock<u64>,
|
||||
/// Ancient block info.
|
||||
@@ -169,7 +170,7 @@ impl TestBlockChainClient {
|
||||
queue_size: AtomicUsize::new(0),
|
||||
miner: Arc::new(Miner::with_spec(&spec)),
|
||||
spec: spec,
|
||||
vm_factory: EvmFactory::new(VMType::Interpreter, 1024 * 1024),
|
||||
vm_factory: VmFactory::new(VMType::Interpreter, 1024 * 1024),
|
||||
latest_block_timestamp: RwLock::new(10_000_000),
|
||||
ancient_block: RwLock::new(None),
|
||||
first_block: RwLock::new(None),
|
||||
@@ -399,7 +400,7 @@ impl MiningBlockChainClient for TestBlockChainClient {
|
||||
block.reopen(&*self.spec.engine)
|
||||
}
|
||||
|
||||
fn vm_factory(&self) -> &EvmFactory {
|
||||
fn vm_factory(&self) -> &VmFactory {
|
||||
&self.vm_factory
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ use block::{OpenBlock, SealedBlock, ClosedBlock};
|
||||
use blockchain::TreeRoute;
|
||||
use encoded;
|
||||
use vm::LastHashes;
|
||||
use error::{ImportResult, CallError, Error as EthcoreError};
|
||||
use error::{TransactionImportResult, BlockImportError};
|
||||
use evm::{Factory as EvmFactory, Schedule};
|
||||
use error::{ImportResult, CallError, Error as EthcoreError, TransactionImportResult, BlockImportError};
|
||||
use evm::Schedule;
|
||||
use factory::VmFactory;
|
||||
use executive::Executed;
|
||||
use filter::Filter;
|
||||
use header::{BlockNumber};
|
||||
@@ -298,7 +298,7 @@ pub trait MiningBlockChainClient: BlockChainClient {
|
||||
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock;
|
||||
|
||||
/// Returns EvmFactory.
|
||||
fn vm_factory(&self) -> &EvmFactory;
|
||||
fn vm_factory(&self) -> &VmFactory;
|
||||
|
||||
/// Broadcast a block proposal.
|
||||
fn broadcast_proposal_block(&self, block: SealedBlock);
|
||||
|
||||
@@ -390,11 +390,6 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
|
||||
self.machine().verify_transaction_basic(t, header)
|
||||
}
|
||||
|
||||
/// If this machine supports wasm.
|
||||
fn supports_wasm(&self) -> bool {
|
||||
self.machine().supports_wasm()
|
||||
}
|
||||
|
||||
/// Additional information.
|
||||
fn additional_params(&self) -> HashMap<String, String> {
|
||||
self.machine().additional_params()
|
||||
|
||||
@@ -141,6 +141,9 @@ pub fn new_constantinople_test_machine() -> EthereumMachine { load_machine(inclu
|
||||
/// Create a new Musicoin-MCIP3-era spec.
|
||||
pub fn new_mcip3_test_machine() -> EthereumMachine { load_machine(include_bytes!("../../res/ethereum/mcip3_test.json")) }
|
||||
|
||||
/// Create new Kovan spec with wasm activated at certain block
|
||||
pub fn new_kovan_wasm_test_machine() -> EthereumMachine { load_machine(include_bytes!("../../res/ethereum/kovan_wasm_test.json")) }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bigint::prelude::U256;
|
||||
|
||||
@@ -24,11 +24,12 @@ use util::*;
|
||||
use bytes::{Bytes, BytesRef};
|
||||
use state::{Backend as StateBackend, State, Substate, CleanupMode};
|
||||
use machine::EthereumMachine as Machine;
|
||||
use vm::EnvInfo;
|
||||
use error::ExecutionError;
|
||||
use evm::{CallType, Factory, Finalize, FinalizationResult};
|
||||
use vm::{self, Ext, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, ActionValue};
|
||||
use wasm;
|
||||
use evm::{CallType, Finalize, FinalizationResult};
|
||||
use vm::{
|
||||
self, Ext, EnvInfo, CreateContractAddress, ReturnData, CleanDustMode, ActionParams,
|
||||
ActionValue, Schedule,
|
||||
};
|
||||
use externalities::*;
|
||||
use trace::{self, Tracer, VMTracer};
|
||||
use transaction::{Action, SignedTransaction};
|
||||
@@ -40,8 +41,6 @@ pub use executed::{Executed, ExecutionResult};
|
||||
/// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp`
|
||||
const STACK_SIZE_PER_DEPTH: usize = 24*1024;
|
||||
|
||||
const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm";
|
||||
|
||||
/// Returns new address created from address, nonce, and code hash
|
||||
pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address, nonce: &U256, code: &[u8]) -> (Address, Option<H256>) {
|
||||
use rlp::RlpStream;
|
||||
@@ -154,14 +153,6 @@ impl TransactOptions<trace::NoopTracer, trace::NoopVMTracer> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn executor(machine: &Machine, vm_factory: &Factory, params: &ActionParams) -> Box<vm::Vm> {
|
||||
if machine.supports_wasm() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) {
|
||||
Box::new(wasm::WasmInterpreter)
|
||||
} else {
|
||||
vm_factory.create(params.gas)
|
||||
}
|
||||
}
|
||||
|
||||
/// Transaction executor.
|
||||
pub struct Executive<'a, B: 'a + StateBackend> {
|
||||
state: &'a mut State<B>,
|
||||
@@ -336,6 +327,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
|
||||
fn exec_vm<T, V>(
|
||||
&mut self,
|
||||
schedule: Schedule,
|
||||
params: ActionParams,
|
||||
unconfirmed_substate: &mut Substate,
|
||||
output_policy: OutputPolicy,
|
||||
@@ -351,19 +343,20 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
let vm_factory = self.state.vm_factory();
|
||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
|
||||
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
|
||||
return executor(self.machine, &vm_factory, ¶ms).exec(params, &mut ext).finalize(ext);
|
||||
let mut vm = vm_factory.create(¶ms, &schedule);
|
||||
return vm.exec(params, &mut ext).finalize(ext);
|
||||
}
|
||||
|
||||
// Start in new thread to reset stack
|
||||
// TODO [todr] No thread builder yet, so we need to reset once for a while
|
||||
// https://github.com/aturon/crossbeam/issues/16
|
||||
crossbeam::scope(|scope| {
|
||||
let machine = self.machine;
|
||||
let vm_factory = self.state.vm_factory();
|
||||
let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
|
||||
|
||||
scope.spawn(move || {
|
||||
executor(machine, &vm_factory, ¶ms).exec(params, &mut ext).finalize(ext)
|
||||
let mut vm = vm_factory.create(¶ms, &schedule);
|
||||
vm.exec(params, &mut ext).finalize(ext)
|
||||
})
|
||||
}).join()
|
||||
}
|
||||
@@ -473,7 +466,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("scope is conditional on params.code.is_some(); qed"));
|
||||
|
||||
let res = {
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
||||
self.exec_vm(schedule, params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
||||
};
|
||||
|
||||
vm_tracer.done_subtrace(subvmtracer);
|
||||
@@ -564,9 +557,14 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
||||
|
||||
let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed"));
|
||||
|
||||
let res = {
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), &mut subtracer, &mut subvmtracer)
|
||||
};
|
||||
let res = self.exec_vm(
|
||||
schedule,
|
||||
params,
|
||||
&mut unconfirmed_substate,
|
||||
OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())),
|
||||
&mut subtracer,
|
||||
&mut subvmtracer
|
||||
);
|
||||
|
||||
vm_tracer.done_subtrace(subvmtracer);
|
||||
|
||||
@@ -1485,8 +1483,6 @@ mod tests {
|
||||
params.gas = U256::from(20025);
|
||||
params.code = Some(Arc::new(code));
|
||||
params.value = ActionValue::Transfer(U256::zero());
|
||||
let mut state = get_temp_state_with_factory(factory);
|
||||
state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap();
|
||||
let info = EnvInfo::default();
|
||||
let machine = ::ethereum::new_byzantium_test_machine();
|
||||
let mut substate = Substate::new();
|
||||
@@ -1501,4 +1497,60 @@ mod tests {
|
||||
assert_eq!(output[..], returns[..]);
|
||||
assert_eq!(state.storage_at(&contract_address, &H256::from(&U256::zero())).unwrap(), H256::from(&U256::from(0)));
|
||||
}
|
||||
|
||||
fn wasm_sample_code() -> Arc<Vec<u8>> {
|
||||
Arc::new(
|
||||
"0061736d01000000010d0360027f7f0060017f0060000002270303656e7603726574000003656e760673656e646572000103656e76066d656d6f727902010110030201020404017000000501000708010463616c6c00020901000ac10101be0102057f017e4100410028020441c0006b22043602042004412c6a41106a220041003602002004412c6a41086a22014200370200200441186a41106a22024100360200200441186a41086a220342003703002004420037022c2004410036021c20044100360218200441186a1001200020022802002202360200200120032903002205370200200441106a2002360200200441086a200537030020042004290318220537022c200420053703002004411410004100200441c0006a3602040b0b0a010041040b0410c00000"
|
||||
.from_hex()
|
||||
.unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wasm_activated_test() {
|
||||
let contract_address = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
|
||||
let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
|
||||
let mut state = get_temp_state();
|
||||
state.add_balance(&sender, &U256::from(10000000000u64), CleanupMode::NoEmpty).unwrap();
|
||||
state.commit().unwrap();
|
||||
|
||||
let mut params = ActionParams::default();
|
||||
params.origin = sender.clone();
|
||||
params.sender = sender.clone();
|
||||
params.address = contract_address.clone();
|
||||
params.gas = U256::from(20025);
|
||||
params.code = Some(wasm_sample_code());
|
||||
|
||||
let mut info = EnvInfo::default();
|
||||
|
||||
// 100 > 10
|
||||
info.number = 100;
|
||||
|
||||
// Network with wasm activated at block 10
|
||||
let machine = ::ethereum::new_kovan_wasm_test_machine();
|
||||
|
||||
let mut output = [0u8; 20];
|
||||
let FinalizationResult { gas_left: result, .. } = {
|
||||
let mut ex = Executive::new(&mut state, &info, &machine);
|
||||
ex.call(params.clone(), &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(result, U256::from(18433));
|
||||
// Transaction successfully returned sender
|
||||
assert_eq!(output[..], sender[..]);
|
||||
|
||||
// 1 < 10
|
||||
info.number = 1;
|
||||
|
||||
let mut output = [0u8; 20];
|
||||
let FinalizationResult { gas_left: result, .. } = {
|
||||
let mut ex = Executive::new(&mut state, &info, &machine);
|
||||
ex.call(params, &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(result, U256::from(20025));
|
||||
// Since transaction errored due to wasm was not activated, result is just empty
|
||||
assert_eq!(output[..], [0u8; 20][..]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,44 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use trie::TrieFactory;
|
||||
use evm::Factory as EvmFactory;
|
||||
use account_db::Factory as AccountFactory;
|
||||
use evm::{Factory as EvmFactory, VMType};
|
||||
use vm::{Vm, ActionParams, Schedule};
|
||||
use wasm::WasmInterpreter;
|
||||
|
||||
const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm";
|
||||
|
||||
/// Virtual machine factory
|
||||
#[derive(Default, Clone)]
|
||||
pub struct VmFactory {
|
||||
evm: EvmFactory,
|
||||
}
|
||||
|
||||
impl VmFactory {
|
||||
pub fn create(&self, params: &ActionParams, schedule: &Schedule) -> Box<Vm> {
|
||||
if schedule.wasm.is_some() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) {
|
||||
Box::new(WasmInterpreter)
|
||||
} else {
|
||||
self.evm.create(¶ms.gas)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(evm: VMType, cache_size: usize) -> Self {
|
||||
VmFactory { evm: EvmFactory::new(evm, cache_size) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EvmFactory> for VmFactory {
|
||||
fn from(evm: EvmFactory) -> Self {
|
||||
VmFactory { evm: evm }
|
||||
}
|
||||
}
|
||||
|
||||
/// Collection of factories.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Factories {
|
||||
/// factory for evm.
|
||||
pub vm: EvmFactory,
|
||||
pub vm: VmFactory,
|
||||
/// factory for tries.
|
||||
pub trie: TrieFactory,
|
||||
/// factory for account databases.
|
||||
|
||||
@@ -259,7 +259,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
||||
&mut tracer,
|
||||
&mut vm_tracer,
|
||||
));
|
||||
let mut evm = vm_factory.create(params.gas);
|
||||
let mut evm = vm_factory.create(¶ms, &machine.schedule(0u64.into()));
|
||||
let res = evm.exec(params, &mut ex);
|
||||
// a return in finalize will not alter callcreates
|
||||
let callcreates = ex.callcreates.clone();
|
||||
|
||||
@@ -377,11 +377,6 @@ impl EthereumMachine {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// If this machine supports wasm.
|
||||
pub fn supports_wasm(&self) -> bool {
|
||||
self.params().wasm
|
||||
}
|
||||
|
||||
/// Additional params.
|
||||
pub fn additional_params(&self) -> HashMap<String, String> {
|
||||
hash_map![
|
||||
|
||||
@@ -110,8 +110,8 @@ pub struct CommonParams {
|
||||
pub nonce_cap_increment: u64,
|
||||
/// Enable dust cleanup for contracts.
|
||||
pub remove_dust_contracts: bool,
|
||||
/// Wasm support
|
||||
pub wasm: bool,
|
||||
/// Wasm activation blocknumber, if any disabled initially.
|
||||
pub wasm_activation_transition: BlockNumber,
|
||||
/// Gas limit bound divisor (how much gas limit can change per block)
|
||||
pub gas_limit_bound_divisor: U256,
|
||||
/// Registrar contract address.
|
||||
@@ -147,6 +147,9 @@ impl CommonParams {
|
||||
false => ::vm::CleanDustMode::BasicOnly,
|
||||
};
|
||||
}
|
||||
if block_number >= self.wasm_activation_transition {
|
||||
schedule.wasm = Some(Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether these params contain any bug-fix hard forks.
|
||||
@@ -221,12 +224,15 @@ impl From<ethjson::spec::Params> for CommonParams {
|
||||
),
|
||||
nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into),
|
||||
remove_dust_contracts: p.remove_dust_contracts.unwrap_or(false),
|
||||
wasm: p.wasm.unwrap_or(false),
|
||||
gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(),
|
||||
registrar: p.registrar.map_or_else(Address::new, Into::into),
|
||||
node_permission_contract: p.node_permission_contract.map(Into::into),
|
||||
max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into),
|
||||
transaction_permission_contract: p.transaction_permission_contract.map(Into::into),
|
||||
wasm_activation_transition: p.wasm_activation_transition.map_or(
|
||||
BlockNumber::max_value(),
|
||||
Into::into
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ use executed::{Executed, ExecutionError};
|
||||
use types::state_diff::StateDiff;
|
||||
use transaction::SignedTransaction;
|
||||
use state_db::StateDB;
|
||||
use evm::{Factory as EvmFactory};
|
||||
use factory::VmFactory;
|
||||
|
||||
use bigint::prelude::U256;
|
||||
use bigint::hash::H256;
|
||||
@@ -376,7 +376,7 @@ impl<B: Backend> State<B> {
|
||||
}
|
||||
|
||||
/// Get a VM factory that can execute on this state.
|
||||
pub fn vm_factory(&self) -> EvmFactory {
|
||||
pub fn vm_factory(&self) -> VmFactory {
|
||||
self.factories.vm.clone()
|
||||
}
|
||||
|
||||
|
||||
@@ -275,7 +275,7 @@ pub fn get_temp_state() -> State<::state_db::StateDB> {
|
||||
pub fn get_temp_state_with_factory(factory: EvmFactory) -> State<::state_db::StateDB> {
|
||||
let journal_db = get_temp_state_db();
|
||||
let mut factories = Factories::default();
|
||||
factories.vm = factory;
|
||||
factories.vm = factory.into();
|
||||
State::new(journal_db, U256::from(0), factories)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user