From f57fad67edfabce8d11e5573a74431608fe07a25 Mon Sep 17 00:00:00 2001 From: fro Date: Thu, 16 Aug 2018 15:05:45 +0300 Subject: [PATCH 1/8] Wasm gasleft extern added --- ethcore/res/wasm-tests | 2 +- ethcore/src/spec/spec.rs | 9 ++++++++ ethcore/vm/src/schedule.rs | 3 +++ ethcore/wasm/src/env.rs | 9 ++++++++ ethcore/wasm/src/runtime.rs | 10 +++++++++ ethcore/wasm/src/tests.rs | 41 +++++++++++++++++++++++++++++++++++++ json/src/spec/params.rs | 3 +++ 7 files changed, 76 insertions(+), 1 deletion(-) diff --git a/ethcore/res/wasm-tests b/ethcore/res/wasm-tests index 242b8d8a89e..9bf43d81592 160000 --- a/ethcore/res/wasm-tests +++ b/ethcore/res/wasm-tests @@ -1 +1 @@ -Subproject commit 242b8d8a89ecb3e11277f0beb8180c95792aac6b +Subproject commit 9bf43d815922ab5ec86873101fc33fcaf365128c diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index a83046a7258..629e39b2c1c 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -125,6 +125,8 @@ pub struct CommonParams { pub remove_dust_contracts: bool, /// Wasm activation blocknumber, if any disabled initially. pub wasm_activation_transition: BlockNumber, + /// Wasm activation blocknumber, if any disabled initially. + pub wasm_gasleft_activation_transition: BlockNumber, /// Number of first block where KIP-4 rules begin. Only has effect if Wasm is activated. pub kip4_transition: BlockNumber, /// Gas limit bound divisor (how much gas limit can change per block) @@ -195,6 +197,9 @@ impl CommonParams { if block_number >= self.kip4_transition { wasm.have_create2 = true; } + if block_number >= self.wasm_gasleft_activation_transition { + wasm.have_gasleft = true; + } schedule.wasm = Some(wasm); } } @@ -308,6 +313,10 @@ impl From for CommonParams { BlockNumber::max_value, Into::into ), + wasm_gasleft_activation_transition: p.wasm_gasleft_activation_transition.map_or_else( + BlockNumber::max_value, + Into::into + ), } } } diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index ec72c4683fd..01cc56154d5 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -151,6 +151,8 @@ pub struct WasmCosts { pub opcodes_div: u32, /// Whether create2 extern function is activated. pub have_create2: bool, + /// Does it have a GASLEFT instruction + pub have_gasleft: bool, } impl Default for WasmCosts { @@ -169,6 +171,7 @@ impl Default for WasmCosts { opcodes_mul: 3, opcodes_div: 8, have_create2: false, + have_gasleft: false, } } } diff --git a/ethcore/wasm/src/env.rs b/ethcore/wasm/src/env.rs index a9e536f5f1f..fb9e93e0fd0 100644 --- a/ethcore/wasm/src/env.rs +++ b/ethcore/wasm/src/env.rs @@ -49,6 +49,7 @@ pub mod ids { pub const ORIGIN_FUNC: usize = 200; pub const ELOG_FUNC: usize = 210; pub const CREATE2_FUNC: usize = 220; + pub const GASLEFT_FUNC: usize = 230; pub const PANIC_FUNC: usize = 1000; pub const DEBUG_FUNC: usize = 1010; @@ -157,6 +158,11 @@ pub mod signatures { None, ); + pub const GASLEFT: StaticSignature = StaticSignature( + &[], + Some(I64), + ); + pub const GASLIMIT: StaticSignature = StaticSignature( &[I32], None, @@ -207,6 +213,7 @@ pub struct ImportResolver { memory: RefCell>, have_create2: bool, + have_gasleft: bool, } impl ImportResolver { @@ -217,6 +224,7 @@ impl ImportResolver { memory: RefCell::new(None), have_create2: schedule.have_create2, + have_gasleft: schedule.have_gasleft, } } @@ -274,6 +282,7 @@ impl wasmi::ModuleImportResolver for ImportResolver { "origin" => host(signatures::ORIGIN, ids::ORIGIN_FUNC), "elog" => host(signatures::ELOG, ids::ELOG_FUNC), "create2" if self.have_create2 => host(signatures::CREATE2, ids::CREATE2_FUNC), + "gasleft" if self.have_gasleft => host(signatures::GASLEFT, ids::GASLEFT_FUNC), _ => { return Err(wasmi::Error::Instantiation( format!("Export {} not found", field_name), diff --git a/ethcore/wasm/src/runtime.rs b/ethcore/wasm/src/runtime.rs index 1c814ab7cdd..3c5d27d5c19 100644 --- a/ethcore/wasm/src/runtime.rs +++ b/ethcore/wasm/src/runtime.rs @@ -666,6 +666,15 @@ impl<'a> Runtime<'a> { self.return_u256_ptr(args.nth_checked(0)?, difficulty) } + /// Signature: `fn gasleft() -> i64` + pub fn gasleft(&mut self) -> Result { + Ok(RuntimeValue::from( + self.gas_left()? * self.ext.schedule().wasm().opcodes_mul as u64 + / self.ext.schedule().wasm().opcodes_div as u64 + ) + ) + } + /// Signature: `fn gaslimit(dest: *mut u8)` pub fn gaslimit(&mut self, args: RuntimeArgs) -> Result<()> { let gas_limit = self.ext.env_info().gas_limit; @@ -782,6 +791,7 @@ mod ext_impl { ORIGIN_FUNC => void!(self.origin(args)), ELOG_FUNC => void!(self.elog(args)), CREATE2_FUNC => some!(self.create2(args)), + GASLEFT_FUNC => some!(self.gasleft()), _ => panic!("env module doesn't provide function at index {}", index), } } diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index fdbb545904c..8da933994fd 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -815,6 +815,47 @@ fn externs() { assert_eq!(gas_left, U256::from(90_428)); } +// This test checks the ability of wasm contract to invoke gasleft +#[test] +fn gasleft() { + ::ethcore_logger::init_log(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(load_sample!("gasleft.wasm"))); + + let mut ext = FakeExt::new().with_wasm(); + ext.schedule.wasm.as_mut().unwrap().have_gasleft = true; + + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); + match result { + GasLeft::Known(_) => {}, + GasLeft::NeedsReturn { gas_left, data, .. } => { + let gas = LittleEndian::read_u64(data.as_ref()); + assert_eq!(gas, 93_420); + assert_eq!(gas_left, U256::from(93_343)); + }, + } +} + +// This test should fail because +// ext.schedule.wasm.as_mut().unwrap().have_gasleft = false; +#[test] +fn gasleft_panic() { + ::ethcore_logger::init_log(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(load_sample!("gasleft.wasm"))); + let mut ext = FakeExt::new().with_wasm(); + let mut interpreter = wasm_interpreter(params); + match interpreter.exec(&mut ext) { + Err(..) => {}, + Ok(..) => panic!("interpreter.exec should return Err if ext.schedule.wasm.have_gasleft = false") + } +} + #[test] fn embedded_keccak() { ::ethcore_logger::init_log(); diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index cf57e9af456..be79758f8ab 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -152,6 +152,9 @@ pub struct Params { /// KIP4 activiation block height. #[serde(rename="kip4Transition")] pub kip4_transition: Option, + /// Wasm `gasleft` extern (aka opcode) activation block height. + #[serde(rename="wasmGasleftActivationTransition")] + pub wasm_gasleft_activation_transition: Option, } #[cfg(test)] From 1dd8a019f67dda1e3526399af75ed77929a67fed Mon Sep 17 00:00:00 2001 From: fro Date: Thu, 16 Aug 2018 15:19:35 +0300 Subject: [PATCH 2/8] wasm_gasleft_activation_transition -> kip4_transition --- ethcore/src/spec/spec.rs | 8 -------- json/src/spec/params.rs | 3 --- 2 files changed, 11 deletions(-) diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 629e39b2c1c..7fff0c12877 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -125,8 +125,6 @@ pub struct CommonParams { pub remove_dust_contracts: bool, /// Wasm activation blocknumber, if any disabled initially. pub wasm_activation_transition: BlockNumber, - /// Wasm activation blocknumber, if any disabled initially. - pub wasm_gasleft_activation_transition: BlockNumber, /// Number of first block where KIP-4 rules begin. Only has effect if Wasm is activated. pub kip4_transition: BlockNumber, /// Gas limit bound divisor (how much gas limit can change per block) @@ -196,8 +194,6 @@ impl CommonParams { let mut wasm = ::vm::WasmCosts::default(); if block_number >= self.kip4_transition { wasm.have_create2 = true; - } - if block_number >= self.wasm_gasleft_activation_transition { wasm.have_gasleft = true; } schedule.wasm = Some(wasm); @@ -313,10 +309,6 @@ impl From for CommonParams { BlockNumber::max_value, Into::into ), - wasm_gasleft_activation_transition: p.wasm_gasleft_activation_transition.map_or_else( - BlockNumber::max_value, - Into::into - ), } } } diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index be79758f8ab..cf57e9af456 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -152,9 +152,6 @@ pub struct Params { /// KIP4 activiation block height. #[serde(rename="kip4Transition")] pub kip4_transition: Option, - /// Wasm `gasleft` extern (aka opcode) activation block height. - #[serde(rename="wasmGasleftActivationTransition")] - pub wasm_gasleft_activation_transition: Option, } #[cfg(test)] From 21eaf7759168272bca369538e25e0e158b9f08a3 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 21 Aug 2018 13:32:54 +0300 Subject: [PATCH 3/8] use kip-6 switch --- ethcore/src/spec/spec.rs | 8 ++++++++ json/src/spec/params.rs | 3 +++ 2 files changed, 11 insertions(+) diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 7fff0c12877..72019811455 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -127,6 +127,8 @@ pub struct CommonParams { pub wasm_activation_transition: BlockNumber, /// Number of first block where KIP-4 rules begin. Only has effect if Wasm is activated. pub kip4_transition: BlockNumber, + /// Number of first block where KIP-6 rules begin. Only has effect if Wasm is activated. + pub kip6_transition: BlockNumber, /// Gas limit bound divisor (how much gas limit can change per block) pub gas_limit_bound_divisor: U256, /// Registrar contract address. @@ -194,6 +196,8 @@ impl CommonParams { let mut wasm = ::vm::WasmCosts::default(); if block_number >= self.kip4_transition { wasm.have_create2 = true; + } + if block_number >= self.kip6_transition { wasm.have_gasleft = true; } schedule.wasm = Some(wasm); @@ -309,6 +313,10 @@ impl From for CommonParams { BlockNumber::max_value, Into::into ), + kip6_transition: p.kip6_transition.map_or_else( + BlockNumber::max_value, + Into::into + ), } } } diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index cf57e9af456..d3319f7c49e 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -152,6 +152,9 @@ pub struct Params { /// KIP4 activiation block height. #[serde(rename="kip4Transition")] pub kip4_transition: Option, + /// KIP6 activiation block height. + #[serde(rename="kip6Transition")] + pub kip6_transition: Option, } #[cfg(test)] From 2ea832bf04d1985b429e12d10d9aafd5822ea8cf Mon Sep 17 00:00:00 2001 From: fro Date: Tue, 21 Aug 2018 15:43:01 +0400 Subject: [PATCH 4/8] gasleft_panic -> gasleft_fail rename --- ethcore/wasm/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index 8da933994fd..4deb2a4ca24 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -842,7 +842,7 @@ fn gasleft() { // This test should fail because // ext.schedule.wasm.as_mut().unwrap().have_gasleft = false; #[test] -fn gasleft_panic() { +fn gasleft_fail() { ::ethcore_logger::init_log(); let mut params = ActionParams::default(); From d34218932cbb716bf623fdd7e52e159f838b8b80 Mon Sep 17 00:00:00 2001 From: fro Date: Tue, 21 Aug 2018 19:26:47 +0400 Subject: [PATCH 5/8] call_msg_gasleft test added and gas_left agustments because this https://github.com/paritytech/wasm-tests/pull/52 --- ethcore/res/wasm-tests | 2 +- ethcore/wasm/src/tests.rs | 68 +++++++++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/ethcore/res/wasm-tests b/ethcore/res/wasm-tests index 9bf43d81592..87d8e84a36a 160000 --- a/ethcore/res/wasm-tests +++ b/ethcore/res/wasm-tests @@ -1 +1 @@ -Subproject commit 9bf43d815922ab5ec86873101fc33fcaf365128c +Subproject commit 87d8e84a36a8fa327b57c6b60322adb34204a2ff diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index 4deb2a4ca24..0b19a86b98f 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -303,7 +303,7 @@ fn create() { &FakeCall { call_type: FakeCallType::Create, create_scheme: Some(CreateContractAddress::FromSenderAndCodeHash), - gas: U256::from(52_017), + gas: U256::from(49_674), sender_address: None, receive_address: None, value: Some((1_000_000_000 / 2).into()), @@ -315,7 +315,7 @@ fn create() { &FakeCall { call_type: FakeCallType::Create, create_scheme: Some(CreateContractAddress::FromSenderSaltAndCodeHash(H256::from([5u8].as_ref()))), - gas: U256::from(10_740), + gas: U256::from(6039), sender_address: None, receive_address: None, value: Some((1_000_000_000 / 2).into()), @@ -323,7 +323,7 @@ fn create() { code_address: None, } )); - assert_eq!(gas_left, U256::from(10_675)); + assert_eq!(gas_left, U256::from(5974)); } #[test] @@ -371,6 +371,54 @@ fn call_msg() { assert_eq!(gas_left, U256::from(91_672)); } +// The same as `call_msg`, but send a `pwasm_ethereum::gasleft` +// value as `gas` argument to the inner pwasm_ethereum::call +#[test] +fn call_msg_gasleft() { + ::ethcore_logger::init_log(); + + let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap(); + let receiver: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap(); + let contract_address: Address = "0d461d4174b4ae35775c4a342f1e5e1e4e6c4db5".parse().unwrap(); + + let mut params = ActionParams::default(); + params.sender = sender.clone(); + params.address = receiver.clone(); + params.code_address = contract_address.clone(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(load_sample!("call_gasleft.wasm"))); + params.data = Some(Vec::new()); + + let mut ext = FakeExt::new().with_wasm(); + ext.schedule.wasm.as_mut().unwrap().have_gasleft = true; + ext.balances.insert(receiver.clone(), U256::from(10000000000u64)); + + let gas_left = { + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); + match result { + GasLeft::Known(gas_left) => gas_left, + GasLeft::NeedsReturn { .. } => { panic!("Call test should not return payload"); }, + } + }; + + trace!(target: "wasm", "fake_calls: {:?}", &ext.calls); + assert!(ext.calls.contains( + &FakeCall { + call_type: FakeCallType::Call, + create_scheme: None, + gas: U256::from(91_163), + sender_address: Some(receiver), + receive_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])), + value: Some(1000000000.into()), + data: vec![129u8, 123, 113, 107, 101, 97], + code_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])), + } + )); + + assert_eq!(gas_left, U256::from(91_669)); +} + #[test] fn call_code() { ::ethcore_logger::init_log(); @@ -591,7 +639,7 @@ fn math_add() { U256::from_dec_str("1888888888888888888888888888887").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(92_095)); + assert_eq!(gas_left, U256::from(92_072)); } // multiplication @@ -613,7 +661,7 @@ fn math_mul() { U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(91_423)); + assert_eq!(gas_left, U256::from(91_400)); } // subtraction @@ -635,7 +683,7 @@ fn math_sub() { U256::from_dec_str("111111111111111111111111111111").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(92_095)); + assert_eq!(gas_left, U256::from(92_072)); } // subtraction with overflow @@ -677,7 +725,7 @@ fn math_div() { U256::from_dec_str("1125000").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(87_379)); + assert_eq!(gas_left, U256::from(85_700)); } #[test] @@ -705,7 +753,7 @@ fn storage_metering() { }; // 0 -> not 0 - assert_eq!(gas_left, U256::from(72_395)); + assert_eq!(gas_left, U256::from(72_164)); // #2 @@ -724,7 +772,7 @@ fn storage_metering() { }; // not 0 -> not 0 - assert_eq!(gas_left, U256::from(87_395)); + assert_eq!(gas_left, U256::from(87_164)); } // This test checks the ability of wasm contract to invoke @@ -914,7 +962,7 @@ fn events() { assert_eq!(&log_entry.data, b"gnihtemos"); assert_eq!(&result, b"gnihtemos"); - assert_eq!(gas_left, U256::from(83_158)); + assert_eq!(gas_left, U256::from(83_161)); } #[test] From f1d1ede5d933a3685b02ebe1b374a766d3ff3812 Mon Sep 17 00:00:00 2001 From: fro Date: Thu, 23 Aug 2018 11:11:14 +0400 Subject: [PATCH 6/8] change .. to _ --- ethcore/wasm/src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index 0b19a86b98f..b47752d2700 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -899,8 +899,8 @@ fn gasleft_fail() { let mut ext = FakeExt::new().with_wasm(); let mut interpreter = wasm_interpreter(params); match interpreter.exec(&mut ext) { - Err(..) => {}, - Ok(..) => panic!("interpreter.exec should return Err if ext.schedule.wasm.have_gasleft = false") + Err(_) => {}, + Ok(_) => panic!("interpreter.exec should return Err if ext.schedule.wasm.have_gasleft = false") } } From 7b136ff51edb92572c8979a6edd636716d91088f Mon Sep 17 00:00:00 2001 From: fro Date: Thu, 23 Aug 2018 11:14:11 +0400 Subject: [PATCH 7/8] fix comment for the have_gasleft param --- ethcore/vm/src/schedule.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index 01cc56154d5..2d263b63efd 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -151,7 +151,7 @@ pub struct WasmCosts { pub opcodes_div: u32, /// Whether create2 extern function is activated. pub have_create2: bool, - /// Does it have a GASLEFT instruction + /// Whether gasleft extern function is activated. pub have_gasleft: bool, } From fa53a4adbac80af5393d2478bf10c6d84af2342f Mon Sep 17 00:00:00 2001 From: fro Date: Thu, 23 Aug 2018 12:51:34 +0400 Subject: [PATCH 8/8] update tests (https://github.com/paritytech/wasm-tests/pull/54/commits/0edbf860ff7ed4b6b6336097ba44836e8c6482dd) --- ethcore/res/wasm-tests | 2 +- ethcore/wasm/src/tests.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ethcore/res/wasm-tests b/ethcore/res/wasm-tests index 87d8e84a36a..0edbf860ff7 160000 --- a/ethcore/res/wasm-tests +++ b/ethcore/res/wasm-tests @@ -1 +1 @@ -Subproject commit 87d8e84a36a8fa327b57c6b60322adb34204a2ff +Subproject commit 0edbf860ff7ed4b6b6336097ba44836e8c6482dd diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index b47752d2700..b1a773cb422 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -407,7 +407,7 @@ fn call_msg_gasleft() { &FakeCall { call_type: FakeCallType::Call, create_scheme: None, - gas: U256::from(91_163), + gas: U256::from(91_165), sender_address: Some(receiver), receive_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])), value: Some(1000000000.into()), @@ -416,7 +416,7 @@ fn call_msg_gasleft() { } )); - assert_eq!(gas_left, U256::from(91_669)); + assert_eq!(gas_left, U256::from(91_671)); } #[test] @@ -881,8 +881,8 @@ fn gasleft() { GasLeft::Known(_) => {}, GasLeft::NeedsReturn { gas_left, data, .. } => { let gas = LittleEndian::read_u64(data.as_ref()); - assert_eq!(gas, 93_420); - assert_eq!(gas_left, U256::from(93_343)); + assert_eq!(gas, 93_423); + assert_eq!(gas_left, U256::from(93_349)); }, } }