Skip to content

Commit

Permalink
fix: saturating underflows
Browse files Browse the repository at this point in the history
  • Loading branch information
clostao committed Nov 6, 2023
1 parent f8068a2 commit cf65581
Show file tree
Hide file tree
Showing 11 changed files with 8,503 additions and 58 deletions.
8,303 changes: 8,303 additions & 0 deletions chain-specs/testnet.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion node/src/chain_spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use stability_runtime::{opaque::SessionKeys, EnableManualSeal, Signature};
pub mod alphanet;
pub mod betanet;
pub mod dev;
pub mod testnet;

// The URL for the telemetry server.
// const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
Expand Down Expand Up @@ -164,7 +165,7 @@ pub fn base_genesis(
storage: {
let mut storage = BTreeMap::new();
let initial_default_token_balance = H256::from_str("0x00000000000000000000000000000000000000000000d3c21bcecceda1000000").expect("invalid hex storage value"); // 10M
storage.insert(H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000002").expect("invalid hex storage key"), initial_default_token_balance);
storage.insert(H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000002").expect("invalid hex storage key"), initial_default_token_balance); // Total Supply
storage.insert(H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000003").expect("invalid hex storage key"), H256::from_str("0x53746162696c6974792047617320546f6b656e00000000000000000000000026").expect("invalid hex storage value")); // Name
storage.insert(H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000004").expect("invalid hex storage key"), H256::from_str("0x5347540000000000000000000000000000000000000000000000000000000006").expect("invalid hex storage value")); // Symbol
storage.insert(H256::from_str("0x0000000000000000000000000000000000000000000000000000000000000005").expect("invalid hex storage key"), H256::from_str("0x000000000000000000000000af537bd156c7e548d0bf2cd43168dabf7af2feb5").expect("invalid hex storage value")); // Owner
Expand Down
70 changes: 70 additions & 0 deletions node/src/chain_spec/testnet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use super::{base_genesis, get_authority_from_pubkeys, ChainSpec};
use sc_service::ChainType;
use sp_application_crypto::Ss58Codec;
use sp_core::ecdsa;
use sp_runtime::traits::{IdentifyAccount, Verify};
use stability_runtime::{AccountId, Signature, WASM_BINARY};
use std::vec;

type AccountPublic = <Signature as Verify>::Signer;

fn get_account_id_from_public(pubkey: &str) -> AccountId {
AccountPublic::from(ecdsa::Public::from_string(pubkey).unwrap()).into_account()
}

pub fn testnet_config() -> Result<ChainSpec, String> {
let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?;
Ok(ChainSpec::from_genesis(
// Name
"Testnet",
// ID
"testnet",
ChainType::Live,
move || {
base_genesis(
wasm_binary,
vec![
get_authority_from_pubkeys(
"KWECfQF69Vr61qop6NVpesYrnw5WRS4M816286K7NUuVAn2zd",
"5FviP577ihFCP4n8jCnrd38dQDCn2VeM5DAoYNEHbPy7JtWz",
),
get_authority_from_pubkeys(
"KW5B2djwfWnVUPjZALW9NjKPkYc5wA1LSXmYD7HB2QeNoyBX1",
"5FqDv66PJL7TtC49CitcfGNokKJjbL3nwDRmYnQ66BJttUrw",
),
get_authority_from_pubkeys(
"KWAefjXz8rjkX23DYt1tdjUoz9E8PPPQaA5SDULYc1mPpyg6i",
"5GUVATr2DwH51tnqaUEuBtuHA4bLnoWBAkauDxDafMukpZAZ",
),
get_authority_from_pubkeys(
"KWBJnoEoDMniHfxEC2iMv5xLQNwVHV7GdZPCD31eiiLi4niHt",
"5FiEnbnj7VV5CWAtbJXtZjCkiQTBBRqyb8MgXEkydW1SfLiJ",
),
get_authority_from_pubkeys(
"KW7fmVoR3DnYBEX8DwBfPZR2QBLf4uTQvXNm7zweVRWvXqJyt",
"5GzRrcmG4kztd31FPWEcr51B3Jd2GZPh6ZjpxwzymopHuViN",
),
get_authority_from_pubkeys(
"KWBJUVzDvXYKakKX1wuHKqxxH5qg751fHwtaG15KYpuPReU9x",
"5FqhzMYnwsDx4uZYiGVXxJWqvtGwTgMEgYvziEkihE6tfov7",
),
],
vec![get_account_id_from_public(
"KWECfQF69Vr61qop6NVpesYrnw5WRS4M816286K7NUuVAn2zd",
)],
20180427,
)
},
// Bootnodes
vec![],
// Telemetry
None,
// Protocol ID
None,
None,
// Properties
None,
// Extensions
None,
))
}
1 change: 1 addition & 0 deletions node/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl SubstrateCli for Cli {
Ok(match id {
"alphanet" => Box::new(chain_spec::alphanet::alphanet_config()?),
"betanet" => Box::new(chain_spec::betanet::betanet_config()?),
"testnet" => Box::new(chain_spec::testnet::testnet_config()?),
"" | "local" | "dev" => {
let enable_manual_seal = self.sealing.map(|_| true);
Box::new(chain_spec::dev::development_config(enable_manual_seal))
Expand Down
52 changes: 39 additions & 13 deletions pallets/dnt-fee-controller/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub mod pallet {
ERC20WithdrawFailed,
ERC20DepositFailed,
FeeVaultOverflow,
ArithmeticError,
InvalidPercentage,
}

Expand Down Expand Up @@ -105,9 +106,14 @@ pub mod pallet {
) -> Result<(), Self::Error> {
let fee_vault = FeeVaultPrecompileAddressStorage::<T>::get().unwrap();
let mapped_amount = amount
.saturating_mul(conversion_rate.0)
.div_mod(conversion_rate.1)
.0;
.checked_mul(conversion_rate.0)
.map(|v| v.div_mod(conversion_rate.1).0);

let mapped_amount = match mapped_amount {
Some(amount) => amount,
None => return Err(Error::ArithmeticError),
};

T::ERC20Manager::withdraw_amount(token, from, mapped_amount)
.map_err(|_| Error::<T>::ERC20WithdrawFailed)?;
T::ERC20Manager::deposit_amount(token, fee_vault, mapped_amount)
Expand All @@ -123,11 +129,22 @@ pub mod pallet {
paid_amount: U256,
actual_amount: U256,
) -> Result<(), Self::Error> {
let over_fee = paid_amount.saturating_sub(actual_amount);
let over_fee = paid_amount.checked_sub(actual_amount);

let over_fee = match over_fee {
Some(amount) => amount,
None => return Err(Error::ArithmeticError),
};

let mapped_amount = over_fee
.saturating_mul(conversion_rate.0)
.div_mod(conversion_rate.1)
.0;
.checked_mul(conversion_rate.0)
.map(|v| v.div_mod(conversion_rate.1).0);

let mapped_amount = match mapped_amount {
Some(amount) => amount,
None => return Err(Error::ArithmeticError),
};

let fee_vault = FeeVaultPrecompileAddressStorage::<T>::get().unwrap();
T::ERC20Manager::withdraw_amount(token, fee_vault, mapped_amount)
.map_err(|_| Error::<T>::ERC20WithdrawFailed)?;
Expand All @@ -145,19 +162,28 @@ pub mod pallet {
to: Option<H160>,
) -> Result<(U256, U256), Self::Error> {
let fee_in_user_token = actual_amount
.saturating_mul(conversion_rate.0)
.div_mod(conversion_rate.1)
.0;
.checked_mul(conversion_rate.0)
.map(|v| v.div_mod(conversion_rate.1).0);

let fee_in_user_token = match fee_in_user_token {
Some(amount) => amount,
None => return Err(Error::ArithmeticError),
};

let validator_share = match to {
None => 100.into(),
Some(_) => ValidatorPercentageStorage::<T>::get().unwrap(),
};

let validator_fee = fee_in_user_token
.saturating_mul(validator_share.into())
.div_mod(U256::from(100))
.0;
.checked_mul(validator_share.into())
.map(|v| v.div_mod(U256::from(100)).0);

let validator_fee = match validator_fee {
Some(a) => a,
None => return Err(Error::ArithmeticError),
};

let dapp_fee = fee_in_user_token - validator_fee;

pallet_fee_rewards_vault::Pallet::<T>::add_claimable_reward(
Expand Down
49 changes: 36 additions & 13 deletions pallets/sponsored-transactions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,17 @@ pub mod pallet {

let (transaction_fee_token, conversion_rate) = Self::get_fee_token_info(&from);

let max_gas_used = match gas_limit.checked_mul(gas_price.into()) {
Some(a) => a,
None => return Err(DispatchError::Other("Arithmetic error due to overflow.")),
};

Self::transfer_fee_token(
&transaction_fee_token,
conversion_rate,
&meta_trx_sponsor,
&from,
gas_limit.saturating_mul(gas_price.into()),
max_gas_used,
)
.map_err(|_| DispatchError::Other("Failed to borrow fee token"))?;

Expand All @@ -151,16 +156,25 @@ pub mod pallet {
let dispatch = pallet_ethereum::Pallet::<T>::transact(origin, transaction)
.map_err(|_| DispatchError::Other("Signature doesn't meet with sponsor address"))?;

let gas_used = Self::gas_from_actual_weight(dispatch.actual_weight.unwrap());
let gas_used = Self::gas_from_actual_weight(dispatch.actual_weight.unwrap())
.map_err(|_| DispatchError::Other("Arithmetic error due to overflow."))?;

let gas_left = gas_limit.saturating_sub(gas_used.into());
let gas_left = match gas_limit.checked_sub(gas_used.into()) {
Some(v) => v,
None => 0.into(),
};

let refunding_amount = match gas_left.checked_mul(gas_price.into()) {
Some(amount) => amount,
None => return Err(DispatchError::Other("Arithmetic error due to overflow.")),
};

Self::transfer_fee_token(
&transaction_fee_token,
conversion_rate,
&from,
&meta_trx_sponsor,
gas_left.saturating_mul(gas_price.into()),
refunding_amount,
)
.map_err(|_| DispatchError::Other("Failed to refund fee token"))?;

Expand Down Expand Up @@ -281,14 +295,19 @@ pub mod pallet {
}
}

fn gas_from_actual_weight(weight: Weight) -> u64 {
let actual_weight = weight.saturating_add(
T::BlockWeights::get()
fn gas_from_actual_weight(weight: Weight) -> Result<u64, ()> {
let actual_weight = match weight.checked_add(
&T::BlockWeights::get()
.get(frame_support::dispatch::DispatchClass::Normal)
.base_extrinsic,
);
) {
Some(v) => v,
None => return Err(()),
};

<T as pallet_evm::Config>::GasWeightMapping::weight_to_gas(actual_weight)
Ok(<T as pallet_evm::Config>::GasWeightMapping::weight_to_gas(
actual_weight,
))
}

fn ensure_sponsor_balance(sponsor: H160, token: H160, amount: U256) -> Result<(), ()> {
Expand All @@ -307,10 +326,14 @@ pub mod pallet {
payee: &H160,
amount: U256,
) -> Result<(), ()> {
let actual_amount = amount
.saturating_mul(conversion_rate.0)
.div_mod(conversion_rate.1)
.0;
let actual_amount = match amount
.checked_mul(conversion_rate.0)
.map(|v| v.div_mod(conversion_rate.1).0)
{
Some(v) => v,
None => return Err(()),
};

T::ERC20Manager::withdraw_amount(token.clone(), payer.clone(), actual_amount)
.map_err(|_| {})?;

Expand Down
4 changes: 2 additions & 2 deletions pallets/sponsored-transactions/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,9 @@ fn check_correct_fee_management(called_arguments: Vec<(bool, H160, H160, U256)>)
for (is_deposit, token, _, amount) in called_arguments.iter() {
assert!(token.eq(&called_arguments[0].1));
if *is_deposit {
total_deposited = amount.saturating_add(total_deposited);
total_deposited = amount.checked_add(total_deposited).unwrap();
} else {
total_withdrawn = amount.saturating_add(total_withdrawn);
total_withdrawn = amount.checked_add(total_withdrawn).unwrap();
}
}
assert_eq!(total_deposited, total_withdrawn);
Expand Down
7 changes: 6 additions & 1 deletion pallets/validator-set/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,10 +465,15 @@ impl<T: Config> Pallet<T> {
fn do_remove_validator(validator_id: T::AccountId) -> DispatchResult {
let mut validators = <Validators<T>>::get();

let validators_count = match validators.len().checked_sub(1) {
Some(v) => v,
None => return Err(DispatchError::Other("Arithmetic error due to underflow.")),
};

// Ensuring that the post removal, target validator count doesn't go
// below the minimum.
ensure!(
validators.len().saturating_sub(1) as u32 >= T::MinAuthorities::get(),
validators_count as u32 >= T::MinAuthorities::get(),
Error::<T>::TooLowValidatorCount
);

Expand Down
Loading

0 comments on commit cf65581

Please sign in to comment.