-
Notifications
You must be signed in to change notification settings - Fork 375
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(e2e-evm): Add message call tests #2034
Draft
drklee3
wants to merge
19
commits into
dl-e2e-abi-tests-refactor
Choose a base branch
from
dl-e2e-abi-callcode
base: dl-e2e-abi-tests-refactor
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+744
−54
Draft
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
b6fc83e
test: CALLCODE tests to ensure behavior
drklee3 28c3652
docs: add memory safety comments to functionCallCode
drklee3 49fb512
refactor: Move tx params to test cases list
drklee3 5a486f4
test: Add storage function to callcode test contract
drklee3 7e0daac
test: Add callcode storage tests
drklee3 4a98706
test: Add callcode to disabled tests
drklee3 d2df6b7
test: Add callcode to ABI compliance tests
drklee3 99c2f6e
fix: Pass callvalue() to callcode
drklee3 0e39988
refactor: Rename callcode test files for clarity
drklee3 a346d11
test: Verify expected callcode balances
drklee3 c437a06
fix: Prevent assertion skip on 0 expected value
drklee3 38f7cc5
refactor: Test msg sender, value for all msg calls
drklee3 19f36bd
lint: Remove unused imports
drklee3 6f336dc
fix: Increase ABI basic test contractCallerGas
drklee3 8d6101e
refactor: Rename callcode test file
drklee3 b696a23
refactor: Re-add .test suffix to test file
drklee3 6fcd3f8
refactor: Use dynamic context for caller tests
drklee3 428d6c2
test: Expand ctx/storage tests for precompiles
drklee3 83ab338
refactor: Optional expected storage for STATICCALL
drklee3 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 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 |
---|---|---|
|
@@ -9,23 +9,105 @@ pragma solidity ^0.8.24; | |
// Low level caller | ||
// | ||
contract Caller { | ||
/** | ||
* @dev Call a function via CALL with the current msg.value | ||
*/ | ||
function functionCall(address payable to, bytes calldata data) external payable { | ||
(bool success, bytes memory result) = to.call{value: msg.value}(data); | ||
this.functionCallWithValue(to, msg.value, data); | ||
} | ||
|
||
/** | ||
* @dev Call a function via CALL with a specific value that may be different | ||
* from the current msg.value | ||
*/ | ||
function functionCallWithValue(address payable to, uint256 value, bytes calldata data) public payable { | ||
(bool success, bytes memory result) = to.call{value: value}(data); | ||
|
||
if (!success) { | ||
// solhint-disable-next-line gas-custom-errors | ||
if (result.length == 0) revert("reverted with no reason"); | ||
|
||
// solhint-disable-next-line no-inline-assembly | ||
assembly { | ||
// Bubble up errors: revert(pointer, length of revert reason) | ||
// - result is a dynamic array, so the first 32 bytes is the | ||
// length of the array. | ||
// - add(32, result) skips the length of the array and points to | ||
// the start of the data. | ||
// - mload(result) reads 32 bytes from the memory location, | ||
// which is the length of the revert reason. | ||
revert(add(32, result), mload(result)) | ||
} | ||
} | ||
} | ||
|
||
// TODO: Callcode | ||
/** | ||
* @dev Call a contract function via CALLCODE with the current msg.value | ||
*/ | ||
function functionCallCode(address to, bytes calldata data) external payable { | ||
this.functionCallCodeWithValue(to, msg.value, data); | ||
} | ||
|
||
/** | ||
* @dev Call a contract function via CALLCODE with a specific value that may | ||
* be different from the current msg.value | ||
*/ | ||
function functionCallCodeWithValue(address to, uint256 value, bytes calldata data) external payable { | ||
// solhint-disable-next-line no-inline-assembly | ||
assembly { | ||
// Copy the calldata to memory, as callcode uses memory pointers. | ||
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. 💯 and good note on memory safety for future reference if modifying this function |
||
// offset is where the actual data starts in the calldata. Copy the | ||
// data to memory starting at 0. | ||
// Note: We are taking full control of memory as we do not return | ||
// to high-level Solidity code. This would be not memory safe as it | ||
// may exceed the scratch space in the first 64 bytes from 0. | ||
// This should be safe to still do, similar to the OpenZeppelin | ||
// proxy contract, overwriting the full memory scratch pad at | ||
// target 0 AND never returning to high-level Solidity code. | ||
calldatacopy(0, data.offset, data.length) | ||
|
||
// callcode(g, a, v, in, insize, out, outsize) | ||
// returns 0 on error (eg. out of gas) and 1 on success | ||
let result := callcode( | ||
gas(), // gas | ||
to, // to address | ||
value, // value to send | ||
0, // in - pointer to start of input, 0 since we copied the data to 0 | ||
data.length, // insize - size of the input | ||
0, // out | ||
0 // outsize - 0 since we don't know the size of the output | ||
) | ||
|
||
// Copy the returned data to memory. | ||
// returndatacopy(t, f, s) | ||
// - t: target location in memory | ||
// - f: source location in return data | ||
// - s: size | ||
// Note: Same memory safety notes as above with calldatacopy() | ||
returndatacopy(0, 0, returndatasize()) | ||
|
||
switch result | ||
// 0 on error | ||
case 0 { | ||
revert(0, returndatasize()) | ||
} | ||
// 1 on success | ||
case 1 { | ||
return(0, returndatasize()) | ||
} | ||
// Invalid result | ||
default { | ||
revert(0, 0) | ||
} | ||
} | ||
} | ||
|
||
function functionDelegateCall(address to, bytes calldata data) external { | ||
/** | ||
* @dev Call a contract function via DELEGATECALL with the current msg.value | ||
* and current msg.sender. DELEGATECALL cannot specify a different | ||
* value. | ||
*/ | ||
function functionDelegateCall(address to, bytes calldata data) external payable { | ||
// solhint-disable-next-line avoid-low-level-calls | ||
(bool success, bytes memory result) = to.delegatecall(data); | ||
|
||
|
@@ -40,7 +122,12 @@ contract Caller { | |
} | ||
} | ||
|
||
function functionStaticCall(address to, bytes calldata data) external view { | ||
/** | ||
* @dev Call a contract function via STATICCALL with the current msg.value | ||
* and current msg.sender. | ||
* @return The result of the static call in bytes. | ||
*/ | ||
function functionStaticCall(address to, bytes calldata data) external view returns (bytes memory) { | ||
(bool success, bytes memory result) = to.staticcall(data); | ||
|
||
if (!success) { | ||
|
@@ -52,6 +139,8 @@ contract Caller { | |
revert(add(32, result), mload(result)) | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
} | ||
|
||
|
This file contains 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
This file contains 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,43 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.24; | ||
|
||
interface ContextInspector { | ||
/** | ||
* @dev Emitted when the emitMsgSender() function is called. | ||
*/ | ||
event MsgSender(address sender); | ||
|
||
/** | ||
* @dev Emitted when the emitMsgValue() function is called. | ||
* | ||
* Note that `value` may be zero. | ||
*/ | ||
event MsgValue(uint256 value); | ||
|
||
function emitMsgSender() external; | ||
function emitMsgValue() external payable; | ||
function getMsgSender() external view returns (address); | ||
} | ||
|
||
/** | ||
* @title A contract to inspect the msg context. | ||
* @notice This contract is used to test the expected msg.sender and msg.value | ||
* of a contract call in various scenarios. | ||
*/ | ||
contract ContextInspectorMock is ContextInspector { | ||
function emitMsgSender() external { | ||
emit MsgSender(msg.sender); | ||
} | ||
|
||
function emitMsgValue() external payable { | ||
emit MsgValue(msg.value); | ||
} | ||
|
||
/** | ||
* @dev Returns the current msg.sender. This is primarily used for testing | ||
* staticcall as events are not emitted. | ||
*/ | ||
function getMsgSender() external view returns (address) { | ||
return msg.sender; | ||
} | ||
} |
This file contains 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,19 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.24; | ||
|
||
interface StorageBasic { | ||
function setStorageValue(uint256 value) external; | ||
} | ||
|
||
/** | ||
* @title A basic contract with a storage value. | ||
* @notice This contract is used to test storage reads and writes, primarily | ||
* for testing storage behavior in delegateCall. | ||
*/ | ||
contract StorageBasicMock is StorageBasic { | ||
uint256 public storageValue; | ||
|
||
function setStorageValue(uint256 value) external { | ||
storageValue = value; | ||
} | ||
} |
Oops, something went wrong.
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.
Thank you for adding comments where I should have left them 🥇