Skip to content
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
12 changes: 12 additions & 0 deletions prdoc/pr_9942.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
title: 'pallet-revive: Fix dry run balance check logic'
doc:
- audience: Runtime User
description: |-
Fix fault balance check logic during dry-run:

We should not enforce that the sender has enough balance for the fees in case no `gas` is supplied.

cc @TorstenStueber
crates:
- name: pallet-revive
bump: major
25 changes: 14 additions & 11 deletions substrate/frame/revive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1460,20 +1460,22 @@ impl<T: Config> Pallet<T> {
let mut call_info = create_call::<T>(tx, None)
.map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;

// emulate transaction behavior
// the dry-run might leave out certain fields
// in those cases we skip the check that the caller has enough balance
// to pay for the fees
let fees = call_info.tx_fee.saturating_add(call_info.storage_deposit);
match (gas, from, value.is_zero()) {
(Some(_), Some(from), _) | (_, Some(from), false) => {
let balance = Self::evm_balance(&from).saturating_add(value);
if balance < Pallet::<T>::convert_native_to_evm(fees) {
return Err(EthTransactError::Message(format!(
"insufficient funds for gas * price + value: address {from:?} have {balance:?} (supplied gas {gas:?})",
)));
}
},
_ => {},
if let Some(from) = &from {
let fees = if gas.is_some() { fees } else { Zero::zero() };
let balance = Self::evm_balance(from);
if balance < Pallet::<T>::convert_native_to_evm(fees).saturating_add(value) {
return Err(EthTransactError::Message(format!(
"insufficient funds for gas * price + value ({fees:?}): address {from:?} have {balance:?} (supplied gas {gas:?})",
)));
}
Comment on lines +1467 to +1474
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my tests against Geth, the error is also triggered if some value is passed and a user is specified

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you think the old behavior was correct? i.e we should perform the check even if gas is None?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to look again looks like evm tests are green though

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah these tests are failing now

×  unit  src/others.test.ts > eth-rpc > eth_call (not enough funds) 275ms
   → expected 'failed to run contract: Module(Module…' to include 'insufficient funds'
 ×  unit  src/others.test.ts > eth-rpc > eth_call transfer (not enough funds) 135ms
   → expected 'failed to run contract: Module(Module…' to include 'insufficient funds'
 ×  unit  src/others.test.ts > eth-rpc > eth_estimate (not enough funds) 8ms
   → expected 'failed to run contract: Module(Module…' to include 'insufficient funds'
 ×  unit  src/others.test.ts > eth-rpc > eth_estimate call caller (not enough funds) 7ms
   → expected 'failed to run contract: Module(Module…' to include 'insufficient funds'

I added these checks on purpose, if you specify some value, and a from then from should have enough funds when the call is dried run

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new code still does check of you have enough to cover the value. It just skips the check for the txfee if no gas is specified. Because that value will the block gas limit and from might not have enough to pay for all of that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I pushed a fix. Test suite should now be passing.

}

// the deposit is done when the transaction is transformed from an `eth_transact`
// we emulate this behavior for the dry-run her
T::FeeInfo::deposit_txfee(T::Currency::issue(fees));

let extract_error = |err| {
Expand Down Expand Up @@ -1599,6 +1601,7 @@ impl<T: Config> Pallet<T> {
)))?;
}

// not enough gas supplied to pay for both the tx fees and the storage deposit
let transaction_fee = T::FeeInfo::tx_fee(call_info.encoded_len, &call_info.call);
let available_fee = T::FeeInfo::remaining_txfee();
if transaction_fee > available_fee {
Expand Down
Loading