Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Coming to agreement with geth on RIPEMD touch revert #5652

Closed
wants to merge 2 commits into from

Conversation

gumb0
Copy link
Member

@gumb0 gumb0 commented Jul 4, 2019

figured cpp does a very complicated thing. It's so complicated that I don't want to describe it.

-- Yoichi Hirai

This is the old issue, originated that time when both Geth and Parity had incorrect revert behavior, and then it was decided to introduce a hack into consensus rules instead of doing huge chain reorg.

The buggy behavior that is now a rule is basically: when precompiled contract with address 0x03 (RIPEMD160) is touched, then exception happens and state changes are reverted, this address should be still considered touched in the end, so that "remove empty touched accounts" rule (EIP-158) deletes it from the state at the end of transaction.

There are several related tests created after this incident:

Dimitriy now has regenerated these latter tests via geth, and now aleth doesn't pass them.

In geth all of these cases look to be handled by just one hack https://github.com/ethereum/go-ethereum/blob/7527215a68eaac8a880be83f3f1ded0ed82f6650/core/state/state_object.go#L145-L149

Our current hack covers only the first tx_xcf416c53 case, because for us failing CALL to precompile is a special case, that doesn't invoke any rollback

// Empty precompiled contracts need to be deleted even in case of OOG
// because the bug in both Geth and Parity led to deleting RIPEMD precompiled in this case
// see https://github.com/ethereum/go-ethereum/pull/3341/files#diff-2433aa143ee4772026454b8abd76b9dd
// We mark the account as touched here, so that is can be removed among other touched empty accounts (after tx finalization)
if (m_envInfo.number() >= m_sealEngine.chainParams().EIP158ForkBlock)
m_s.addBalance(_p.codeAddress, 0);

Now for us to cover the case of OOG in caller's frame, it looks like we unfortunately have to add another similar hack in revert logic.

From the point of view of our code it feels like an unnecessary hack, not related to original problem, but I guess from geth's perspective to replicate our behavior they would need to do some "unnecessary" hacks in their code. Oh well.

More references:

cc @holiman @winsvega

@gumb0
Copy link
Member Author

gumb0 commented Jul 4, 2019

Looks now like the revert tests generated with old testeth are failing, and the tests generated with geth are passing.
Fixed now

@codecov-io
Copy link

Codecov Report

Merging #5652 into master will decrease coverage by 0.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #5652      +/-   ##
==========================================
- Coverage   62.83%   62.81%   -0.02%     
==========================================
  Files         349      348       -1     
  Lines       29722    29709      -13     
  Branches     3346     3347       +1     
==========================================
- Hits        18675    18662      -13     
  Misses       9837     9837              
  Partials     1210     1210

@gumb0
Copy link
Member Author

gumb0 commented Jul 9, 2019

Note that I don't see any difference in test results, if I change our original hack (the one covering failed CALL) to handle only RIPEMD and not other precompiles.

This suggests that tests might not cover the cases of CALL to other empty precompiles with not enough gas and leaving them touched/untouched.
(so similar to tx_xcf416c53, but with other precompiles that are empty and not enough gas passed in CALL params)
Not sure if we should care about this coverage.

@holiman @winsvega

@gumb0 gumb0 requested review from chfast and halfalicious July 9, 2019 16:13
// https://github.com/ethereum/go-ethereum/pull/3341/files#diff-2433aa143ee4772026454b8abd76b9dd
// https://github.com/ethereum/EIPs/issues/716
// https://github.com/ethereum/aleth/pull/5652
if (change.address != c_RipemdPrecompiledAddress)
Copy link
Member

Choose a reason for hiding this comment

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

Uff, this check is actually placed in some hot part of the code...

Copy link
Member Author

@gumb0 gumb0 Jul 9, 2019

Choose a reason for hiding this comment

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

Maybe we could try to introduce some new kind of touch, that is un-revertable and set only for precompiles...

Copy link
Member Author

Choose a reason for hiding this comment

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

@chfast Ok, here's the alternative solution #5663
No hacks in rollback() at the expense of additional flag in Account class.

I think I like it better, at least it allows to have one central piece of weirdness only in Executive.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually now I have a third idea, to keep the list of unrevertably touched accounts in State, instead of putting the flag in each Account.
Third PR is coming...

Copy link
Member Author

Choose a reason for hiding this comment

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

@winsvega
Copy link
Contributor

winsvega commented Jul 10, 2019

tx_xcf416c53

added more tests around touch on precompiled addresses and OOG / NO OOG within the same call, not within the same transaction

ethereum/tests#610

have aleth argue with geth on Byzantium no OOG touch to 0x0000....008 empty account

@gumb0
Copy link
Member Author

gumb0 commented Jul 10, 2019

have aleth argue with geth on Byzantium no OOG touch to 0x0000....008 empty account

have a new test case for this
ethereum/tests#610

This branch and untouch-ripemd-alternative2 branch pass it, did you try with aleth's master?

@gumb0 gumb0 removed the in progress label Jul 10, 2019
@winsvega
Copy link
Contributor

winsvega commented Jul 10, 2019

did you try with aleth's master

no

This branch and untouch-ripemd-alternative2 branch pass it,

good. merging the tests then

@gumb0
Copy link
Member Author

gumb0 commented Jul 11, 2019

Closing in favor of #5664

@gumb0 gumb0 closed this Jul 11, 2019
@gumb0 gumb0 deleted the untouch-ripemd branch July 11, 2019 10:33
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants