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

Commit ef19c3b

Browse files
sorpaasandresilva
authored andcommitted
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 aa95a5e commit ef19c3b

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
@@ -127,6 +127,8 @@ pub struct CommonParams {
127127
pub remove_dust_contracts: bool,
128128
/// Wasm activation blocknumber, if any disabled initially.
129129
pub wasm_activation_transition: BlockNumber,
130+
/// Number of first block where KIP-4 rules begin. Only has effect if Wasm is activated.
131+
pub kip4_transition: BlockNumber,
130132
/// Gas limit bound divisor (how much gas limit can change per block)
131133
pub gas_limit_bound_divisor: U256,
132134
/// Registrar contract address.
@@ -190,7 +192,11 @@ impl CommonParams {
190192
};
191193
}
192194
if block_number >= self.wasm_activation_transition {
193-
schedule.wasm = Some(Default::default());
195+
let mut wasm = ::vm::WasmCosts::default();
196+
if block_number >= self.kip4_transition {
197+
wasm.have_create2 = true;
198+
}
199+
schedule.wasm = Some(wasm);
194200
}
195201
}
196202

@@ -301,6 +307,10 @@ impl From<ethjson::spec::Params> for CommonParams {
301307
BlockNumber::max_value,
302308
Into::into
303309
),
310+
kip4_transition: p.kip4_transition.map_or_else(
311+
BlockNumber::max_value,
312+
Into::into
313+
),
304314
}
305315
}
306316
}

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. pWASM `create` scheme.
5757
FromSenderAndNonce,

ethcore/vm/src/schedule.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ pub struct WasmCosts {
151151
pub opcodes_mul: u32,
152152
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
153153
pub opcodes_div: u32,
154+
/// Whether create2 extern function is activated.
155+
pub have_create2: bool,
154156
}
155157

156158
impl Default for WasmCosts {
@@ -168,6 +170,7 @@ impl Default for WasmCosts {
168170
max_stack_height: 64*1024,
169171
opcodes_mul: 3,
170172
opcodes_div: 8,
173+
have_create2: false,
171174
}
172175
}
173176
}

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>,
@@ -137,9 +138,10 @@ impl Ext for FakeExt {
137138
self.blockhashes.get(number).unwrap_or(&H256::new()).clone()
138139
}
139140

140-
fn create(&mut self, gas: &U256, value: &U256, code: &[u8], _address: CreateContractAddress) -> ContractCreateResult {
141+
fn create(&mut self, gas: &U256, value: &U256, code: &[u8], address: CreateContractAddress) -> ContractCreateResult {
141142
self.calls.insert(FakeCall {
142143
call_type: FakeCallType::Create,
144+
create_scheme: Some(address),
143145
gas: *gas,
144146
sender_address: None,
145147
receive_address: None,
@@ -163,6 +165,7 @@ impl Ext for FakeExt {
163165

164166
self.calls.insert(FakeCall {
165167
call_type: FakeCallType::Call,
168+
create_scheme: None,
166169
gas: *gas,
167170
sender_address: Some(sender_address.clone()),
168171
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
@@ -322,7 +322,7 @@ impl<'a> Runtime<'a> {
322322
if self.gas_counter > self.gas_limit { return Err(Error::InvalidGasState); }
323323
Ok(self.gas_limit - self.gas_counter)
324324
}
325-
325+
326326
/// General gas charging extern.
327327
fn gas(&mut self, args: RuntimeArgs) -> Result<()> {
328328
let amount: u32 = args.nth_checked(0)?;
@@ -512,29 +512,7 @@ impl<'a> Runtime<'a> {
512512
self.return_u256_ptr(args.nth_checked(0)?, val)
513513
}
514514

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

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

547-
match self.ext.create(&gas_left, &endowment, &code, vm::CreateContractAddress::FromSenderAndCodeHash) {
525+
match self.ext.create(&gas_left, &endowment, &code, scheme) {
548526
vm::ContractCreateResult::Created(address, gas_left) => {
549527
self.memory.set(result_ptr, &*address)?;
550528
self.gas_counter = self.gas_limit -
@@ -572,6 +550,59 @@ impl<'a> Runtime<'a> {
572550
}
573551
}
574552

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

0 commit comments

Comments
 (0)