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 https://github.com/paritytech/wasm-tests/pull/52
* change .. to _
* fix comment for the have_gasleft param
* update tests (0edbf860ff
)
This commit is contained in:
parent
b87c7cac54
commit
5ed2527663
@ -1 +1 @@
|
|||||||
Subproject commit 242b8d8a89ecb3e11277f0beb8180c95792aac6b
|
Subproject commit 0edbf860ff7ed4b6b6336097ba44836e8c6482dd
|
@ -127,6 +127,8 @@ pub struct CommonParams {
|
|||||||
pub wasm_activation_transition: BlockNumber,
|
pub wasm_activation_transition: BlockNumber,
|
||||||
/// Number of first block where KIP-4 rules begin. Only has effect if Wasm is activated.
|
/// Number of first block where KIP-4 rules begin. Only has effect if Wasm is activated.
|
||||||
pub kip4_transition: BlockNumber,
|
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)
|
/// Gas limit bound divisor (how much gas limit can change per block)
|
||||||
pub gas_limit_bound_divisor: U256,
|
pub gas_limit_bound_divisor: U256,
|
||||||
/// Registrar contract address.
|
/// Registrar contract address.
|
||||||
@ -195,6 +197,9 @@ impl CommonParams {
|
|||||||
if block_number >= self.kip4_transition {
|
if block_number >= self.kip4_transition {
|
||||||
wasm.have_create2 = true;
|
wasm.have_create2 = true;
|
||||||
}
|
}
|
||||||
|
if block_number >= self.kip6_transition {
|
||||||
|
wasm.have_gasleft = true;
|
||||||
|
}
|
||||||
schedule.wasm = Some(wasm);
|
schedule.wasm = Some(wasm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,6 +313,10 @@ impl From<ethjson::spec::Params> for CommonParams {
|
|||||||
BlockNumber::max_value,
|
BlockNumber::max_value,
|
||||||
Into::into
|
Into::into
|
||||||
),
|
),
|
||||||
|
kip6_transition: p.kip6_transition.map_or_else(
|
||||||
|
BlockNumber::max_value,
|
||||||
|
Into::into
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,6 +151,8 @@ pub struct WasmCosts {
|
|||||||
pub opcodes_div: u32,
|
pub opcodes_div: u32,
|
||||||
/// Whether create2 extern function is activated.
|
/// Whether create2 extern function is activated.
|
||||||
pub have_create2: bool,
|
pub have_create2: bool,
|
||||||
|
/// Whether gasleft extern function is activated.
|
||||||
|
pub have_gasleft: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WasmCosts {
|
impl Default for WasmCosts {
|
||||||
@ -169,6 +171,7 @@ impl Default for WasmCosts {
|
|||||||
opcodes_mul: 3,
|
opcodes_mul: 3,
|
||||||
opcodes_div: 8,
|
opcodes_div: 8,
|
||||||
have_create2: false,
|
have_create2: false,
|
||||||
|
have_gasleft: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ pub mod ids {
|
|||||||
pub const ORIGIN_FUNC: usize = 200;
|
pub const ORIGIN_FUNC: usize = 200;
|
||||||
pub const ELOG_FUNC: usize = 210;
|
pub const ELOG_FUNC: usize = 210;
|
||||||
pub const CREATE2_FUNC: usize = 220;
|
pub const CREATE2_FUNC: usize = 220;
|
||||||
|
pub const GASLEFT_FUNC: usize = 230;
|
||||||
|
|
||||||
pub const PANIC_FUNC: usize = 1000;
|
pub const PANIC_FUNC: usize = 1000;
|
||||||
pub const DEBUG_FUNC: usize = 1010;
|
pub const DEBUG_FUNC: usize = 1010;
|
||||||
@ -157,6 +158,11 @@ pub mod signatures {
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
pub const GASLEFT: StaticSignature = StaticSignature(
|
||||||
|
&[],
|
||||||
|
Some(I64),
|
||||||
|
);
|
||||||
|
|
||||||
pub const GASLIMIT: StaticSignature = StaticSignature(
|
pub const GASLIMIT: StaticSignature = StaticSignature(
|
||||||
&[I32],
|
&[I32],
|
||||||
None,
|
None,
|
||||||
@ -207,6 +213,7 @@ pub struct ImportResolver {
|
|||||||
memory: RefCell<Option<MemoryRef>>,
|
memory: RefCell<Option<MemoryRef>>,
|
||||||
|
|
||||||
have_create2: bool,
|
have_create2: bool,
|
||||||
|
have_gasleft: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImportResolver {
|
impl ImportResolver {
|
||||||
@ -217,6 +224,7 @@ impl ImportResolver {
|
|||||||
memory: RefCell::new(None),
|
memory: RefCell::new(None),
|
||||||
|
|
||||||
have_create2: schedule.have_create2,
|
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),
|
"origin" => host(signatures::ORIGIN, ids::ORIGIN_FUNC),
|
||||||
"elog" => host(signatures::ELOG, ids::ELOG_FUNC),
|
"elog" => host(signatures::ELOG, ids::ELOG_FUNC),
|
||||||
"create2" if self.have_create2 => host(signatures::CREATE2, ids::CREATE2_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(
|
return Err(wasmi::Error::Instantiation(
|
||||||
format!("Export {} not found", field_name),
|
format!("Export {} not found", field_name),
|
||||||
|
@ -666,6 +666,15 @@ impl<'a> Runtime<'a> {
|
|||||||
self.return_u256_ptr(args.nth_checked(0)?, difficulty)
|
self.return_u256_ptr(args.nth_checked(0)?, difficulty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Signature: `fn gasleft() -> i64`
|
||||||
|
pub fn gasleft(&mut self) -> Result<RuntimeValue> {
|
||||||
|
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)`
|
/// Signature: `fn gaslimit(dest: *mut u8)`
|
||||||
pub fn gaslimit(&mut self, args: RuntimeArgs) -> Result<()> {
|
pub fn gaslimit(&mut self, args: RuntimeArgs) -> Result<()> {
|
||||||
let gas_limit = self.ext.env_info().gas_limit;
|
let gas_limit = self.ext.env_info().gas_limit;
|
||||||
@ -782,6 +791,7 @@ mod ext_impl {
|
|||||||
ORIGIN_FUNC => void!(self.origin(args)),
|
ORIGIN_FUNC => void!(self.origin(args)),
|
||||||
ELOG_FUNC => void!(self.elog(args)),
|
ELOG_FUNC => void!(self.elog(args)),
|
||||||
CREATE2_FUNC => some!(self.create2(args)),
|
CREATE2_FUNC => some!(self.create2(args)),
|
||||||
|
GASLEFT_FUNC => some!(self.gasleft()),
|
||||||
_ => panic!("env module doesn't provide function at index {}", index),
|
_ => panic!("env module doesn't provide function at index {}", index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,7 +303,7 @@ fn create() {
|
|||||||
&FakeCall {
|
&FakeCall {
|
||||||
call_type: FakeCallType::Create,
|
call_type: FakeCallType::Create,
|
||||||
create_scheme: Some(CreateContractAddress::FromSenderAndCodeHash),
|
create_scheme: Some(CreateContractAddress::FromSenderAndCodeHash),
|
||||||
gas: U256::from(52_017),
|
gas: U256::from(49_674),
|
||||||
sender_address: None,
|
sender_address: None,
|
||||||
receive_address: None,
|
receive_address: None,
|
||||||
value: Some((1_000_000_000 / 2).into()),
|
value: Some((1_000_000_000 / 2).into()),
|
||||||
@ -315,7 +315,7 @@ fn create() {
|
|||||||
&FakeCall {
|
&FakeCall {
|
||||||
call_type: FakeCallType::Create,
|
call_type: FakeCallType::Create,
|
||||||
create_scheme: Some(CreateContractAddress::FromSenderSaltAndCodeHash(H256::from([5u8].as_ref()))),
|
create_scheme: Some(CreateContractAddress::FromSenderSaltAndCodeHash(H256::from([5u8].as_ref()))),
|
||||||
gas: U256::from(10_740),
|
gas: U256::from(6039),
|
||||||
sender_address: None,
|
sender_address: None,
|
||||||
receive_address: None,
|
receive_address: None,
|
||||||
value: Some((1_000_000_000 / 2).into()),
|
value: Some((1_000_000_000 / 2).into()),
|
||||||
@ -323,7 +323,7 @@ fn create() {
|
|||||||
code_address: None,
|
code_address: None,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
assert_eq!(gas_left, U256::from(10_675));
|
assert_eq!(gas_left, U256::from(5974));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -371,6 +371,54 @@ fn call_msg() {
|
|||||||
assert_eq!(gas_left, U256::from(91_672));
|
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_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()),
|
||||||
|
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_671));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn call_code() {
|
fn call_code() {
|
||||||
::ethcore_logger::init_log();
|
::ethcore_logger::init_log();
|
||||||
@ -591,7 +639,7 @@ fn math_add() {
|
|||||||
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
|
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
);
|
);
|
||||||
assert_eq!(gas_left, U256::from(92_095));
|
assert_eq!(gas_left, U256::from(92_072));
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiplication
|
// multiplication
|
||||||
@ -613,7 +661,7 @@ fn math_mul() {
|
|||||||
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
|
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
);
|
);
|
||||||
assert_eq!(gas_left, U256::from(91_423));
|
assert_eq!(gas_left, U256::from(91_400));
|
||||||
}
|
}
|
||||||
|
|
||||||
// subtraction
|
// subtraction
|
||||||
@ -635,7 +683,7 @@ fn math_sub() {
|
|||||||
U256::from_dec_str("111111111111111111111111111111").unwrap(),
|
U256::from_dec_str("111111111111111111111111111111").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
);
|
);
|
||||||
assert_eq!(gas_left, U256::from(92_095));
|
assert_eq!(gas_left, U256::from(92_072));
|
||||||
}
|
}
|
||||||
|
|
||||||
// subtraction with overflow
|
// subtraction with overflow
|
||||||
@ -677,7 +725,7 @@ fn math_div() {
|
|||||||
U256::from_dec_str("1125000").unwrap(),
|
U256::from_dec_str("1125000").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
);
|
);
|
||||||
assert_eq!(gas_left, U256::from(87_379));
|
assert_eq!(gas_left, U256::from(85_700));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -705,7 +753,7 @@ fn storage_metering() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 0 -> not 0
|
// 0 -> not 0
|
||||||
assert_eq!(gas_left, U256::from(72_395));
|
assert_eq!(gas_left, U256::from(72_164));
|
||||||
|
|
||||||
// #2
|
// #2
|
||||||
|
|
||||||
@ -724,7 +772,7 @@ fn storage_metering() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// not 0 -> not 0
|
// 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
|
// This test checks the ability of wasm contract to invoke
|
||||||
@ -815,6 +863,47 @@ fn externs() {
|
|||||||
assert_eq!(gas_left, U256::from(90_428));
|
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_423);
|
||||||
|
assert_eq!(gas_left, U256::from(93_349));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test should fail because
|
||||||
|
// ext.schedule.wasm.as_mut().unwrap().have_gasleft = false;
|
||||||
|
#[test]
|
||||||
|
fn gasleft_fail() {
|
||||||
|
::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]
|
#[test]
|
||||||
fn embedded_keccak() {
|
fn embedded_keccak() {
|
||||||
::ethcore_logger::init_log();
|
::ethcore_logger::init_log();
|
||||||
@ -873,7 +962,7 @@ fn events() {
|
|||||||
assert_eq!(&log_entry.data, b"gnihtemos");
|
assert_eq!(&log_entry.data, b"gnihtemos");
|
||||||
|
|
||||||
assert_eq!(&result, b"gnihtemos");
|
assert_eq!(&result, b"gnihtemos");
|
||||||
assert_eq!(gas_left, U256::from(83_158));
|
assert_eq!(gas_left, U256::from(83_161));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -152,6 +152,9 @@ pub struct Params {
|
|||||||
/// KIP4 activiation block height.
|
/// KIP4 activiation block height.
|
||||||
#[serde(rename="kip4Transition")]
|
#[serde(rename="kip4Transition")]
|
||||||
pub kip4_transition: Option<Uint>,
|
pub kip4_transition: Option<Uint>,
|
||||||
|
/// KIP6 activiation block height.
|
||||||
|
#[serde(rename="kip6Transition")]
|
||||||
|
pub kip6_transition: Option<Uint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
Reference in New Issue
Block a user