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

Commit 3e62635

Browse files
lexfrlandresilva
authored andcommitted
gasleft extern implemented for WASM runtime (kip-6) (#9357)
* Wasm gasleft extern added * wasm_gasleft_activation_transition -> kip4_transition * use kip-6 switch * gasleft_panic -> gasleft_fail rename * call_msg_gasleft test added and gas_left agustments because this openethereum/wasm-tests#52 * change .. to _ * fix comment for the have_gasleft param * update tests (openethereum/wasm-tests@0edbf86)
1 parent 924c75e commit 3e62635

File tree

7 files changed

+134
-11
lines changed

7 files changed

+134
-11
lines changed

ethcore/res/wasm-tests

ethcore/src/spec/spec.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ pub struct CommonParams {
129129
pub wasm_activation_transition: BlockNumber,
130130
/// Number of first block where KIP-4 rules begin. Only has effect if Wasm is activated.
131131
pub kip4_transition: BlockNumber,
132+
/// Number of first block where KIP-6 rules begin. Only has effect if Wasm is activated.
133+
pub kip6_transition: BlockNumber,
132134
/// Gas limit bound divisor (how much gas limit can change per block)
133135
pub gas_limit_bound_divisor: U256,
134136
/// Registrar contract address.
@@ -196,6 +198,9 @@ impl CommonParams {
196198
if block_number >= self.kip4_transition {
197199
wasm.have_create2 = true;
198200
}
201+
if block_number >= self.kip6_transition {
202+
wasm.have_gasleft = true;
203+
}
199204
schedule.wasm = Some(wasm);
200205
}
201206
}
@@ -311,6 +316,10 @@ impl From<ethjson::spec::Params> for CommonParams {
311316
BlockNumber::max_value,
312317
Into::into
313318
),
319+
kip6_transition: p.kip6_transition.map_or_else(
320+
BlockNumber::max_value,
321+
Into::into
322+
),
314323
}
315324
}
316325
}

ethcore/vm/src/schedule.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ pub struct WasmCosts {
153153
pub opcodes_div: u32,
154154
/// Whether create2 extern function is activated.
155155
pub have_create2: bool,
156+
/// Whether gasleft extern function is activated.
157+
pub have_gasleft: bool,
156158
}
157159

158160
impl Default for WasmCosts {
@@ -171,6 +173,7 @@ impl Default for WasmCosts {
171173
opcodes_mul: 3,
172174
opcodes_div: 8,
173175
have_create2: false,
176+
have_gasleft: false,
174177
}
175178
}
176179
}

