Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removes fee panics from sdk #1878

Merged
merged 3 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/unreleased/SDK/1878-remove-sdk-fee-panics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Added two new variants to the `TxError` enum, `BalanceToLowForFees` and
`FeeUnshieldingError`, representing possible failures in transactions' fees.
([\#1878](https://github.com/anoma/namada/pull/1878))
2 changes: 2 additions & 0 deletions .changelog/unreleased/bug-fixes/1878-remove-sdk-fee-panics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Removed gas and fees related panics from the sdk.
([\#1878](https://github.com/anoma/namada/pull/1878))
119 changes: 69 additions & 50 deletions shared/src/ledger/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,11 @@ pub async fn aux_signing_data<
};

if fee_payer == masp_tx_key().to_public() {
panic!(
other_err(
"The gas payer cannot be the MASP, please provide a different gas \
payer."
);
.to_string(),
)?;
}

Ok(SigningTxData {
Expand All @@ -301,18 +302,18 @@ pub async fn solve_pow_challenge<C: crate::ledger::queries::Client + Sync>(
total_fee: Amount,
balance: Amount,
source: Address,
) -> Option<crate::core::ledger::testnet_pow::Solution> {
) -> Result<Option<crate::core::ledger::testnet_pow::Solution>, Error> {
let is_bal_sufficient = total_fee <= balance;
if !is_bal_sufficient {
let token_addr = args.fee_token.clone();
let err_msg = format!(
"The wrapper transaction source doesn't have enough balance to \
pay fee {}, got {}.",
format_denominated_amount(client, &token_addr, total_fee).await,
format_denominated_amount(client, &token_addr, balance).await,
);
if !args.force && cfg!(feature = "mainnet") {
panic!("{}", err_msg);
let fee_amount =
format_denominated_amount(client, &token_addr, total_fee).await;
let balance =
format_denominated_amount(client, &token_addr, balance).await;
return Err(Error::from(TxError::BalanceTooLow(
source, token_addr, fee_amount, balance,
)));
}
}
// A PoW solution can be used to allow zero-fee testnet transactions
Expand All @@ -325,9 +326,9 @@ pub async fn solve_pow_challenge<C: crate::ledger::queries::Client + Sync>(

// Solve the solution, this blocks until a solution is found
let solution = challenge.solve();
Some(solution)
Ok(Some(solution))
} else {
None
Ok(None)
}
}

Expand All @@ -339,7 +340,7 @@ pub async fn update_pow_challenge<C: crate::ledger::queries::Client + Sync>(
tx: &mut Tx,
requires_pow: bool,
source: Address,
) {
) -> Result<(), Error> {
let gas_cost_key = parameter_storage::get_gas_cost_key();
let minimum_fee = match rpc::query_storage_value::<
C,
Expand All @@ -349,16 +350,17 @@ pub async fn update_pow_challenge<C: crate::ledger::queries::Client + Sync>(
.and_then(|map| {
map.get(&args.fee_token)
.map(ToOwned::to_owned)
.ok_or_else(|| Error::Other("no fee found".to_string()))
.ok_or_else(|| {
Error::Other(format!(
"Could not retrieve from storage the gas cost for token {}",
args.fee_token
))
})
}) {
Ok(amount) => amount,
Err(_e) => {
eprintln!(
"Could not retrieve the gas cost for token {}",
args.fee_token
);
Err(e) => {
if !args.force {
panic!();
return Err(e);
} else {
token::Amount::default()
}
Expand Down Expand Up @@ -408,13 +410,15 @@ pub async fn update_pow_challenge<C: crate::ledger::queries::Client + Sync>(
balance,
source,
)
.await;
.await?;
wrapper.fee = Fee {
amount_per_gas_unit: fee_amount,
token: args.fee_token.clone(),
};
wrapper.pow_solution = pow_solution;
}

Ok(())
}

/// Informations about the post-tx balance of the tx's source. Used to correctly
Expand Down Expand Up @@ -444,7 +448,7 @@ pub async fn wrap_tx<
epoch: Epoch,
fee_payer: common::PublicKey,
#[cfg(not(feature = "mainnet"))] requires_pow: bool,
) -> Option<Epoch> {
) -> Result<Option<Epoch>, Error> {
let fee_payer_address = Address::from(&fee_payer);
// Validate fee amount and token
let gas_cost_key = parameter_storage::get_gas_cost_key();
Expand All @@ -456,16 +460,17 @@ pub async fn wrap_tx<
.and_then(|map| {
map.get(&args.fee_token)
.map(ToOwned::to_owned)
.ok_or_else(|| Error::Other("no fee found".to_string()))
.ok_or_else(|| {
Error::Other(format!(
"Could not retrieve from storage the gas cost for token {}",
args.fee_token
))
})
}) {
Ok(amount) => amount,
Err(_e) => {
eprintln!(
"Could not retrieve the gas cost for token {}",
args.fee_token
);
Err(e) => {
if !args.force {
panic!();
return Err(e);
} else {
token::Amount::default()
}
Expand Down Expand Up @@ -587,48 +592,62 @@ pub async fn wrap_tx<
&& !args.force
&& cfg!(feature = "mainnet")
{
panic!(
"Fee unshielding descriptions exceed the limit"
);
return Err(Error::from(
TxError::FeeUnshieldingError(format!(
"Descriptions exceed the limit: found \
{descriptions}, limit \
{descriptions_limit}"
)),
));
}

updated_balance += total_fee;
(Some(transaction), Some(unshielding_epoch))
}
Ok(None) => {
eprintln!("Missing unshielding transaction");
if !args.force && cfg!(feature = "mainnet") {
panic!();
return Err(Error::from(
TxError::FeeUnshieldingError(
"Missing unshielding transaction"
.to_string(),
),
));
}

(None, None)
}
Err(e) => {
eprintln!("Error in fee unshielding generation: {}", e);
if !args.force && cfg!(feature = "mainnet") {
panic!();
return Err(Error::from(
TxError::FeeUnshieldingError(e.to_string()),
));
}

(None, None)
}
}
} else {
let token_addr = args.fee_token.clone();
let err_msg = format!(
"The wrapper transaction source doesn't have enough \
balance to pay fee {}, balance: {}.",
format_denominated_amount(client, &token_addr, total_fee)
.await,
format_denominated_amount(
if !args.force && cfg!(feature = "mainnet") {
let fee_amount = format_denominated_amount(
client,
&token_addr,
updated_balance
total_fee,
)
.await,
);
eprintln!("{}", err_msg);
if !args.force && cfg!(feature = "mainnet") {
panic!("{}", err_msg);
.await;

let balance = format_denominated_amount(
client,
&token_addr,
updated_balance,
)
.await;
return Err(Error::from(TxError::BalanceTooLowForFees(
fee_payer_address,
token_addr,
fee_amount,
balance,
)));
}

(None, None)
Expand Down Expand Up @@ -662,7 +681,7 @@ pub async fn wrap_tx<
updated_balance,
fee_payer_address,
)
.await;
.await?;

tx.add_wrapper(
Fee {
Expand All @@ -678,7 +697,7 @@ pub async fn wrap_tx<
unshield_section_hash,
);

unshielding_epoch
Ok(unshielding_epoch)
}

#[allow(clippy::result_large_err)]
Expand Down
4 changes: 2 additions & 2 deletions shared/src/ledger/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ pub async fn prepare_tx<
if !args.dry_run {
let epoch = rpc::query_epoch(client).await?;

Ok(signing::wrap_tx(
signing::wrap_tx(
client,
shielded,
tx,
Expand All @@ -174,7 +174,7 @@ pub async fn prepare_tx<
#[cfg(not(feature = "mainnet"))]
requires_pow,
)
.await)
.await
} else {
Ok(None)
}
Expand Down
9 changes: 9 additions & 0 deletions shared/src/types/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ pub enum TxError {
to be transferred. Amount to transfer is {2} and the balance is {3}."
)]
BalanceTooLow(Address, Address, String, String),
/// Balance is too low for fee payment
#[error(
"The balance of the source {0} of token {1} is lower than the amount \
required for fees. Amount of the fees is {2} and the balance is {3}."
)]
BalanceTooLowForFees(Address, Address, String, String),
/// Token Address does not exist on chain
#[error("The token address {0} doesn't exist on chain.")]
TokenDoesNotExist(Address),
Expand All @@ -213,6 +219,9 @@ pub enum TxError {
/// No Balance found for token
#[error("{0}")]
MaspError(String),
/// Error in the fee unshielding transaction
#[error("Error in fee unshielding: {0}")]
FeeUnshieldingError(String),
/// Wasm validation failed
#[error("Validity predicate code validation failed with {0}")]
WasmValidationFailure(WasmValidationError),
Expand Down
Loading