Skip to content

Commit db70416

Browse files
authored
Merge pull request #470 from CosmWasm/fix-GAS_LIMIT
Increase GAS_LIMIT by a lot and stabilize set_gas_limit
2 parents f340d59 + d04123d commit db70416

File tree

4 files changed

+83
-22
lines changed

4 files changed

+83
-22
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
**cosmwasm-vm**
1212

1313
- Remove unused cache size argument from `CosmCache`.
14+
- `set_gas_limit` now panics if the given gas limit exceeds the max. supported
15+
value.
16+
- Increase the max. supported value for gas limit from 10_000_000_000 to
17+
0x7FFFFFFFFFFFFFFF.
1418

1519
## 0.9.3 (2020-07-08)
1620

packages/vm/src/backends/singlepass.rs

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG;
1212
use crate::errors::VmResult;
1313
use crate::middleware::DeterministicMiddleware;
1414

15-
/// In Wasmer, The gas limit on instances is set during compile time and is included in the compiled binaries.
16-
/// This causes issues when trying to reuse the same precompiled binaries for another instance with a different
17-
/// gas limit.
18-
/// https://github.com/wasmerio/wasmer/pull/996
19-
/// To work around that, we set the gas limit of all Wasmer instances to this very-high gas limit value, under
20-
/// the assumption that users won't request more than this amount of gas. Then to set a gas limit below that figure,
21-
/// we pretend to consume the difference between the two in `set_gas_limit`, so the amount of units left is equal to
22-
/// the requested gas limit.
23-
pub const GAS_LIMIT: u64 = 10_000_000_000;
15+
/// In Wasmer, the gas limit is set on modules during compilation and is included in the cached modules.
16+
/// This causes issues when trying to instantiate the same compiled module with a different gas limit.
17+
/// A fix for this is proposed here: https://github.com/wasmerio/wasmer/pull/996.
18+
///
19+
/// To work around this limitation, we set the gas limit of all Wasmer instances to this very high value,
20+
/// assuming users won't request more than this amount of gas. In order to set the real gas limit, we pretend
21+
/// to consume the difference between the two in `set_gas_limit` ("points used" in the metering middleware).
22+
/// Since we observed overflow behaviour in the points used, we ensure both MAX_GAS_LIMIT and points used stay
23+
/// far below u64::MAX.
24+
const MAX_GAS_LIMIT: u64 = u64::MAX / 2;
2425

2526
pub fn compile(code: &[u8]) -> VmResult<Module> {
2627
let module = compile_with(code, compiler().as_ref())?;
@@ -31,7 +32,7 @@ pub fn compiler() -> Box<dyn Compiler> {
3132
let c: StreamingCompiler<SinglePassMCG, _, _, _, _> = StreamingCompiler::new(move || {
3233
let mut chain = MiddlewareChain::new();
3334
chain.push(DeterministicMiddleware::new());
34-
chain.push(metering::Metering::new(GAS_LIMIT));
35+
chain.push(metering::Metering::new(MAX_GAS_LIMIT));
3536
chain
3637
});
3738
Box::new(c)
@@ -43,13 +44,75 @@ pub fn backend() -> &'static str {
4344

4445
/// Set the amount of gas units that can be used in the instance.
4546
pub fn set_gas_limit(instance: &mut WasmerInstance, limit: u64) {
46-
let used = GAS_LIMIT.saturating_sub(limit);
47-
metering::set_points_used(instance, used)
47+
if limit > MAX_GAS_LIMIT {
48+
panic!(
49+
"Attempted to set gas limit larger than max gas limit (got: {}; maximum: {}).",
50+
limit, MAX_GAS_LIMIT
51+
);
52+
} else {
53+
let used = MAX_GAS_LIMIT - limit;
54+
metering::set_points_used(instance, used);
55+
}
4856
}
4957

5058
/// Get how many more gas units can be used in the instance.
5159
pub fn get_gas_left(instance: &WasmerInstance) -> u64 {
5260
let used = metering::get_points_used(instance);
53-
// when running out of gas, get_points_used can exceed GAS_LIMIT
54-
GAS_LIMIT.saturating_sub(used)
61+
// when running out of gas, get_points_used can exceed MAX_GAS_LIMIT
62+
MAX_GAS_LIMIT.saturating_sub(used)
63+
}
64+
65+
#[cfg(test)]
66+
mod test {
67+
use super::*;
68+
use wabt::wat2wasm;
69+
use wasmer_runtime_core::imports;
70+
71+
fn instantiate(code: &[u8]) -> WasmerInstance {
72+
let module = compile(code).unwrap();
73+
let import_obj = imports! { "env" => {}, };
74+
module.instantiate(&import_obj).unwrap()
75+
}
76+
77+
#[test]
78+
fn get_gas_left_defaults_to_constant() {
79+
let wasm = wat2wasm("(module)").unwrap();
80+
let instance = instantiate(&wasm);
81+
let gas_left = get_gas_left(&instance);
82+
assert_eq!(gas_left, MAX_GAS_LIMIT);
83+
}
84+
85+
#[test]
86+
fn set_gas_limit_works() {
87+
let wasm = wat2wasm("(module)").unwrap();
88+
let mut instance = instantiate(&wasm);
89+
90+
let limit = 3456789;
91+
set_gas_limit(&mut instance, limit);
92+
assert_eq!(get_gas_left(&instance), limit);
93+
94+
let limit = 1;
95+
set_gas_limit(&mut instance, limit);
96+
assert_eq!(get_gas_left(&instance), limit);
97+
98+
let limit = 0;
99+
set_gas_limit(&mut instance, limit);
100+
assert_eq!(get_gas_left(&instance), limit);
101+
102+
let limit = MAX_GAS_LIMIT;
103+
set_gas_limit(&mut instance, limit);
104+
assert_eq!(get_gas_left(&instance), limit);
105+
}
106+
107+
#[test]
108+
#[should_panic(
109+
expected = "Attempted to set gas limit larger than max gas limit (got: 9223372036854775808; maximum: 9223372036854775807)."
110+
)]
111+
fn set_gas_limit_panic_for_values_too_large() {
112+
let wasm = wat2wasm("(module)").unwrap();
113+
let mut instance = instantiate(&wasm);
114+
115+
let limit = MAX_GAS_LIMIT + 1;
116+
set_gas_limit(&mut instance, limit);
117+
}
55118
}

packages/vm/src/context.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,10 +363,7 @@ mod test {
363363
static INIT_AMOUNT: u128 = 500;
364364
static INIT_DENOM: &str = "TOKEN";
365365

366-
#[cfg(feature = "singlepass")]
367-
use crate::backends::singlepass::GAS_LIMIT;
368-
#[cfg(not(feature = "singlepass"))]
369-
const GAS_LIMIT: u64 = 10_000_000_000;
366+
const GAS_LIMIT: u64 = 5_000_000;
370367

371368
fn make_instance() -> Box<WasmerInstance> {
372369
let module = compile(&CONTRACT).unwrap();

packages/vm/src/imports.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,7 @@ mod test {
224224
static INIT_AMOUNT: u128 = 500;
225225
static INIT_DENOM: &str = "TOKEN";
226226

227-
#[cfg(feature = "singlepass")]
228-
use crate::backends::singlepass::GAS_LIMIT;
229-
#[cfg(not(feature = "singlepass"))]
230-
const GAS_LIMIT: u64 = 10_000_000_000;
227+
const GAS_LIMIT: u64 = 5_000_000;
231228

232229
fn make_instance() -> Box<WasmerInstance> {
233230
let module = compile(&CONTRACT).unwrap();

0 commit comments

Comments
 (0)