-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Never revert on ovmCREATE* #10
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -511,10 +511,17 @@ contract ExecutionManager is FullStateManager { | |
| * calldata: variable-length bytes: | ||
| * [methodID (bytes4)] | ||
| * [ovmInitcode (bytes (variable length))] | ||
| * returndata: [newOvmContractAddress (as bytes32)] | ||
| * returndata: [newOvmContractAddress (as bytes32)] -- will be all 0s if this create failed. | ||
| */ | ||
| function ovmCREATE() public { | ||
| require(!executionContext.inStaticContext, "Cannot create new contracts from a STATICCALL."); | ||
| if (executionContext.inStaticContext) { | ||
| // Cannot create new contracts from a STATICCALL -- return 0 address | ||
| assembly { | ||
| let returnData := mload(0x40) | ||
| mstore(returnData, 0) | ||
| return(returnData, 0x20) | ||
| } | ||
| } | ||
|
|
||
| bytes memory _ovmInitcode; | ||
| assembly { | ||
|
|
@@ -534,7 +541,14 @@ contract ExecutionManager is FullStateManager { | |
| uint creatorNonce = getOvmContractNonce(creator); | ||
| address _newOvmContractAddress = contractAddressGenerator.getAddressFromCREATE(creator, creatorNonce); | ||
| // Next we need to actually create the contract in our state at that address | ||
| createNewContract(_newOvmContractAddress, _ovmInitcode); | ||
| if (!createNewContract(_newOvmContractAddress, _ovmInitcode)) { | ||
| // Failure: Return 0 address | ||
| assembly { | ||
| let returnData := mload(0x40) | ||
| mstore(returnData, 0) | ||
| return(returnData, 0x20) | ||
| } | ||
| } | ||
| // We also need to increment the contract nonce | ||
| incrementOvmContractNonce(creator); | ||
|
|
||
|
|
@@ -557,10 +571,17 @@ contract ExecutionManager is FullStateManager { | |
| * [methodID (bytes4)] | ||
| * [salt (bytes32)] | ||
| * [ovmInitcode (bytes (variable length))] | ||
| * returndata: [newOvmContractAddress (as bytes32)] | ||
| * returndata: [newOvmContractAddress (as bytes32)] -- will be all 0s if this create failed. | ||
| */ | ||
| function ovmCREATE2() public { | ||
| require(!executionContext.inStaticContext, "Cannot create new contracts from a STATICCALL."); | ||
| if (executionContext.inStaticContext) { | ||
| // Cannot create new contracts from a STATICCALL -- return 0 address | ||
| assembly { | ||
| let returnData := mload(0x40) | ||
| mstore(returnData, 0) | ||
| return(returnData, 0x20) | ||
| } | ||
| } | ||
|
|
||
| bytes memory _ovmInitcode; | ||
| bytes32 _salt; | ||
|
|
@@ -582,7 +603,14 @@ contract ExecutionManager is FullStateManager { | |
| address creator = executionContext.ovmActiveContract; | ||
| address _newOvmContractAddress = contractAddressGenerator.getAddressFromCREATE2(creator, _salt, _ovmInitcode); | ||
| // Next we need to actually create the contract in our state at that address | ||
| createNewContract(_newOvmContractAddress, _ovmInitcode); | ||
| if (!createNewContract(_newOvmContractAddress, _ovmInitcode)) { | ||
| // Failure: Return 0 address | ||
| assembly { | ||
| let returnData := mload(0x40) | ||
| mstore(returnData, 0) | ||
| return(returnData, 0x20) | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| } | ||
|
|
||
| // Shifting so that it is left-padded, big-endian ('00'x12 + 20 bytes of address) | ||
| bytes32 newOvmContractAddressBytes32 = bytes32(bytes20(_newOvmContractAddress)) >> 96; | ||
|
|
@@ -601,21 +629,25 @@ contract ExecutionManager is FullStateManager { | |
| * @notice Create a new contract at some OVM contract address. | ||
| * @param _newOvmContractAddress The desired OVM contract address for this new contract we will deploy. | ||
| * @param _ovmInitcode The initcode for our new contract | ||
| * @return True if this succeeded, false otherwise. | ||
| */ | ||
| function createNewContract(address _newOvmContractAddress, bytes memory _ovmInitcode) internal { | ||
| function createNewContract(address _newOvmContractAddress, bytes memory _ovmInitcode) internal returns (bool){ | ||
| // Purity check the initcode -- unless the overridePurityChecker flag is set to true | ||
| require(overridePurityChecker || purityChecker.isBytecodePure(_ovmInitcode), "createNewContract: Contract init code is not pure."); | ||
| if (!overridePurityChecker && !purityChecker.isBytecodePure(_ovmInitcode)) { | ||
| // Contract init code is not pure. | ||
| return false; | ||
| } | ||
| // Switch the context to be the new contract | ||
| (address oldMsgSender, address oldActiveContract) = switchActiveContract(_newOvmContractAddress); | ||
| // Deploy the _ovmInitcode as a code contract -- Note the init script will run in the newly set context | ||
| address codeContractAddress = deployCodeContract(_ovmInitcode); | ||
| // Get the runtime bytecode | ||
| bytes memory codeContractBytecode = getCodeContractBytecode(codeContractAddress); | ||
| // Purity check the runtime bytecode -- unless the overridePurityChecker flag is set to true | ||
| require( | ||
| overridePurityChecker || purityChecker.isBytecodePure(codeContractBytecode), | ||
| "createNewContract: Contract runtime bytecode is not pure." | ||
| ); | ||
| if (!overridePurityChecker && !purityChecker.isBytecodePure(codeContractBytecode)) { | ||
| // Contract runtime bytecode is not pure. | ||
| return false; | ||
| } | ||
| // Associate the code contract with our ovm contract | ||
| associateCodeContract(_newOvmContractAddress, codeContractAddress); | ||
| // Get the code contract address to be emitted by a CreatedContract event | ||
|
|
@@ -624,6 +656,7 @@ contract ExecutionManager is FullStateManager { | |
| restoreContractContext(oldMsgSender, oldActiveContract); | ||
| // Emit CreatedContract event! We've created a new contract! | ||
| emit CreatedContract(_newOvmContractAddress, codeContractAddress, codeContractHash); | ||
| return true; | ||
| } | ||
|
|
||
| /** | ||
|
|
||
16 changes: 16 additions & 0 deletions
16
packages/ovm/src/contracts/testing-contracts/InvalidOpcodes.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| pragma solidity ^0.5.0; | ||
| pragma experimental ABIEncoderV2; | ||
|
|
||
| contract InvalidOpcodes { | ||
| function getCoinbase() public returns (address){ | ||
| return block.coinbase; | ||
| } | ||
|
|
||
| function getDifficulty() public returns (uint){ | ||
| return block.difficulty; | ||
| } | ||
|
|
||
| function getBlockNumber() public returns (uint) { | ||
| return block.number; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know that this is what is returned during a failed STATIC_CALL? I personally don't so just want to make sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep! https://github.com/ethereum-optimism/optimism-monorepo/pull/10/files#diff-712fcb88c95eed4ca84335dd59b7c435R440
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose we had tests for all failures result in 0 address and that static calls to create fail, but I added some tests to make sure that static calls actually return 0 address 👍