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

Commit 5b41575

Browse files
authored
Fix/div by zero (#5041)
* Handle gas_price being zero separately * Bump spec_version * Add a unit & integration tests for gas price = 0
1 parent 0f4f9d7 commit 5b41575

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

bin/node/runtime/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
8181
// and set impl_version to 0. If only runtime
8282
// implementation changes and behavior does not, then leave spec_version as
8383
// is and increment impl_version.
84-
spec_version: 225,
85-
impl_version: 1,
84+
spec_version: 226,
85+
impl_version: 0,
8686
apis: RUNTIME_API_VERSIONS,
8787
};
8888

frame/contracts/src/gas.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,11 @@ pub fn refund_unused_gas<T: Trait>(
250250
pub fn approx_gas_for_balance<Balance>(gas_price: Balance, balance: Balance) -> Gas
251251
where Balance: AtLeast32Bit
252252
{
253-
(balance / gas_price).saturated_into::<Gas>()
253+
if gas_price.is_zero() {
254+
Zero::zero()
255+
} else {
256+
(balance / gas_price).saturated_into::<Gas>()
257+
}
254258
}
255259

256260
/// A simple utility macro that helps to match against a
@@ -294,7 +298,7 @@ macro_rules! match_tokens {
294298
#[cfg(test)]
295299
mod tests {
296300
use super::{GasMeter, Token};
297-
use crate::tests::Test;
301+
use crate::{tests::Test, gas::approx_gas_for_balance};
298302

299303
/// A trivial token that charges the specified number of gas units.
300304
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -382,4 +386,22 @@ mod tests {
382386
let mut gas_meter = GasMeter::<Test>::with_limit(25, 10);
383387
assert!(!gas_meter.charge(&(), SimpleToken(25)).is_out_of_gas());
384388
}
389+
390+
// A unit test for `fn approx_gas_for_balance()`, and makes
391+
// sure setting gas_price 0 does not cause `div by zero` error.
392+
#[test]
393+
fn approx_gas_for_balance_works() {
394+
let tests = vec![
395+
(approx_gas_for_balance(0_u64, 123), 0),
396+
(approx_gas_for_balance(0_u64, 456), 0),
397+
(approx_gas_for_balance(1_u64, 123), 123),
398+
(approx_gas_for_balance(1_u64, 456), 456),
399+
(approx_gas_for_balance(100_u64, 900), 9),
400+
(approx_gas_for_balance(123_u64, 900), 7),
401+
];
402+
403+
for (lhs, rhs) in tests {
404+
assert_eq!(lhs, rhs);
405+
}
406+
}
385407
}

frame/contracts/src/tests.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,6 +2079,22 @@ fn deploy_and_call_other_contract() {
20792079
});
20802080
}
20812081

2082+
#[test]
2083+
fn deploy_works_without_gas_price() {
2084+
let (wasm, code_hash) = compile_module::<Test>(CODE_GET_RUNTIME_STORAGE).unwrap();
2085+
ExtBuilder::default().existential_deposit(50).gas_price(0).build().execute_with(|| {
2086+
Balances::deposit_creating(&ALICE, 1_000_000);
2087+
assert_ok!(Contracts::put_code(Origin::signed(ALICE), 100_000, wasm));
2088+
assert_ok!(Contracts::instantiate(
2089+
Origin::signed(ALICE),
2090+
100,
2091+
100_000,
2092+
code_hash.into(),
2093+
vec![],
2094+
));
2095+
});
2096+
}
2097+
20822098
const CODE_SELF_DESTRUCT: &str = r#"
20832099
(module
20842100
(import "env" "ext_scratch_size" (func $ext_scratch_size (result i32)))

0 commit comments

Comments
 (0)