Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Commit e8b13cb

Browse files
authored
Implement KIP4: create2 for wasm (#9277)
* Basic implementation for kip4 * Add KIP-4 config flags * typo: docs fix * Fix args offset * Add tests for create2 * tests: evm * Update wasm-tests and fix all gas costs * Update wasm-tests * Update wasm-tests and fix gas costs
1 parent 3f2fd61 commit e8b13cb

File tree

11 files changed

+143
-58
lines changed

11 files changed

+143
-58
lines changed

ethcore/evm/src/tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ fn test_calls(factory: super::Factory) {
746746

747747
assert_set_contains(&ext.calls, &FakeCall {
748748
call_type: FakeCallType::Call,
749+
create_scheme: None,
749750
gas: U256::from(2556),
750751
sender_address: Some(address.clone()),
751752
receive_address: Some(code_address.clone()),
@@ -755,6 +756,7 @@ fn test_calls(factory: super::Factory) {
755756
});
756757
assert_set_contains(&ext.calls, &FakeCall {
757758
call_type: FakeCallType::Call,
759+
create_scheme: None,
758760
gas: U256::from(2556),
759761
sender_address: Some(address.clone()),
760762
receive_address: Some(address.clone()),

ethcore/res/wasm-tests

ethcore/src/spec/spec.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ pub struct CommonParams {
125125
pub remove_dust_contracts: bool,
126126
/// Wasm activation blocknumber, if any disabled initially.
127127
pub wasm_activation_transition: BlockNumber,
128+
/// Number of first block where KIP-4 rules begin. Only has effect if Wasm is activated.
129+
pub kip4_transition: BlockNumber,
128130
/// Gas limit bound divisor (how much gas limit can change per block)
129131
pub gas_limit_bound_divisor: U256,
130132
/// Registrar contract address.
@@ -187,7 +189,11 @@ impl CommonParams {
187189
};
188190
}
189191
if block_number >= self.wasm_activation_transition {
190-
schedule.wasm = Some(Default::default());
192+
let mut wasm = ::vm::WasmCosts::default();
193+
if block_number >= self.kip4_transition {
194+
wasm.have_create2 = true;
195+
}
196+
schedule.wasm = Some(wasm);
191197
}
192198
}
193199

@@ -294,6 +300,10 @@ impl From<ethjson::spec::Params> for CommonParams {
294300
BlockNumber::max_value,
295301
Into::into
296302
),
303+
kip4_transition: p.kip4_transition.map_or_else(
304+
BlockNumber::max_value,
305+
Into::into
306+
),
297307
}
298308
}
299309
}

ethcore/vm/src/ext.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub enum MessageCallResult {
5151
}
5252

5353
/// Specifies how an address is calculated for a new contract.
54-
#[derive(Copy, Clone, PartialEq, Eq)]
54+
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
5555
pub enum CreateContractAddress {
5656
/// Address is calculated from sender and nonce. Pre EIP-86 (Metropolis)
5757
FromSenderAndNonce,

ethcore/vm/src/schedule.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ pub struct WasmCosts {
149149
pub opcodes_mul: u32,
150150
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
151151
pub opcodes_div: u32,
152+
/// Whether create2 extern function is activated.
153+
pub have_create2: bool,
152154
}
153155

154156
impl Default for WasmCosts {
@@ -166,6 +168,7 @@ impl Default for WasmCosts {
166168
max_stack_height: 64*1024,
167169
opcodes_mul: 3,
168170
opcodes_div: 8,
171+
have_create2: false,
169172
}
170173
}
171174
}

ethcore/vm/src/tests.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub enum FakeCallType {
3939
#[derive(PartialEq, Eq, Hash, Debug)]
4040
pub struct FakeCall {
4141
pub call_type: FakeCallType,
42+
pub create_scheme: Option<CreateContractAddress>,
4243
pub gas: U256,
4344
pub sender_address: Option<Address>,
4445
pub receive_address: Option<Address>,
@@ -133,9 +134,10 @@ impl Ext for FakeExt {
133134
self.blockhashes.get(number).unwrap_or(&H256::new()).clone()
134135
}
135136

136-
fn create(&mut self, gas: &U256, value: &U256, code: &[u8], _address: CreateContractAddress) -> ContractCreateResult {
137+
fn create(&mut self, gas: &U256, value: &U256, code: &[u8], address: CreateContractAddress) -> ContractCreateResult {
137138
self.calls.insert(FakeCall {
138139
call_type: FakeCallType::Create,
140+
create_scheme: Some(address),
139141
gas: *gas,
140142
sender_address: None,
141143
receive_address: None,
@@ -159,6 +161,7 @@ impl Ext for FakeExt {
159161

160162
self.calls.insert(FakeCall {
161163
call_type: FakeCallType::Call,
164+
create_scheme: None,
162165
gas: *gas,
163166
sender_address: Some(sender_address.clone()),
164167
receive_address: Some(receive_address.clone()),

ethcore/wasm/src/env.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
//! Env module glue for wasmi interpreter
1818
1919
use std::cell::RefCell;
20+
use vm::WasmCosts;
2021
use wasmi::{
2122
self, Signature, Error, FuncRef, FuncInstance, MemoryDescriptor,
2223
MemoryRef, MemoryInstance, memory_units,
@@ -47,6 +48,7 @@ pub mod ids {
4748
pub const SENDER_FUNC: usize = 190;
4849
pub const ORIGIN_FUNC: usize = 200;
4950
pub const ELOG_FUNC: usize = 210;
51+
pub const CREATE2_FUNC: usize = 220;
5052

5153
pub const PANIC_FUNC: usize = 1000;
5254
pub const DEBUG_FUNC: usize = 1010;
@@ -125,6 +127,11 @@ pub mod signatures {
125127
Some(I32),
126128
);
127129

130+
pub const CREATE2: StaticSignature = StaticSignature(
131+
&[I32, I32, I32, I32, I32],
132+
Some(I32),
133+
);
134+
128135
pub const SUICIDE: StaticSignature = StaticSignature(
129136
&[I32],
130137
None,
@@ -195,18 +202,21 @@ fn host(signature: signatures::StaticSignature, idx: usize) -> FuncRef {
195202
/// Maps all functions that runtime support to the corresponding contract import
196203
/// entries.
197204
/// Also manages initial memory request from the runtime.
198-
#[derive(Default)]
199205
pub struct ImportResolver {
200206
max_memory: u32,
201207
memory: RefCell<Option<MemoryRef>>,
208+
209+
have_create2: bool,
202210
}
203211

204212
impl ImportResolver {
205213
/// New import resolver with specifed maximum amount of inital memory (in wasm pages = 64kb)
206-
pub fn with_limit(max_memory: u32) -> ImportResolver {
214+
pub fn with_limit(max_memory: u32, schedule: &WasmCosts) -> ImportResolver {
207215
ImportResolver {
208216
max_memory: max_memory,
209217
memory: RefCell::new(None),
218+
219+
have_create2: schedule.have_create2,
210220
}
211221
}
212222

@@ -263,6 +273,7 @@ impl wasmi::ModuleImportResolver for ImportResolver {
263273
"sender" => host(signatures::SENDER, ids::SENDER_FUNC),
264274
"origin" => host(signatures::ORIGIN, ids::ORIGIN_FUNC),
265275
"elog" => host(signatures::ELOG, ids::ELOG_FUNC),
276+
"create2" if self.have_create2 => host(signatures::CREATE2, ids::CREATE2_FUNC),
266277
_ => {
267278
return Err(wasmi::Error::Instantiation(
268279
format!("Export {} not found", field_name),

ethcore/wasm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl vm::Vm for WasmInterpreter {
9090

9191
let loaded_module = wasmi::Module::from_parity_wasm_module(module).map_err(Error::Interpreter)?;
9292

93-
let instantiation_resolver = env::ImportResolver::with_limit(16);
93+
let instantiation_resolver = env::ImportResolver::with_limit(16, ext.schedule().wasm());
9494

9595
let module_instance = wasmi::ModuleInstance::new(
9696
&loaded_module,

ethcore/wasm/src/runtime.rs

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ impl<'a> Runtime<'a> {
321321
if self.gas_counter > self.gas_limit { return Err(Error::InvalidGasState); }
322322
Ok(self.gas_limit - self.gas_counter)
323323
}
324-
324+
325325
/// General gas charging extern.
326326
fn gas(&mut self, args: RuntimeArgs) -> Result<()> {
327327
let amount: u32 = args.nth_checked(0)?;
@@ -511,29 +511,7 @@ impl<'a> Runtime<'a> {
511511
self.return_u256_ptr(args.nth_checked(0)?, val)
512512
}
513513

514-
/// Creates a new contract
515-
///
516-
/// Arguments:
517-
/// * endowment - how much value (in Wei) transfer to the newly created contract
518-
/// * code_ptr - pointer to the code data
519-
/// * code_len - lenght of the code data
520-
/// * result_ptr - pointer to write an address of the newly created contract
521-
pub fn create(&mut self, args: RuntimeArgs) -> Result<RuntimeValue>
522-
{
523-
//
524-
// method signature:
525-
// fn create(endowment: *const u8, code_ptr: *const u8, code_len: u32, result_ptr: *mut u8) -> i32;
526-
//
527-
trace!(target: "wasm", "runtime: CREATE");
528-
let endowment = self.u256_at(args.nth_checked(0)?)?;
529-
trace!(target: "wasm", " val: {:?}", endowment);
530-
let code_ptr: u32 = args.nth_checked(1)?;
531-
trace!(target: "wasm", " code_ptr: {:?}", code_ptr);
532-
let code_len: u32 = args.nth_checked(2)?;
533-
trace!(target: "wasm", " code_len: {:?}", code_len);
534-
let result_ptr: u32 = args.nth_checked(3)?;
535-
trace!(target: "wasm", "result_ptr: {:?}", result_ptr);
536-
514+
fn do_create(&mut self, endowment: U256, code_ptr: u32, code_len: u32, result_ptr: u32, scheme: vm::CreateContractAddress) -> Result<RuntimeValue> {
537515
let code = self.memory.get(code_ptr, code_len as usize)?;
538516

539517
self.adjusted_charge(|schedule| schedule.create_gas as u64)?;
@@ -543,7 +521,7 @@ impl<'a> Runtime<'a> {
543521
* U256::from(self.ext.schedule().wasm().opcodes_mul)
544522
/ U256::from(self.ext.schedule().wasm().opcodes_div);
545523

546-
match self.ext.create(&gas_left, &endowment, &code, vm::CreateContractAddress::FromSenderAndCodeHash) {
524+
match self.ext.create(&gas_left, &endowment, &code, scheme) {
547525
vm::ContractCreateResult::Created(address, gas_left) => {
548526
self.memory.set(result_ptr, &*address)?;
549527
self.gas_counter = self.gas_limit -
@@ -571,6 +549,59 @@ impl<'a> Runtime<'a> {
571549
}
572550
}
573551

552+
/// Creates a new contract
553+
///
554+
/// Arguments:
555+
/// * endowment - how much value (in Wei) transfer to the newly created contract
556+
/// * code_ptr - pointer to the code data
557+
/// * code_len - lenght of the code data
558+
/// * result_ptr - pointer to write an address of the newly created contract
559+
pub fn create(&mut self, args: RuntimeArgs) -> Result<RuntimeValue> {
560+
//
561+
// method signature:
562+
// fn create(endowment: *const u8, code_ptr: *const u8, code_len: u32, result_ptr: *mut u8) -> i32;
563+
//
564+
trace!(target: "wasm", "runtime: CREATE");
565+
let endowment = self.u256_at(args.nth_checked(0)?)?;
566+
trace!(target: "wasm", " val: {:?}", endowment);
567+
let code_ptr: u32 = args.nth_checked(1)?;
568+
trace!(target: "wasm", " code_ptr: {:?}", code_ptr);
569+
let code_len: u32 = args.nth_checked(2)?;
570+
trace!(target: "wasm", " code_len: {:?}", code_len);
571+
let result_ptr: u32 = args.nth_checked(3)?;
572+
trace!(target: "wasm", "result_ptr: {:?}", result_ptr);
573+
574+
self.do_create(endowment, code_ptr, code_len, result_ptr, vm::CreateContractAddress::FromSenderAndCodeHash)
575+
}
576+
577+
/// Creates a new contract using FromSenderSaltAndCodeHash scheme
578+
///
579+
/// Arguments:
580+
/// * endowment - how much value (in Wei) transfer to the newly created contract
581+
/// * salt - salt to be used in contract creation address
582+
/// * code_ptr - pointer to the code data
583+
/// * code_len - lenght of the code data
584+
/// * result_ptr - pointer to write an address of the newly created contract
585+
pub fn create2(&mut self, args: RuntimeArgs) -> Result<RuntimeValue> {
586+
//
587+
// method signature:
588+
// fn create2(endowment: *const u8, salt: *const u8, code_ptr: *const u8, code_len: u32, result_ptr: *mut u8) -> i32;
589+
//
590+
trace!(target: "wasm", "runtime: CREATE2");
591+
let endowment = self.u256_at(args.nth_checked(0)?)?;
592+
trace!(target: "wasm", " val: {:?}", endowment);
593+
let salt: H256 = self.u256_at(args.nth_checked(1)?)?.into();
594+
trace!(target: "wasm", " salt: {:?}", salt);
595+
let code_ptr: u32 = args.nth_checked(2)?;
596+
trace!(target: "wasm", " code_ptr: {:?}", code_ptr);
597+
let code_len: u32 = args.nth_checked(3)?;
598+
trace!(target: "wasm", " code_len: {:?}", code_len);
599+
let result_ptr: u32 = args.nth_checked(4)?;
600+
trace!(target: "wasm", "result_ptr: {:?}", result_ptr);
601+
602+
self.do_create(endowment, code_ptr, code_len, result_ptr, vm::CreateContractAddress::FromSenderSaltAndCodeHash(salt))
603+
}
604+
574605
fn debug(&mut self, args: RuntimeArgs) -> Result<()>
575606
{
576607
trace!(target: "wasm", "Contract debug message: {}", {
@@ -744,6 +775,7 @@ mod ext_impl {
744775
SENDER_FUNC => void!(self.sender(args)),
745776
ORIGIN_FUNC => void!(self.origin(args)),
746777
ELOG_FUNC => void!(self.elog(args)),
778+
CREATE2_FUNC => some!(self.create2(args)),
747779
_ => panic!("env module doesn't provide function at index {}", index),
748780
}
749781
}

0 commit comments

Comments
 (0)