diff --git a/Cargo.toml b/Cargo.toml index b35ee27d..79b96fad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ std = [ "evm-gasometer/std", "evm-runtime/std", ] +allow_explicit_address = [] with-codec = [ "scale-codec", "scale-info", diff --git a/README.md b/README.md index dd1378a1..79651fda 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,17 @@ * written in Rust, can be used as a binary, cargo crate or shared library +### Feature Flags + +SputnikVM provides optional feature flags to enable specific functionalities: + +- `allow_explicit_address` +Enables the `transact_create_force_address` method, allowing contract creation with a predefined address. +- `with-codec` +- `with-serde` +- `tracing` +- `force-debug` + ## Dependencies Ensure you have at least `rustc 1.51.0 (2fd73fabe 2021-03-23)`. Rust 1.50.0 and diff --git a/src/executor/stack/executor.rs b/src/executor/stack/executor.rs index aa79c2b8..b02d9b05 100644 --- a/src/executor/stack/executor.rs +++ b/src/executor/stack/executor.rs @@ -550,6 +550,55 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> } } + /// Execute a `CREATE` transaction that force the contract address + #[cfg(feature = "allow_explicit_address")] + pub fn transact_create_force_address( + &mut self, + caller: H160, + value: U256, + init_code: Vec<u8>, + gas_limit: u64, + access_list: Vec<(H160, Vec<H256>)>, // See EIP-2930 + contract_address: H160, + ) -> (ExitReason, Vec<u8>) { + event!(TransactCreate { + caller, + value, + init_code: &init_code, + gas_limit, + address: self.create_address(CreateScheme::Fixed(contract_address)), + }); + + if let Some(limit) = self.config.max_initcode_size { + if init_code.len() > limit { + self.state.metadata_mut().gasometer.fail(); + return emit_exit!(ExitError::CreateContractLimit.into(), Vec::new()); + } + } + + if let Err(e) = self.record_create_transaction_cost(&init_code, &access_list) { + return emit_exit!(e.into(), Vec::new()); + } + self.initialize_with_access_list(access_list); + + match self.create_inner( + caller, + CreateScheme::Fixed(contract_address), + value, + init_code, + Some(gas_limit), + false, + ) { + Capture::Exit((s, _, v)) => emit_exit!(s, v), + Capture::Trap(rt) => { + let mut cs = Vec::with_capacity(DEFAULT_CALL_STACK_CAPACITY); + cs.push(rt.0); + let (s, _, v) = self.execute_with_call_stack(&mut cs); + emit_exit!(s, v) + } + } + } + /// Execute a `CALL` transaction with a given caller, address, value and /// gas limit and data. ///