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

Refund Reset #1111

Merged
merged 5 commits into from
Dec 13, 2022
Merged

Refund Reset #1111

merged 5 commits into from
Dec 13, 2022

Conversation

qbzzt
Copy link
Collaborator

@qbzzt qbzzt commented Dec 6, 2022

Check if the refund amount (for sstore(<cell>, 0)) resets when various things happen.

@jochem-brouwer
Copy link
Member

Here is an edge case with EthereumJS found which is not covered by tests (and also not by this PR). It can only happen on Frontier.

  1. on contract A, a nonzero storage slot is set to zero (so this charges a refund)
  2. contract A creates a new contract B
  3. The code in contract B is ran, however, contract B cannot pay the final code deposit fee (i.e. the gas to pay to deposit the code, per byte, which is 200 gas)
  4. In Frontier/Chainstart this means that: the nonce/balance/storage of contract B is all committed, except that now the code deposited is the empty code (it thus does not change)
  5. contract A succesfully ends the transaction

Our bug happens because in (4) we clear out the storage refunds and the selfdestruct, but this should not happen

@jochem-brouwer
Copy link
Member

@qbzzt
Copy link
Collaborator Author

qbzzt commented Dec 10, 2022

Here is an edge case with EthereumJS found which is not covered by tests (and also not by this PR). It can only happen on Frontier.

  1. on contract A, a nonzero storage slot is set to zero (so this charges a refund)
  2. contract A creates a new contract B
  3. The code in contract B is ran, however, contract B cannot pay the final code deposit fee (i.e. the gas to pay to deposit the code, per byte, which is 200 gas)
  4. In Frontier/Chainstart this means that: the nonce/balance/storage of contract B is all committed, except that now the code deposited is the empty code (it thus does not change)
  5. contract A succesfully ends the transaction

Our bug happens because in (4) we clear out the storage refunds and the selfdestruct, but this should not happen

So it matters exactly where in the CREATE process the OOG happens, just having OOG in the constructor is useless. Let me see how I can get that. Since it's the final stage, I assume that if n is the minimum gas that results in a successful CREATE, n-1 would fail in the right location, right?

@qbzzt
Copy link
Collaborator Author

qbzzt commented Dec 11, 2022

@jochem-brouwer , can you check if the latest test (https://github.com/ethereum/tests/blob/aa7a5b466ad73919995c63e01c80dc34ebe99af6/src/GeneralStateTestsFiller/stRefundTest/refundResetFrontierFiller.yml) covers this corner case? Also, does did it happen only on Frontier, or also on other versions?

@jochem-brouwer
Copy link
Member

I just checked (and might have missed this before, if that is the case - sorry!) - test refundResetFrontier_d2g0v0_Frontier indeed triggers our problem.

It only happens on Frontier. This bug is caused by: there is enough gas to pay for execution for creating a contract, but not enough to pay the final deposit fee. Per Homestead (first hardfork, right after Frontier): https://eips.ethereum.org/EIPS/eip-2, quote; If contract creation does not have enough gas to pay for the final gas fee for adding the contract code to the state, the contract creation fails (i.e. goes out-of-gas) rather than leaving an empty contract. (point 3). This means that the situation which caused this bug cannot happen at Homestead or after (since it does not trigger the "not enough gas for code deposit error")

Thanks for writing these tests 😄

@winsvega
Copy link
Collaborator

Yay! ready to merge?

@qbzzt
Copy link
Collaborator Author

qbzzt commented Dec 12, 2022

It depends. Do we want to generalize it to other similar (not identical) problems? Or is this the kind of rare fluke we don't expect to ever happen again, so we shouldn't look for variants on the theme of refund counter after a failed call.

@winsvega
Copy link
Collaborator

Lets merge this one, the rest can be smth to think about for the future testccases.
Can open an issue

@qbzzt
Copy link
Collaborator Author

qbzzt commented Dec 12, 2022

Sure, it's ready to merge.

@winsvega winsvega merged commit 9e0a5e0 into develop Dec 13, 2022
@winsvega winsvega deleted the 20221204-refund-reset branch December 13, 2022 20:47
@winsvega
Copy link
Collaborator

make an issue in case you would want to return to this topic to write more scenarios. about refund reset in different context

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