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: Fail cleanly on negative gas limit #17486

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

kimbor
Copy link
Member

@kimbor kimbor commented Jan 22, 2025

Description:
When a contract transaction is submitted with a negative gas limit, we currently throw an exception. Instead we should return INSUFFICIENT_GAS.

Related issue(s):
Fixes #17470

@kimbor kimbor added this to the v0.59 milestone Jan 22, 2025
@kimbor kimbor self-assigned this Jan 22, 2025
@kimbor kimbor marked this pull request as ready for review January 22, 2025 20:12
@kimbor kimbor requested review from a team as code owners January 22, 2025 20:12
@kimbor kimbor requested a review from derektriley January 22, 2025 20:12
Copy link

codacy-production bot commented Jan 22, 2025

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
+0.00% (target: -1.00%) 55.56%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (09de95b) 98065 71462 72.87%
Head commit (fe4ca5d) 98083 (+18) 71478 (+16) 72.88% (+0.00%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#17486) 18 10 55.56%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

Codacy stopped sending the deprecated coverage status on June 5th, 2024. Learn more

Copy link

codecov bot commented Jan 22, 2025

Codecov Report

Attention: Patch coverage is 50.00000% with 9 lines in your changes missing coverage. Please review.

Project coverage is 68.97%. Comparing base (09de95b) to head (fe4ca5d).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...edera/node/app/workflows/ingest/IngestChecker.java 43.75% 8 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##               main   #17486   +/-   ##
=========================================
  Coverage     68.96%   68.97%           
- Complexity    22767    22775    +8     
=========================================
  Files          2619     2619           
  Lines         98282    98300   +18     
  Branches      10184    10187    +3     
=========================================
+ Hits          67783    67802   +19     
- Misses        26669    26671    +2     
+ Partials       3830     3827    -3     
Files with missing lines Coverage Δ
...utils/throttles/GasLimitDeterministicThrottle.java 100.00% <100.00%> (ø)
...edera/node/app/workflows/ingest/IngestChecker.java 88.67% <43.75%> (-3.55%) ⬇️

... and 1 file with indirect coverage changes

Impacted file tree graph

Copy link
Member

@david-bakin-sl david-bakin-sl left a comment

Choose a reason for hiding this comment

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

Questions you could answer if you wish, and a request for some testi for the change to GasLimitDeterministicThrottle.

Comment on lines +64 to +66
if (txGasLimit < 0) {
throw new IllegalArgumentException("Gas limit must be non-negative, but was " + txGasLimit);
}
Copy link
Member

Choose a reason for hiding this comment

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

Is this reasonable for it to throw on negative? I traced back one call chain (the one through ThrottleAccumulator.checkAndEnforceThrottle) to QueryWorkflowIMpl.handleQuery which is the first one with a try/catch and it looks like that'll catch it as a Exception, emit an error, and than fail the transaction. Instead of reporting BUSY (which, admittedly, is odd for negative gas, probably should be caught and translated toINSUFFICIENT_GAS). There's another call chain too, I didn't follow it to the tops of it, but doesn't look like any close exception handler there either. If we're sticking with the signature of this method so that it returns boolean maybe it should just return false - it's invalid input so just throttle it.

Or maybe it just needs to throw a PrecheckException instead of IllegalArgumentException.

Copy link
Member

Choose a reason for hiding this comment

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

Also, should have a test for negative in GasLimitDeterministicThrottleTest.

Copy link
Member

Choose a reason for hiding this comment

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

Also, I wonder if we should disallow anything less than the intrinsic gas limit here. It's just going to get rejected at precheck anyway. Is there a reason to disallow those txs earlier? Some kind of fairness or DoS argument?

Copy link
Member Author

Choose a reason for hiding this comment

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

For my first iteration of this PR, I had it throwing a PreCheckException here. I ended up changing that on the grounds that I didn't want to add a dependency on com.hedera.node.app.spi module. The throws IllegalArgumentException is just a sanity check, any execution path should fail long before it gets here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I will add a test for negative gasLimit in GasLimitDeterministicThrottleTest.

.orElse(0L);
default -> 0L;
};
if (gas < 0) {
Copy link
Member

Choose a reason for hiding this comment

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

Again, my question would be: Why <0 instead of <=0 or even <= 21000.

(Don't know the answer here or above, which is why I'm asking.)

In this case you'd have to signal the default case - i.e., not a contract-related operation throttled by gas - separately than using 0L.

Copy link
Member

Choose a reason for hiding this comment

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

Needs a test in IngestCheckerTest.ThrottleTests?

Actually, I don't see a test for any of the conditions in assertThrottlingPreconditions. Also actually, assertThrottlingPreconditions seems misnamed? Until this code you just added it doesn't seem to be checking throttling preconditions at all, just some interesting system preconditions.

Copy link
Member Author

Choose a reason for hiding this comment

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

Most of the preconditions are checked during pureChecks methods on each transaction type. That's where we check whether the gas limit is <=intrinsicGas. But, checking throttles comes earlier in the ingest workflow than running pureChecks. Before we check throttles, we do just the bare minimum checks necessary to ensure that the throttle checking code will succeed. That's what this method is about.

Copy link
Member Author

Choose a reason for hiding this comment

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

And yes, I'll add that test too.

@@ -1272,4 +1272,29 @@ final Stream<DynamicTest> callHtsSystemContractTest() {
.hasKnownStatus(SUCCESS));
}));
}

@HapiTest
final Stream<DynamicTest> negativeGasFailsGracefully() {
Copy link
Member

Choose a reason for hiding this comment

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

This tests new code at IngestChecker.assertThrottlingPreconditions. Needs a separate test for new code at GasLimitDeterministicThrottle.allow. If there's a way to hapispec test throttles, don't know.

Copy link
Member Author

Choose a reason for hiding this comment

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

The GasLimitDeterministicThrottle.allow txGasLimit<0 code path should never execute. I'll create a unit test for it but I don't think there's any way to create a hapi test.

Signed-off-by: Kim Rader <[email protected]>
Signed-off-by: Kim Rader <[email protected]>
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.

throttle error on negative gas
2 participants