Skip to content

Commit e533cb0

Browse files
paritytech-release-backport-bot[bot]TorstenStuebergithub-actions[bot]
authored
[unstable2507] Backport #10567 (#10598)
Backport #10567 into `unstable2507` from TorstenStueber. See the [documentation](https://github.com/paritytech/polkadot-sdk/blob/master/docs/BACKPORT.md) on how to use this bot. <!-- # To be used by other automation, do not modify: original-pr-number: #${pull_number} --> Co-authored-by: Torsten Stüber <[email protected]> Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent c916632 commit e533cb0

File tree

3 files changed

+50
-11
lines changed

3 files changed

+50
-11
lines changed

prdoc/pr_10567.prdoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
title: '[Revive] Fix construction of negative zero SignedGas'
2+
doc:
3+
- audience: Runtime Dev
4+
description: |-
5+
Closes https://github.com/paritytech-secops/srlabs_findings/issues/603
6+
7+
This fixes an issue where a zero `SignedGas` value can be constructed that uses the `Negative` variant. The rest of the code relies on the invariant that zero `SignedGas` has always the `Positive` variant and this is also documented in the code.
8+
crates:
9+
- name: pallet-revive
10+
bump: patch

substrate/frame/revive/src/metering/gas.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ impl<T: Config> Default for SignedGas<T> {
4545
}
4646

4747
impl<T: Config> SignedGas<T> {
48+
/// Safely construct a negative `SignedGas` amount
49+
///
50+
/// Ensures the invariant that `Negative` must not be used for zero
51+
pub fn safe_new_negative(amount: BalanceOf<T>) -> Self {
52+
if amount == Default::default() {
53+
Positive(amount)
54+
} else {
55+
Negative(amount)
56+
}
57+
}
58+
4859
/// Transform a weight fee into a gas amount.
4960
pub fn from_weight_fee(weight_fee: BalanceOf<T>) -> Self {
5061
Self::Positive(weight_fee)
@@ -65,8 +76,8 @@ impl<T: Config> SignedGas<T> {
6576

6677
match deposit {
6778
StorageDeposit::Charge(amount) => Positive(multiplier.saturating_mul_int(*amount)),
68-
StorageDeposit::Refund(amount) if *amount == Default::default() => Positive(*amount),
69-
StorageDeposit::Refund(amount) => Negative(multiplier.saturating_mul_int(*amount)),
79+
StorageDeposit::Refund(amount) =>
80+
Self::safe_new_negative(multiplier.saturating_mul_int(*amount)),
7081
}
7182
}
7283

@@ -108,16 +119,16 @@ impl<T: Config> SignedGas<T> {
108119
pub fn saturating_add(&self, rhs: &Self) -> Self {
109120
match (self, rhs) {
110121
(Positive(lhs), Positive(rhs)) => Positive(lhs.saturating_add(*rhs)),
111-
(Negative(lhs), Negative(rhs)) => Negative(lhs.saturating_add(*rhs)),
122+
(Negative(lhs), Negative(rhs)) => Self::safe_new_negative(lhs.saturating_add(*rhs)),
112123
(Positive(lhs), Negative(rhs)) =>
113124
if lhs >= rhs {
114125
Positive(lhs.saturating_sub(*rhs))
115126
} else {
116-
Negative(rhs.saturating_sub(*lhs))
127+
Self::safe_new_negative(rhs.saturating_sub(*lhs))
117128
},
118129
(Negative(lhs), Positive(rhs)) =>
119130
if lhs > rhs {
120-
Negative(lhs.saturating_sub(*rhs))
131+
Self::safe_new_negative(lhs.saturating_sub(*rhs))
121132
} else {
122133
Positive(rhs.saturating_sub(*lhs))
123134
},
@@ -128,16 +139,16 @@ impl<T: Config> SignedGas<T> {
128139
pub fn saturating_sub(&self, rhs: &Self) -> Self {
129140
match (self, rhs) {
130141
(Positive(lhs), Negative(rhs)) => Positive(lhs.saturating_add(*rhs)),
131-
(Negative(lhs), Positive(rhs)) => Negative(lhs.saturating_add(*rhs)),
142+
(Negative(lhs), Positive(rhs)) => Self::safe_new_negative(lhs.saturating_add(*rhs)),
132143
(Positive(lhs), Positive(rhs)) =>
133144
if lhs >= rhs {
134145
Positive(lhs.saturating_sub(*rhs))
135146
} else {
136-
Negative(rhs.saturating_sub(*lhs))
147+
Self::safe_new_negative(rhs.saturating_sub(*lhs))
137148
},
138149
(Negative(lhs), Negative(rhs)) =>
139150
if lhs > rhs {
140-
Negative(lhs.saturating_sub(*rhs))
151+
Self::safe_new_negative(lhs.saturating_sub(*rhs))
141152
} else {
142153
Positive(rhs.saturating_sub(*lhs))
143154
},
@@ -147,10 +158,10 @@ impl<T: Config> SignedGas<T> {
147158
// Determine the minimum of two signed gas values.
148159
pub fn min(&self, other: &Self) -> Self {
149160
match (self, other) {
150-
(Positive(_), Negative(rhs)) => Negative(*rhs),
151-
(Negative(lhs), Positive(_)) => Negative(*lhs),
161+
(Positive(_), Negative(rhs)) => Self::safe_new_negative(*rhs),
162+
(Negative(lhs), Positive(_)) => Self::safe_new_negative(*lhs),
152163
(Positive(lhs), Positive(rhs)) => Positive((*lhs).min(*rhs)),
153-
(Negative(lhs), Negative(rhs)) => Negative((*lhs).max(*rhs)),
164+
(Negative(lhs), Negative(rhs)) => Self::safe_new_negative((*lhs).max(*rhs)),
154165
}
155166
}
156167
}

substrate/frame/revive/src/metering/tests.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,24 @@ enum Charge {
4343
D(i64),
4444
}
4545

46+
#[test]
47+
fn test_deposit_calculation() {
48+
use super::SignedGas;
49+
50+
ExtBuilder::default()
51+
.with_next_fee_multiplier(FixedU128::from_rational(2, 1))
52+
.build()
53+
.execute_with(|| {
54+
let deposit1 = StorageDeposit::Refund(10);
55+
let gas_result1 = SignedGas::<Test>::from_adjusted_deposit_charge(&deposit1);
56+
assert_eq!(gas_result1, SignedGas::Negative(BalanceOf::<Test>::from(5u32)));
57+
58+
let deposit2 = StorageDeposit::Refund(1);
59+
let gas_result2 = SignedGas::<Test>::from_adjusted_deposit_charge(&deposit2);
60+
assert_eq!(gas_result2, SignedGas::Positive(BalanceOf::<Test>::from(0u32)));
61+
});
62+
}
63+
4664
#[test_case(FixtureType::Solc , "DepositPrecompile" ; "solc precompiles")]
4765
#[test_case(FixtureType::Resolc , "DepositPrecompile" ; "resolc precompiles")]
4866
#[test_case(FixtureType::Solc , "DepositDirect" ; "solc direct")]

0 commit comments

Comments
 (0)