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

fix gas balance validation issue when balance < gas cost < SGT balance #14

Merged
merged 3 commits into from
Oct 26, 2024

Conversation

qizhou
Copy link

@qizhou qizhou commented Oct 24, 2024

Description

The fix aims to address the validation issue during the tx submission when balance < gas cost < SGT balance (see #11), including

  • introduce new methods to get balances (native/SGT) and effective gas balance
  • both txpool and gas estimator will use the effective gas balance to validate a tx

Tests

Run a devnet, and be able to

  • submit a tx with zero balance and sufficient SGT balance.
  • submit a zero-value tx with a non-zero-balance account and sufficient SGT balance. I checked that the balance is unchanged and the SGT balance is reduced.
  • submit an all-value tx with a non-zero-balance account and sufficient SGT balance. I checked that the balance is zero and the SGT balance is reduced.

eth/gasestimator/gasestimator.go Outdated Show resolved Hide resolved
@qizhou
Copy link
Author

qizhou commented Oct 24, 2024

Add more test cases to cover the tx.value > 0 issue. The txpool filtering condition (for the same account) is relaxed a bit but it should still work. Please double check.

@@ -382,6 +382,15 @@ func (tx *Transaction) Cost() *big.Int {
return total
}

// Cost returns (gas * gasPrice) + (blobGas * blobGasPrice).
func (tx *Transaction) GasCost() *big.Int {

Choose a reason for hiding this comment

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

I think this is more neat: return new(big.Int).Sub(tx.Cost(), tx.Value()), what do you think ?

@@ -1723,7 +1725,9 @@ func (pool *LegacyPool) demoteUnexecutables() {
pool.all.Remove(hash)
log.Trace("Removed old pending transaction", "hash", hash)
}
balance := core.GetEffectiveGasBalance(pool.currentState, pool.chainconfig, addr)
balance, sgtBalance := core.GetGasBalances(pool.currentState, pool.chainconfig, addr)
Copy link

Choose a reason for hiding this comment

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

What is the reason that we want to relax the txpool filtering condition?

Copy link
Author

Choose a reason for hiding this comment

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

In the case of tx.value == acc.balance, and tx.value > sgtBalance, passing either acc.balance or acc.sgtBalance as balance to filter the tx because of the condition tx.Cost() <= balance. By relaxing balance = acc.balance + acc.sgtBalance, the tx will not be filtered out.

Note that the filter here can be relaxed: it is not guaranteed that all txs of the same account can be executed successfully.

Copy link

Choose a reason for hiding this comment

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

Got it

Choose a reason for hiding this comment

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

What's the worst case for this relax, will it lead to DOS ?

Copy link
Author

Choose a reason for hiding this comment

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

The original filter is already relaxed, but definitively we can do more analysis here (or put TODO here)

Copy link

@blockchaindevsh blockchaindevsh Oct 25, 2024

Choose a reason for hiding this comment

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

Originally if the relax happens(when gas limit < actual gas cost), the balance will become zero quickly, so there's no much room for DOS. But now the evil user may deliberately construct transactions with value that can slip into the tx pool and potentially cause DOS.

}
// Ensure the transactor has enough funds to cover for replacements or nonce
// expansions without overdrafts
spent := opts.ExistingExpenditure(from)
if prev := opts.ExistingCost(from, tx.Nonce()); prev != nil {
bump := new(big.Int).Sub(cost, prev)
need := new(big.Int).Add(spent, bump)
if balance.Cmp(need) < 0 && sgtBalance.Cmp(need) < 0 {

Choose a reason for hiding this comment

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

Looks like we're only handing tx.value for the latest tx, but not for those already queued up; We may also need to accumulate tx.value to handle it completely.

Copy link
Author

Choose a reason for hiding this comment

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

opts.ExistingExpediture() is the function to sum up all tx.Cost(). We should probably separate the cost for tx.Value() and tx.GasCost().

@qizhou
Copy link
Author

qizhou commented Oct 26, 2024

File issue #15 to track the validation issue of multiple txs of the same account. We can close this PR so that it is not a blocking issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants