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

Test(s) wanted #942

Closed
holiman opened this issue Sep 7, 2021 · 8 comments · Fixed by #943
Closed

Test(s) wanted #942

holiman opened this issue Sep 7, 2021 · 8 comments · Fixed by #943

Comments

@holiman
Copy link
Contributor

holiman commented Sep 7, 2021

Bug report by @guidovranken, concerning py-evm:

Report

When there is insufficient funds for a CREATE/CREATE2 call, Create::call aborts here:

https://github.com/ethereum/py-evm/blob/efa07f743db4437a2762dfcd05535177046507e7/eth/vm/logic/system.py#L162-L164

That way, it never reaches the call to apply_create_message():

https://github.com/ethereum/py-evm/blob/efa07f743db4437a2762dfcd05535177046507e7/eth/vm/logic/system.py#L195

which in turn would call apply_child_computation():

https://github.com/ethereum/py-evm/blob/efa07f743db4437a2762dfcd05535177046507e7/eth/vm/logic/system.py#L198

which in turn would reset the return data:

https://github.com/ethereum/py-evm/blob/efa07f743db4437a2762dfcd05535177046507e7/eth/vm/computation.py#L386

This way, any return data present before the CREATE/CREATE2 call is retained, whereas Geth always resets it.

Bytecode that may be used to reproduce the issue (this uses the RIPEMD160 precompile to set the initial return data and then runs a CREATE2. The difference in stack state after the subsequent RETURNDATASIZE can be observed to confirm the issue).

{
0x5b, 0x59, 0x59, 0x58, 0x33, 0x3d, 0x58, 0x59, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x85, 0xf1, 0x95, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x84, 0x85, 0x85, 0x85, 0x85, 0xf1, 0x95, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0xf1, 0xf5, 0x3d, 0x30
}

__

This also happens when there is a collision:

https://github.com/ethereum/py-evm/blob/efa07f743db4437a2762dfcd05535177046507e7/eth/vm/logic/system.py#L184-L185

__

Reference to py-evm ticket: ethereum/py-evm#2023

@qbzzt
Copy link
Collaborator

qbzzt commented Sep 8, 2021

Why would CREATE2 overwrite the return data? It doesn't have an output buffer the way the CALL opcode family does.

@holiman
Copy link
Contributor Author

holiman commented Sep 8, 2021

https://eips.ethereum.org/EIPS/eip-211:

As an exception, CREATE and CREATE2 are considered to return the empty buffer in the success case and the failure data in the failure case. If the call-like opcode is executed but does not really instantiate a call frame (for example due to insufficient funds for a value transfer or if the called contract does not exist), the return data buffer is empty.

I think the actual reason for this 'quirk' is this:

As an optimization, it is possible to share the return data buffer across call frames because at most one will be non-empty at any time.

@fselmo
Copy link

fselmo commented Sep 8, 2021

Thanks for sending this in. I just pinged the testing discord channel about this test and came here and saw it was already added. Just as an fyi, the changes has for py-evm for this have been merged, just not yet on a release.

PR with the changes here: ethereum/py-evm#2023

qbzzt added a commit that referenced this issue Sep 9, 2021
@qbzzt qbzzt linked a pull request Sep 9, 2021 that will close this issue
@qbzzt
Copy link
Collaborator

qbzzt commented Sep 9, 2021

I found something interesting and unexpected.

When CREATE fails with REVERT in the constructor and a collision(1), it clears the return data buffer (

)

But when CREATE2 fails in the same circumstances (REVERT, and collision), OTOH, the return data buffer is not cleared:

I wonder if other clients behave the same way.

(1) Granted, not an event you can engineer without a hash collision.

@holiman
Copy link
Contributor Author

holiman commented Sep 9, 2021

In geth, the collision is checked prior to executing the initcode. Therefore, there should be no REVERT executed, if you indeed managed to create a collision.
If you provide the t8n inputs (or the filled test), I can investigate this a bit further.

@holiman
Copy link
Contributor Author

holiman commented Sep 9, 2021

Ok, found the test in your PR. Running the test(s), I see this:

Create (legacy), addr: b44f2c88d3d4283cd1e54e418c4ff7e6a6c73202
Create2, addr: 65ee26a034447b6ac64abdca1cccb7b747e4a231
Create (legacy), addr: b44f2c88d3d4283cd1e54e418c4ff7e6a6c73202
Create2, addr: c70dfd0e2a375ca3353f8083ebe24999fa75d02b
Create2, addr: bb0237ab04970e3cf3e813c02064662adc89336b
  Contract Collision!
Create2, addr: 13c950f8740ffaea1869a88d70b029e8b0c9a8da
Create (legacy), addr: f9d1ea8eab6963659ee85b3e0b4d8a57e7edba2b
  Contract Collision!
Create (legacy), addr: f9d1ea8eab6963659ee85b3e0b4d8a57e7edba2b
  Contract Collision!

So there are 4 legacy CREATE, two of them cause collision.
There are 4 CREATE2, and only one of them cause collision.

@qbzzt
Copy link
Collaborator

qbzzt commented Sep 9, 2021

Oops, you're right, thank you for finding it. Consider it fixed, and the weird phenomena to have disappeared.

winsvega pushed a commit that referenced this issue Sep 11, 2021
@jochem-brouwer
Copy link
Member

Checked this in EthereumJS - we do not have this bug.

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 a pull request may close this issue.

4 participants