ethcore/wasm/src/env.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pub mod ids {
4949
pub const ORIGIN_FUNC: usize = 200;
5050
pub const ELOG_FUNC: usize = 210;
5151
pub const CREATE2_FUNC: usize = 220;
52+
pub const GASLEFT_FUNC: usize = 230;
5253

5354
pub const PANIC_FUNC: usize = 1000;
5455
pub const DEBUG_FUNC: usize = 1010;
@@ -157,6 +158,11 @@ pub mod signatures {
157158
None,
158159
);
159160

161+
pub const GASLEFT: StaticSignature = StaticSignature(
162+
&[],
163+
Some(I64),
164+
);
165+
160166
pub const GASLIMIT: StaticSignature = StaticSignature(
161167
&[I32],
162168
None,
@@ -207,6 +213,7 @@ pub struct ImportResolver {
207213
memory: RefCell<Option<MemoryRef>>,
208214

209215
have_create2: bool,
216+
have_gasleft: bool,
210217
}
211218

212219
impl ImportResolver {
@@ -217,6 +224,7 @@ impl ImportResolver {
217224
memory: RefCell::new(None),
218225

219226
have_create2: schedule.have_create2,
227+
have_gasleft: schedule.have_gasleft,
220228
}
221229
}
222230

@@ -274,6 +282,7 @@ impl wasmi::ModuleImportResolver for ImportResolver {
274282
"origin" => host(signatures::ORIGIN, ids::ORIGIN_FUNC),
275283
"elog" => host(signatures::ELOG, ids::ELOG_FUNC),
276284
"create2" if self.have_create2 => host(signatures::CREATE2, ids::CREATE2_FUNC),
285+
"gasleft" if self.have_gasleft => host(signatures::GASLEFT, ids::GASLEFT_FUNC),
277286
_ => {
278287
return Err(wasmi::Error::Instantiation(
279288
format!("Export {} not found", field_name),

ethcore/wasm/src/runtime.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,15 @@ impl<'a> Runtime<'a> {
661661
self.return_u256_ptr(args.nth_checked(0)?, difficulty)
662662
}
663663

664+
/// Signature: `fn gasleft() -> i64`
665+
pub fn gasleft(&mut self) -> Result<RuntimeValue> {
666+
Ok(RuntimeValue::from(
667+
self.gas_left()? * self.ext.schedule().wasm().opcodes_mul as u64
668+
/ self.ext.schedule().wasm().opcodes_div as u64
669+
)
670+
)
671+
}
672+
664673
/// Signature: `fn gaslimit(dest: *mut u8)`
665674
pub fn gaslimit(&mut self, args: RuntimeArgs) -> Result<()> {
666675
let gas_limit = self.ext.env_info().gas_limit;
@@ -777,6 +786,7 @@ mod ext_impl {
777786
ORIGIN_FUNC => void!(self.origin(args)),
778787
ELOG_FUNC => void!(self.elog(args)),
779788
CREATE2_FUNC => some!(self.create2(args)),
789+
GASLEFT_FUNC => some!(self.gasleft()),
780790
_ => panic!("env module doesn't provide function at index {}", index),
781791
}
782792
}

ethcore/wasm/src/tests.rs

Lines changed: 99 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ fn create() {
303303
&FakeCall {
304304
call_type: FakeCallType::Create,
305305
create_scheme: Some(CreateContractAddress::FromSenderAndCodeHash),
306-
gas: U256::from(52_017),
306+
gas: U256::from(49_674),
307307
sender_address: None,
308308
receive_address: None,
309309
value: Some((1_000_000_000 / 2).into()),
@@ -315,15 +315,15 @@ fn create() {
315315
&FakeCall {
316316
call_type: FakeCallType::Create,
317317
create_scheme: Some(CreateContractAddress::FromSenderSaltAndCodeHash(H256::from([5u8].as_ref()))),
318-
gas: U256::from(10_740),
318+
gas: U256::from(6039),
319319
sender_address: None,
320320
receive_address: None,
321321
value: Some((1_000_000_000 / 2).into()),
322322
data: vec![0u8, 2, 4, 8, 16, 32, 64, 128],
323323
code_address: None,
324324
}
325325
));
326-
assert_eq!(gas_left, U256::from(10_675));
326+
assert_eq!(gas_left, U256::from(5974));
327327
}
328328

329329
#[test]
@@ -371,6 +371,54 @@ fn call_msg() {
371371
assert_eq!(gas_left, U256::from(91_672));
372372
}
373373

374+
// The same as `call_msg`, but send a `pwasm_ethereum::gasleft`
375+
// value as `gas` argument to the inner pwasm_ethereum::call
376+
#[test]
377+
fn call_msg_gasleft() {
378+
::ethcore_logger::init_log();
379+
380+
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
381+
let receiver: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
382+
let contract_address: Address = "0d461d4174b4ae35775c4a342f1e5e1e4e6c4db5".parse().unwrap();
383+
384+
let mut params = ActionParams::default();
385+
params.sender = sender.clone();
386+
params.address = receiver.clone();
387+
params.code_address = contract_address.clone();
388+
params.gas = U256::from(100_000);
389+
params.code = Some(Arc::new(load_sample!("call_gasleft.wasm")));
390+
params.data = Some(Vec::new());
391+
392+
let mut ext = FakeExt::new().with_wasm();
393+
ext.schedule.wasm.as_mut().unwrap().have_gasleft = true;
394+
ext.balances.insert(receiver.clone(), U256::from(10000000000u64));
395+
396+
let gas_left = {
397+
let mut interpreter = wasm_interpreter(params);
398+
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
399+
match result {
400+
GasLeft::Known(gas_left) => gas_left,
401+
GasLeft::NeedsReturn { .. } => { panic!("Call test should not return payload"); },
402+
}
403+
};
404+
405+
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
406+
assert!(ext.calls.contains(
407+
&FakeCall {
408+
call_type: FakeCallType::Call,
409+
create_scheme: None,
410+
gas: U256::from(91_165),
411+
sender_address: Some(receiver),
412+
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])),
413+
value: Some(1000000000.into()),
414+
data: vec![129u8, 123, 113, 107, 101, 97],
415+
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])),
416+
}
417+
));
418+
419+
assert_eq!(gas_left, U256::from(91_671));
420+
}
421+
374422
#[test]
375423
fn call_code() {
376424
::ethcore_logger::init_log();
@@ -591,7 +639,7 @@ fn math_add() {
591639
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
592640
(&result[..]).into()
593641
);
594-
assert_eq!(gas_left, U256::from(92_095));
642+
assert_eq!(gas_left, U256::from(92_072));
595643
}
596644

597645
// multiplication
@@ -613,7 +661,7 @@ fn math_mul() {
613661
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
614662
(&result[..]).into()
615663
);
616-
assert_eq!(gas_left, U256::from(91_423));
664+
assert_eq!(gas_left, U256::from(91_400));
617665
}
618666

619667
// subtraction
@@ -635,7 +683,7 @@ fn math_sub() {
635683
U256::from_dec_str("111111111111111111111111111111").unwrap(),
636684
(&result[..]).into()
637685
);
638-
assert_eq!(gas_left, U256::from(92_095));
686+
assert_eq!(gas_left, U256::from(92_072));
639687
}
640688

641689
// subtraction with overflow
@@ -677,7 +725,7 @@ fn math_div() {
677725
U256::from_dec_str("1125000").unwrap(),
678726
(&result[..]).into()
679727
);
680-
assert_eq!(gas_left, U256::from(87_379));
728+
assert_eq!(gas_left, U256::from(85_700));
681729
}
682730

683731
#[test]
@@ -705,7 +753,7 @@ fn storage_metering() {
705753
};
706754

707755
// 0 -> not 0
708-
assert_eq!(gas_left, U256::from(72_395));
756+
assert_eq!(gas_left, U256::from(72_164));
709757

710758
// #2
711759

@@ -724,7 +772,7 @@ fn storage_metering() {
724772
};
725773

726774
// not 0 -> not 0
727-
assert_eq!(gas_left, U256::from(87_395));
775+
assert_eq!(gas_left, U256::from(87_164));
728776
}
729777

730778
// This test checks the ability of wasm contract to invoke
@@ -815,6 +863,47 @@ fn externs() {
815863
assert_eq!(gas_left, U256::from(90_428));
816864
}
817865

866+
// This test checks the ability of wasm contract to invoke gasleft
867+
#[test]
868+
fn gasleft() {
869+
::ethcore_logger::init_log();
870+
871+
let mut params = ActionParams::default();
872+
params.gas = U256::from(100_000);
873+
params.code = Some(Arc::new(load_sample!("gasleft.wasm")));
874+
875+
let mut ext = FakeExt::new().with_wasm();
876+
ext.schedule.wasm.as_mut().unwrap().have_gasleft = true;
877+
878+
let mut interpreter = wasm_interpreter(params);
879+
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
880+
match result {
881+
GasLeft::Known(_) => {},
882+
GasLeft::NeedsReturn { gas_left, data, .. } => {
883+
let gas = LittleEndian::read_u64(data.as_ref());
884+
assert_eq!(gas, 93_423);
885+
assert_eq!(gas_left, U256::from(93_349));
886+
},
887+
}
888+
}
889+
890+
// This test should fail because
891+
// ext.schedule.wasm.as_mut().unwrap().have_gasleft = false;
892+
#[test]
893+
fn gasleft_fail() {
894+
::ethcore_logger::init_log();
895+
896+
let mut params = ActionParams::default();
897+
params.gas = U256::from(100_000);
898+
params.code = Some(Arc::new(load_sample!("gasleft.wasm")));
899+
let mut ext = FakeExt::new().with_wasm();
900+
let mut interpreter = wasm_interpreter(params);
901+
match interpreter.exec(&mut ext) {
902+
Err(_) => {},
903+
Ok(_) => panic!("interpreter.exec should return Err if ext.schedule.wasm.have_gasleft = false")
904+
}
905+
}
906+
818907
#[test]
819908
fn embedded_keccak() {
820909
::ethcore_logger::init_log();
@@ -873,7 +962,7 @@ fn events() {
873962
assert_eq!(&log_entry.data, b"gnihtemos");
874963

875964
assert_eq!(&result, b"gnihtemos");
876-
assert_eq!(gas_left, U256::from(83_158));
965+
assert_eq!(gas_left, U256::from(83_161));
877966
}
878967

879968
#[test]

json/src/spec/params.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ pub struct Params {
152152
/// KIP4 activiation block height.
153153
#[serde(rename="kip4Transition")]
154154
pub kip4_transition: Option<Uint>,
155+
/// KIP6 activiation block height.
156+
#[serde(rename="kip6Transition")]
157+
pub kip6_transition: Option<Uint>,
155158
}
156159

157160
#[cfg(test)]

0 commit comments

Comments
 (0)