Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
cf113fec
Commit
cf113fec
authored
Sep 21, 2020
by
Kelvin Fichter
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Started porting tests
parent
3e81548f
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1487 additions
and
1751 deletions
+1487
-1751
OVM_ExecutionManager.sol
...ptimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol
+14
-1
Helper_CodeContracts.sol
...contracts/contracts/test-helpers/Helper_CodeContracts.sol
+0
-149
Helper_TestRunner.sol
...es/contracts/contracts/test-helpers/Helper_TestRunner.sol
+173
-0
package.json
packages/contracts/package.json
+1
-1
ovmCALL.spec.ts
...tracts/OVM/execution/OVM_ExecutionManager/ovmCALL.spec.ts
+132
-167
ovmCREATE.spec.ts
...acts/OVM/execution/OVM_ExecutionManager/ovmCREATE.spec.ts
+474
-553
OVM_test.spec.ts
...s/contracts/test/contracts/OVM/execution/OVM_test.spec.ts
+155
-0
constants.ts
packages/contracts/test/helpers/constants.ts
+2
-1
mock-binding.ts
packages/contracts/test/helpers/mocks/mock-binding.ts
+1
-1
index.ts
packages/contracts/test/helpers/test-utils/index.ts
+1
-2
test-generation.ts
...ages/contracts/test/helpers/test-utils/test-generation.ts
+0
-591
test-parsing.ts
packages/contracts/test/helpers/test-utils/test-parsing.ts
+0
-260
test-runner.ts
packages/contracts/test/helpers/test-utils/test-runner.ts
+319
-0
test.types.ts
packages/contracts/test/helpers/test-utils/test.types.ts
+215
-25
No files found.
packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_ExecutionManager.sol
View file @
cf113fec
...
@@ -14,6 +14,9 @@ import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol"
...
@@ -14,6 +14,9 @@ import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol"
/* Contract Imports */
/* Contract Imports */
import { OVM_ECDSAContractAccount } from "../accounts/OVM_ECDSAContractAccount.sol";
import { OVM_ECDSAContractAccount } from "../accounts/OVM_ECDSAContractAccount.sol";
/* Logging */
import { console } from "@nomiclabs/buidler/console.sol";
/**
/**
* @title OVM_ExecutionManager
* @title OVM_ExecutionManager
*/
*/
...
@@ -724,7 +727,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
...
@@ -724,7 +727,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
address ethAddress = Lib_EthUtils.createContract(_bytecode);
address ethAddress = Lib_EthUtils.createContract(_bytecode);
// Now reset this flag so we go back to normal revert behavior.
// Now reset this flag so we go back to normal revert behavior.
messageContext.isCreation =
tru
e;
messageContext.isCreation =
fals
e;
// Contract creation returns the zero address when it fails, which should only be possible
// Contract creation returns the zero address when it fails, which should only be possible
// if the user intentionally runs out of gas. However, we might still have a bit of gas
// if the user intentionally runs out of gas. However, we might still have a bit of gas
...
@@ -1252,6 +1255,16 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
...
@@ -1252,6 +1255,16 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
return bytes('');
return bytes('');
}
}
// INVALID_STATE_ACCESS doesn't need to return any data other than the flag.
if (_flag == RevertFlag.INVALID_STATE_ACCESS) {
return abi.encode(
_flag,
0,
0,
bytes('')
);
}
// Just ABI encode the rest of the parameters.
// Just ABI encode the rest of the parameters.
return abi.encode(
return abi.encode(
_flag,
_flag,
...
...
packages/contracts/contracts/test-helpers/Helper_CodeContracts.sol
deleted
100644 → 0
View file @
3e81548f
pragma solidity >=0.7.0;
pragma experimental ABIEncoderV2;
import {console} from "@nomiclabs/buidler/console.sol";
interface Helper_CodeContractDataTypes {
struct CALLResponse {
bool success;
bytes data;
}
}
contract Helper_CodeContractForCalls is Helper_CodeContractDataTypes {
bytes constant sampleCREATEData = abi.encodeWithSignature("ovmCREATE(bytes)", hex"");
bytes constant sampleCREATE2Data = abi.encodeWithSignature("ovmCREATE2(bytes,bytes32)", hex"", 0x4242424242424242424242424242424242424242424242424242424242424242);
function runSteps(
bytes[] memory callsToEM,
bool _shouldRevert,
address _createEMResponsesStorer
) public returns(CALLResponse[] memory) {
console.log("in runSteps()");
uint numSteps = callsToEM.length;
CALLResponse[] memory EMResponses = new CALLResponse[](numSteps);
for (uint i = 0; i < numSteps; i++) {
bytes memory dataToSend = callsToEM[i];
console.log("calling EM with data:");
console.logBytes(dataToSend);
(bool success, bytes memory responseData) = address(msg.sender).call(dataToSend);
console.log("step to EM had result:");
console.logBool(success);
EMResponses[i].success = success;
if (_isOVMCreateCall(dataToSend)) {
console.log("step to EM returned data:");
console.logBytes(responseData);
EMResponses[i].data = abi.encode(
responseData,
_getStoredEMREsponsesInCreate(_createEMResponsesStorer)
);
console.log("since this is create step, stored concatenation:");
console.logBytes(EMResponses[i].data);
} else {
console.log("step to EM returned data:");
console.logBytes(responseData);
EMResponses[i].data = responseData;
}
}
return EMResponses;
}
function _getStoredEMREsponsesInCreate(address _createEMResponsesStorer) internal returns(bytes memory) {
(bool success, bytes memory data) = _createEMResponsesStorer.call(abi.encodeWithSignature("getLastResponses()"));
return data;
}
function _isOVMCreateCall(bytes memory _calldata) public returns(bool) {
return (
_doMethodIdsMatch(_calldata, sampleCREATEData) || _doMethodIdsMatch(_calldata, sampleCREATE2Data)
);
}
function _doMethodIdsMatch(bytes memory _calldata1, bytes memory _calldata2) internal returns(bool) {
return (
_calldata1[0] == _calldata2[0] &&
_calldata1[1] == _calldata2[1] &&
_calldata1[2] == _calldata2[2] &&
_calldata1[3] == _calldata2[3]
);
}
}
contract Helper_CodeContractForCreates is Helper_CodeContractForCalls {
constructor(
bytes[] memory callsToEM,
bool _shouldRevert,
bytes memory _codeToDeploy,
address _createEMResponsesStorer
) {
console.log("In CREATE helper (deployment)");
CALLResponse[] memory responses = runSteps(callsToEM, _shouldRevert, _createEMResponsesStorer);
Helper_CreateEMResponsesStorer(_createEMResponsesStorer).store(responses);
uint lengthToDeploy = _codeToDeploy.length;
// todo revert if _shouldrevert
assembly {
return(add(_codeToDeploy, 0x20), lengthToDeploy)
}
}
}
contract Helper_CreateEMResponsesStorer is Helper_CodeContractDataTypes {
CALLResponse[] responses;
function store(
CALLResponse[] memory _responses
) public {
console.log("create storer helper is storing responses...");
for (uint i = 0; i < _responses.length; i++) {
responses.push();
responses[i] = _responses[i];
}
console.log("helper successfully stored this many responses:");
console.logUint(responses.length);
}
function getLastResponses() public returns(CALLResponse[] memory) {
console.log("helper is retreiving last stored responses. It has this many responses stored:");
console.logUint(responses.length);
CALLResponse[] memory toReturn = responses;
delete responses;
return toReturn;
}
}
contract Helper_CodeContractForReverts {
function doRevert(
bytes memory _revertdata
) public {
uint revertLength = _revertdata.length;
assembly {
revert(add(_revertdata, 0x20), revertLength)
}
}
}
// note: behavior of this contract covers all 3 cases of EVM message exceptions:
// - out of gas
// - INVALID opcode
// - invalid JUMPDEST
contract Helper_CodeContractForInvalid {
function doInvalid() public {
assembly {
invalid()
}
}
}
// note: behavior of this contract covers all 3 cases of EVM message exceptions:
// - out of gas
// - INVALID opcode
// - invalid JUMPDEST
contract Helper_CodeContractForInvalidInCreation {
constructor() public {
assembly {
invalid()
}
}
}
packages/contracts/contracts/test-helpers/Helper_TestRunner.sol
0 → 100644
View file @
cf113fec
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Logging */
import { console } from "@nomiclabs/buidler/console.sol";
/**
* @title Helper_TestRunner
*/
contract Helper_TestRunner {
struct TestStep {
string functionName;
bytes functionData;
bool expectedReturnStatus;
bytes expectedReturnData;
}
function runSingleTestStep(
TestStep memory _step
)
public
{
bytes32 namehash = keccak256(abi.encodePacked(_step.functionName));
if (namehash == keccak256("evmRETURN")) {
bytes memory returndata = _step.functionData;
assembly {
return(add(returndata, 0x20), mload(returndata))
}
}
if (namehash == keccak256("evmREVERT")) {
bytes memory returndata = _step.functionData;
assembly {
revert(add(returndata, 0x20), mload(returndata))
}
}
if (namehash == keccak256("evmINVALID")) {
assembly {
invalid()
}
}
(bool success, bytes memory returndata) = address(msg.sender).call(_step.functionData);
if (success != _step.expectedReturnStatus) {
if (success == true) {
console.log("ERROR: Expected function to revert, but function returned successfully");
console.log("Offending Step: %s", _step.functionName);
console.log("Return Data:");
console.logBytes(returndata);
console.log("");
} else {
(
uint256 _flag,
uint256 _nuisanceGasLeft,
uint256 _ovmGasRefund,
bytes memory _data
) = _decodeRevertData(returndata);
console.log("ERROR: Expected function to return successfully, but function reverted");
console.log("Offending Step: %s", _step.functionName);
console.log("Flag: %s", _flag);
console.log("Nuisance Gas Left: %s", _nuisanceGasLeft);
console.log("OVM Gas Refund: %s", _ovmGasRefund);
console.log("Extra Data:");
console.logBytes(_data);
console.log("");
}
revert("Test step failed.");
}
if (keccak256(returndata) != keccak256(_step.expectedReturnData)) {
if (success == true) {
console.log("ERROR: Actual return data does not match expected return data");
console.log("Offending Step: %s", _step.functionName);
console.log("Expected:");
console.logBytes(_step.expectedReturnData);
console.log("Actual:");
console.logBytes(returndata);
console.log("");
} else {
(
uint256 _expectedFlag,
uint256 _expectedNuisanceGasLeft,
uint256 _expectedOvmGasRefund,
bytes memory _expectedData
) = _decodeRevertData(_step.expectedReturnData);
(
uint256 _flag,
uint256 _nuisanceGasLeft,
uint256 _ovmGasRefund,
bytes memory _data
) = _decodeRevertData(returndata);
console.log("ERROR: Actual revert flag data does not match expected revert flag data");
console.log("Offending Step: %s", _step.functionName);
console.log("Expected Flag: %s", _expectedFlag);
console.log("Actual Flag: %s", _flag);
console.log("Expected Nuisance Gas Left: %s", _expectedNuisanceGasLeft);
console.log("Actual Nuisance Gas Left: %s", _nuisanceGasLeft);
console.log("Expected OVM Gas Refund: %s", _expectedOvmGasRefund);
console.log("Actual OVM Gas Refund: %s", _ovmGasRefund);
console.log("Expected Extra Data:");
console.logBytes(_expectedData);
console.log("Actual Extra Data:");
console.logBytes(_data);
console.log("");
}
revert("Test step failed.");
}
if (success == false || (success == true && returndata.length == 1)) {
assembly {
if eq(extcodesize(address()), 0) {
return(0, 1)
}
revert(add(returndata, 0x20), mload(returndata))
}
}
}
function runMultipleTestSteps(
TestStep[] memory _steps
)
public
{
for (uint256 i = 0; i < _steps.length; i++) {
runSingleTestStep(_steps[i]);
}
}
function _decodeRevertData(
bytes memory _revertdata
)
internal
returns (
uint256 _flag,
uint256 _nuisanceGasLeft,
uint256 _ovmGasRefund,
bytes memory _data
)
{
if (_revertdata.length == 0) {
return (
0,
0,
0,
bytes('')
);
}
return abi.decode(_revertdata, (uint256, uint256, uint256, bytes));
}
}
contract Helper_TestRunner_CREATE is Helper_TestRunner {
constructor(
bytes memory _bytecode,
TestStep[] memory _steps
) {
if (_steps.length > 0) {
runMultipleTestSteps(_steps);
} else {
assembly {
return(add(_bytecode, 0x20), mload(_bytecode))
}
}
}
}
packages/contracts/package.json
View file @
cf113fec
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
"build"
:
"yarn run build:contracts"
,
"build"
:
"yarn run build:contracts"
,
"build:contracts"
:
"buidler compile"
,
"build:contracts"
:
"buidler compile"
,
"test"
:
"yarn run test:contracts"
,
"test"
:
"yarn run test:contracts"
,
"test:contracts"
:
"buidler test
\"
test/contracts/OVM/execution/OVM_ExecutionManager/ovm
STATICCALL
.spec.ts
\"
"
,
"test:contracts"
:
"buidler test
\"
test/contracts/OVM/execution/OVM_ExecutionManager/ovm
CREATE
.spec.ts
\"
"
,
"lint"
:
"tslint --format stylish --project ."
,
"lint"
:
"tslint --format stylish --project ."
,
"fix"
:
"prettier --config prettier-config.json --write
\"
buidler.config.ts
\"
\"
{src,test}/**/*.ts
\"
"
"fix"
:
"prettier --config prettier-config.json --write
\"
buidler.config.ts
\"
\"
{src,test}/**/*.ts
\"
"
},
},
...
...
packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/ovmCALL.spec.ts
View file @
cf113fec
/* Internal Imports */
/* Internal Imports */
import
{
import
{
runExecutionManagerTest
,
ExecutionManagerTestRunner
,
TestDefinition
,
TestDefinition
,
GAS_LIMIT
,
GAS_LIMIT
,
NULL_BYTES32
,
NON_NULL_BYTES32
,
NON_NULL_BYTES32
,
REVERT_FLAGS
,
REVERT_FLAGS
,
DUMMY_BYTECODE
,
VERIFIED_EMPTY_CONTRACT_HASH
,
VERIFIED_EMPTY_CONTRACT_HASH
,
}
from
'
../../../../helpers
'
}
from
'
../../../../helpers
'
...
@@ -43,236 +41,203 @@ const test_ovmCALL: TestDefinition = {
...
@@ -43,236 +41,203 @@ const test_ovmCALL: TestDefinition = {
},
},
parameters
:
[
parameters
:
[
{
{
name
:
'
ovmCALL(ADDRESS_1) => ovmADDRESS
'
,
steps
:
[
steps
:
[
{
{
functionName
:
'
ovmCALL
'
,
functionName
:
'
ovmCALL
'
,
functionParams
:
[
functionParams
:
{
GAS_LIMIT
/
2
,
gasLimit
:
GAS_LIMIT
,
'
$DUMMY_OVM_ADDRESS_1
'
,
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
[
subSteps
:
[
{
{
functionName
:
'
ovmCALL
'
,
functionName
:
'
ovmADDRESS
'
,
functionParams
:
[
expectedReturnValue
:
'
$DUMMY_OVM_ADDRESS_1
'
,
GAS_LIMIT
/
2
,
},
'
$DUMMY_OVM_ADDRESS_2
'
,
],
[
},
{
expectedReturnStatus
:
true
,
functionName
:
'
ovmCALLER
'
,
},
functionParams
:
[],
],
expectedReturnStatus
:
true
,
},
expectedReturnValues
:
[
'
$DUMMY_OVM_ADDRESS_1
'
],
{
},
name
:
'
ovmCALL(ADDRESS_1) => ovmSSTORE
'
,
{
steps
:
[
functionName
:
'
ovmADDRESS
'
,
{
functionParams
:
[],
functionName
:
'
ovmCALL
'
,
expectedReturnStatus
:
true
,
functionParams
:
{
expectedReturnValues
:
[
'
$DUMMY_OVM_ADDRESS_2
'
],
gasLimit
:
GAS_LIMIT
,
},
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
{
subSteps
:
[
functionName
:
'
ovmSSTORE
'
,
{
functionParams
:
[
NON_NULL_BYTES32
,
NON_NULL_BYTES32
],
functionName
:
'
ovmSSTORE
'
,
expectedReturnStatus
:
true
,
functionParams
:
{
expectedReturnValues
:
[],
key
:
NON_NULL_BYTES32
,
},
value
:
NON_NULL_BYTES32
,
{
},
functionName
:
'
ovmSLOAD
'
,
functionParams
:
[
NON_NULL_BYTES32
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
NON_NULL_BYTES32
],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
},
],
},
expectedReturnStatus
:
true
,
},
],
},
{
name
:
'
ovmCALL(ADDRESS_1) => ovmSSTORE + ovmSLOAD, ovmCALL(ADDRESS_1) => ovmSLOAD
'
,
steps
:
[
{
functionName
:
'
ovmCALL
'
,
functionParams
:
{
gasLimit
:
GAS_LIMIT
,
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
subSteps
:
[
{
{
functionName
:
'
ovmCALL
'
,
functionName
:
'
ovmSSTORE
'
,
functionParams
:
[
functionParams
:
{
GAS_LIMIT
/
2
,
key
:
NON_NULL_BYTES32
,
'
$DUMMY_OVM_ADDRESS_2
'
,
value
:
NON_NULL_BYTES32
,
[
},
{
expectedReturnStatus
:
true
,
functionName
:
'
ovmSLOAD
'
,
},
functionParams
:
[
NON_NULL_BYTES32
],
{
expectedReturnStatus
:
true
,
functionName
:
'
ovmSLOAD
'
,
expectedReturnValues
:
[
NON_NULL_BYTES32
],
functionParams
:
{
},
key
:
NON_NULL_BYTES32
,
],
},
],
expectedReturnStatus
:
true
,
expectedReturnStatus
:
true
,
expectedReturnValue
s
:
[]
,
expectedReturnValue
:
NON_NULL_BYTES32
,
},
},
],
],
],
},
expectedReturnStatus
:
true
,
},
{
functionName
:
'
ovmCALL
'
,
functionParams
:
{
gasLimit
:
GAS_LIMIT
,
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
subSteps
:
[
{
functionName
:
'
ovmSLOAD
'
,
functionParams
:
{
key
:
NON_NULL_BYTES32
,
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
NON_NULL_BYTES32
,
},
],
},
expectedReturnStatus
:
true
,
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
},
],
],
},
},
{
{
name
:
'
ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmADDRESS + ovmCALLER
'
,
steps
:
[
steps
:
[
{
{
functionName
:
'
ovmCALL
'
,
functionName
:
'
ovmCALL
'
,
functionParams
:
[
functionParams
:
{
GAS_LIMIT
/
2
,
gasLimit
:
GAS_LIMIT
,
'
$DUMMY_OVM_ADDRESS_1
'
,
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
[
subSteps
:
[
{
{
functionName
:
'
ovmCALL
'
,
functionName
:
'
ovmCALL
'
,
functionParams
:
[
functionParams
:
{
GAS_LIMIT
/
2
,
gasLimit
:
GAS_LIMIT
,
'
$DUMMY_OVM_ADDRESS_2
'
,
target
:
'
$DUMMY_OVM_ADDRESS_2
'
,
[
subSteps
:
[
{
functionName
:
'
ovmCALLER
'
,
functionParams
:
[],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
'
$DUMMY_OVM_ADDRESS_1
'
],
},
{
{
functionName
:
'
ovmADDRESS
'
,
functionName
:
'
ovmADDRESS
'
,
functionParams
:
[],
expectedReturnValue
:
'
$DUMMY_OVM_ADDRESS_2
'
,
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
'
$DUMMY_OVM_ADDRESS_2
'
],
},
},
{
{
functionName
:
'
ovmSSTORE
'
,
functionName
:
'
ovmCALLER
'
,
functionParams
:
[
NON_NULL_BYTES32
,
NON_NULL_BYTES32
],
expectedReturnValue
:
'
$DUMMY_OVM_ADDRESS_1
'
,
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
{
functionName
:
'
ovmSLOAD
'
,
functionParams
:
[
NON_NULL_BYTES32
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
NON_NULL_BYTES32
],
},
},
],
],
]
,
}
,
expectedReturnStatus
:
true
,
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
},
],
],
]
,
}
,
expectedReturnStatus
:
true
,
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
},
],
],
},
},
{
{
name
:
'
ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_3)
'
,
steps
:
[
steps
:
[
{
{
functionName
:
'
ovmCALL
'
,
functionName
:
'
ovmCALL
'
,
functionParams
:
[
functionParams
:
{
GAS_LIMIT
/
2
,
gasLimit
:
GAS_LIMIT
,
'
$DUMMY_OVM_ADDRESS_1
'
,
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
[
subSteps
:
[
{
{
functionName
:
'
ovmCALL
'
,
functionName
:
'
ovmCALL
'
,
functionParams
:
[
GAS_LIMIT
/
2
,
'
$DUMMY_OVM_ADDRESS_3
'
,
[]],
functionParams
:
{
gasLimit
:
GAS_LIMIT
,
target
:
'
$DUMMY_OVM_ADDRESS_3
'
,
calldata
:
'
0x
'
,
},
expectedReturnStatus
:
true
,
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
true
,
'
0x
'
],
},
},
],
],
]
,
}
,
expectedReturnStatus
:
true
,
expectedReturnStatus
:
true
,
expectedReturnValue
s
:
[]
,
expectedReturnValue
:
'
0x
'
,
},
},
],
],
},
},
],
}
const
test_ovmCALL_revert
:
TestDefinition
=
{
name
:
'
Basic reverts in a code contract called via ovmCALL
'
,
preState
:
{
ExecutionManager
:
{
ovmStateManager
:
'
$OVM_STATE_MANAGER
'
,
ovmSafetyChecker
:
'
$OVM_SAFETY_CHECKER
'
,
messageRecord
:
{
nuisanceGasLeft
:
GAS_LIMIT
,
},
},
StateManager
:
{
owner
:
'
$OVM_EXECUTION_MANAGER
'
,
accounts
:
{
$DUMMY_OVM_ADDRESS_1
:
{
codeHash
:
NON_NULL_BYTES32
,
ethAddress
:
'
$OVM_CALL_HELPER
'
,
},
$DUMMY_OVM_ADDRESS_2
:
{
codeHash
:
NON_NULL_BYTES32
,
ethAddress
:
'
$OVM_REVERT_HELPER
'
,
},
$DUMMY_OVM_ADDRESS_3
:
{
codeHash
:
NON_NULL_BYTES32
,
ethAddress
:
'
$OVM_REVERT_HELPER
'
,
},
$DUMMY_OVM_ADDRESS_4
:
{
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
},
},
},
},
parameters
:
[
{
{
name
:
'
ovmCALL(ADDRESS_1) => INTENTIONAL_REVERT
'
,
steps
:
[
steps
:
[
{
{
functionName
:
'
ovmCALL
'
,
functionName
:
'
ovmCALL
'
,
functionParams
:
[
functionParams
:
{
GAS_LIMIT
/
2
,
gasLimit
:
GAS_LIMIT
,
'
$DUMMY_OVM_ADDRESS_1
'
,
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
[
subSteps
:
[
{
{
functionName
:
'
ovmCALLToRevert
'
,
functionName
:
'
evmREVERT
'
,
functionParams
:
[
returnData
:
{
GAS_LIMIT
/
2
,
flag
:
REVERT_FLAGS
.
INTENTIONAL_REVERT
,
'
$DUMMY_OVM_ADDRESS_2
'
,
data
:
DUMMY_REVERT_DATA
,
[
},
REVERT_FLAGS
.
INTENTIONAL_REVERT
,
DUMMY_REVERT_DATA
,
GAS_LIMIT
/
2
,
0
,
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
false
,
DUMMY_REVERT_DATA
],
},
},
],
],
]
,
}
,
expectedReturnStatus
:
tru
e
,
expectedReturnStatus
:
fals
e
,
expectedReturnValue
s
:
[]
,
expectedReturnValue
:
DUMMY_REVERT_DATA
,
},
},
],
],
},
},
{
{
name
:
'
ovmCALL(ADDRESS_1) => EXCEEDS_NUISANCE_GAS
'
,
steps
:
[
steps
:
[
{
{
functionName
:
'
ovmCALL
'
,
functionName
:
'
ovmCALL
'
,
functionParams
:
[
functionParams
:
{
GAS_LIMIT
/
2
,
gasLimit
:
GAS_LIMIT
,
'
$DUMMY_OVM_ADDRESS_1
'
,
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
[
subSteps
:
[
{
{
functionName
:
'
ovmCALLToRevert
'
,
functionName
:
'
evmREVERT
'
,
functionParams
:
[
returnData
:
{
GAS_LIMIT
/
2
,
flag
:
REVERT_FLAGS
.
EXCEEDS_NUISANCE_GAS
,
'
$DUMMY_OVM_ADDRESS_2
'
,
},
[
REVERT_FLAGS
.
EXCEEDS_NUISANCE_GAS
,
'
0x
'
,
0
,
0
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
false
,
'
0x
'
],
},
},
],
],
]
,
}
,
expectedReturnStatus
:
tru
e
,
expectedReturnStatus
:
fals
e
,
expectedReturnValue
s
:
[]
,
expectedReturnValue
:
'
0x
'
,
},
},
],
],
},
},
],
],
}
}
runExecutionManagerTest
(
test_ovmCALL
)
const
runner
=
new
ExecutionManagerTestRunner
(
)
run
ExecutionManagerTest
(
test_ovmCALL_revert
)
run
ner
.
run
(
test_ovmCALL
)
packages/contracts/test/contracts/OVM/execution/OVM_ExecutionManager/ovmCREATE.spec.ts
View file @
cf113fec
/* Internal Imports */
/* Internal Imports */
import
{
import
{
runExecutionManagerTest
,
ExecutionManagerTestRunner
,
TestDefinition
,
TestDefinition
,
GAS_LIMIT
,
GAS_LIMIT
,
NULL_BYTES32
,
NULL_BYTES32
,
...
@@ -13,8 +13,11 @@ import {
...
@@ -13,8 +13,11 @@ import {
DUMMY_BYTECODE_HASH
,
DUMMY_BYTECODE_HASH
,
}
from
'
../../../../helpers
'
}
from
'
../../../../helpers
'
const
CREATED_CONTRACT_1
=
'
0x2bda4a99d5be88609d23b1e4ab5d1d34fb1c2feb
'
const
CREATED_CONTRACT_1
=
'
0xa1c4ba6fe56bda6db9df39bf45dbfc3cd104bd6f
'
const
NESTED_CREATED_CONTRACT
=
'
0xcb964b3f4162a0d4f5c997b40e19da5a546bc36f
'
const
CREATED_CONTRACT_2
=
'
0x2bda4a99d5be88609d23b1e4ab5d1d34fb1c2feb
'
const
NESTED_CREATED_CONTRACT
=
'
0xb99a3d1d1e3f0bd867570da4776221c1b0b74ea3
'
const
DUMMY_REVERT_DATA
=
'
0xdeadbeef1e5420deadbeef1e5420deadbeef1e5420deadbeef1e5420deadbeef1e5420
'
const
test_ovmCREATE
:
TestDefinition
=
{
const
test_ovmCREATE
:
TestDefinition
=
{
name
:
'
Basic tests for ovmCREATE
'
,
name
:
'
Basic tests for ovmCREATE
'
,
...
@@ -41,616 +44,534 @@ const test_ovmCREATE: TestDefinition = {
...
@@ -41,616 +44,534 @@ const test_ovmCREATE: TestDefinition = {
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
},
},
[
CREATED_CONTRACT_2
]:
{
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
},
[
NESTED_CREATED_CONTRACT
]:
{
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
},
},
verifiedContractStorage
:
{
$DUMMY_OVM_ADDRESS_2
:
{
[
NULL_BYTES32
]:
true
,
},
},
},
},
},
},
},
parameters
:
[
parameters
:
[
{
{
name
:
name
:
'
ovmCREATE, ovmEXTCODESIZE(CREATED)
'
,
'
Should correctly expose code-related opcodes for a created address once deployed
'
,
steps
:
[
parameters
:
[
{
{
steps
:
[
functionName
:
'
ovmCREATE
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
bytecode
:
DUMMY_BYTECODE
,
functionParams
:
[
},
GAS_LIMIT
/
2
,
expectedReturnStatus
:
true
,
'
$DUMMY_OVM_ADDRESS_1
'
,
expectedReturnValue
:
CREATED_CONTRACT_1
,
[
},
{
{
functionName
:
'
ovmCREATE
'
,
functionName
:
'
ovmEXTCODESIZE
'
,
functionParams
:
[
functionParams
:
{
DUMMY_BYTECODE
,
address
:
CREATED_CONTRACT_1
,
// expect creation to succeed?
},
true
,
expectedReturnStatus
:
true
,
[],
expectedReturnValue
:
DUMMY_BYTECODE_BYTELEN
,
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
CREATED_CONTRACT_1
],
},
{
functionName
:
'
ovmEXTCODESIZE
'
,
functionParams
:
[
CREATED_CONTRACT_1
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
DUMMY_BYTECODE_BYTELEN
],
},
{
functionName
:
'
ovmEXTCODEHASH
'
,
functionParams
:
[
CREATED_CONTRACT_1
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
DUMMY_BYTECODE_HASH
],
},
{
functionName
:
'
ovmEXTCODECOPY
'
,
functionParams
:
[
CREATED_CONTRACT_1
,
0
,
DUMMY_BYTECODE_BYTELEN
,
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
DUMMY_BYTECODE_HASH
],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
],
},
},
],
],
},
},
{
{
name
:
name
:
'
ovmCREATE, ovmEXTCODEHASH(CREATED)
'
,
'
Should return 0 address correctly expose empty code-related opcodes if deployment fails
'
,
steps
:
[
parameters
:
[
{
functionName
:
'
ovmCREATE
'
,
functionParams
:
{
bytecode
:
DUMMY_BYTECODE
,
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
CREATED_CONTRACT_1
,
},
{
{
steps
:
[
functionName
:
'
ovmEXTCODEHASH
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
address
:
CREATED_CONTRACT_1
,
functionParams
:
[
},
GAS_LIMIT
/
2
,
expectedReturnStatus
:
true
,
'
$DUMMY_OVM_ADDRESS_1
'
,
expectedReturnValue
:
DUMMY_BYTECODE_HASH
,
[
{
functionName
:
'
ovmCREATE
'
,
functionParams
:
[
DUMMY_BYTECODE
,
// expect creation to succeed?
false
,
[
{
functionName
:
'
ovmREVERT
'
,
functionParams
:
[
'
0x1234
'
],
expectedReturnStatus
:
undefined
,
// TODO: use this wherever not checked
expectedReturnValues
:
undefined
,
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
ZERO_ADDRESS
],
},
{
functionName
:
'
ovmEXTCODESIZE
'
,
functionParams
:
[
CREATED_CONTRACT_1
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
0
],
},
{
functionName
:
'
ovmEXTCODEHASH
'
,
functionParams
:
[
CREATED_CONTRACT_1
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
NULL_BYTES32
],
},
{
functionName
:
'
ovmEXTCODECOPY
'
,
functionParams
:
[
CREATED_CONTRACT_1
,
0
,
256
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
'
0x
'
+
'
00
'
.
repeat
(
256
)],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
],
},
},
],
],
},
},
{
{
name
:
'
Basic relevant context opcodes should be accessible in initcode
'
,
name
:
'
ovmCREATE, ovmEXTCODECOPY(CREATED)
'
,
parameter
s
:
[
step
s
:
[
{
{
steps
:
[
functionName
:
'
ovmCREATE
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
bytecode
:
DUMMY_BYTECODE
,
functionParams
:
[
},
GAS_LIMIT
,
expectedReturnStatus
:
true
,
'
$DUMMY_OVM_ADDRESS_1
'
,
expectedReturnValue
:
CREATED_CONTRACT_1
,
[
},
{
{
functionName
:
'
ovmCREATE
'
,
functionName
:
'
ovmEXTCODECOPY
'
,
functionParams
:
[
functionParams
:
{
// code to deploy:
address
:
CREATED_CONTRACT_1
,
DUMMY_BYTECODE
,
offset
:
0
,
// expect creation to succeed?
length
:
DUMMY_BYTECODE_BYTELEN
,
true
,
},
// steps for initcode:
expectedReturnStatus
:
true
,
[
expectedReturnValue
:
DUMMY_BYTECODE
,
{
functionName
:
'
ovmCALLER
'
,
functionParams
:
[],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
'
$DUMMY_OVM_ADDRESS_1
'
],
},
{
functionName
:
'
ovmADDRESS
'
,
functionParams
:
[],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
CREATED_CONTRACT_1
],
},
{
functionName
:
'
ovmSLOAD
'
,
functionParams
:
[
NON_NULL_BYTES32
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
NULL_BYTES32
],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
CREATED_CONTRACT_1
],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
],
},
},
],
],
},
},
{
{
name
:
name
:
'
ovmCREATE => ovmREVERT
'
,
'
Internal storage manipulation during initcode should be correctly persisted, and all accessible
'
,
steps
:
[
parameters
:
[
{
{
steps
:
[
functionName
:
'
ovmCREATE
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
subSteps
:
[
functionParams
:
[
{
GAS_LIMIT
,
functionName
:
'
ovmREVERT
'
,
'
$DUMMY_OVM_ADDRESS_1
'
,
revertData
:
DUMMY_REVERT_DATA
,
[
expectedReturnStatus
:
true
,
{
expectedReturnValue
:
'
0x00
'
,
functionName
:
'
ovmCREATE
'
,
},
functionParams
:
[
],
// code to deploy:
},
'
$OVM_CALL_HELPER_CODE
'
,
expectedReturnStatus
:
true
,
// expect creation to succeed?
expectedReturnValue
:
ZERO_ADDRESS
,
true
,
// steps for initcode:
[
{
functionName
:
'
ovmSSTORE
'
,
functionParams
:
[
NON_NULL_BYTES32
,
NON_NULL_BYTES32
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
{
functionName
:
'
ovmSLOAD
'
,
functionParams
:
[
NON_NULL_BYTES32
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
NON_NULL_BYTES32
],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
CREATED_CONTRACT_1
],
},
{
functionName
:
'
ovmCALL
'
,
functionParams
:
[
GAS_LIMIT
,
CREATED_CONTRACT_1
,
[
{
functionName
:
'
ovmSLOAD
'
,
functionParams
:
[
NON_NULL_BYTES32
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
NON_NULL_BYTES32
],
},
{
functionName
:
'
ovmSLOAD
'
,
functionParams
:
[
NULL_BYTES32
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
NULL_BYTES32
],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
],
},
},
],
],
},
},
{
{
name
:
name
:
'
ovmCREATE => ovmREVERT, ovmEXTCODESIZE(CREATED)
'
,
'
External storage manipulation during initcode subcalls should correctly be persisted
'
,
steps
:
[
parameters
:
[
{
functionName
:
'
ovmCREATE
'
,
functionParams
:
{
subSteps
:
[
{
functionName
:
'
ovmREVERT
'
,
revertData
:
DUMMY_REVERT_DATA
,
expectedReturnStatus
:
true
,
expectedReturnValue
:
'
0x00
'
,
},
],
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
ZERO_ADDRESS
,
},
{
{
steps
:
[
functionName
:
'
ovmEXTCODESIZE
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
address
:
CREATED_CONTRACT_1
,
functionParams
:
[
},
GAS_LIMIT
,
expectedReturnStatus
:
true
,
'
$DUMMY_OVM_ADDRESS_1
'
,
expectedReturnValue
:
0
,
[
{
functionName
:
'
ovmCREATE
'
,
functionParams
:
[
// code to deploy:
'
$OVM_CALL_HELPER_CODE
'
,
// expect creation to succeed?
true
,
// steps for initcode:
[
{
functionName
:
'
ovmCALL
'
,
functionParams
:
[
GAS_LIMIT
,
'
$DUMMY_OVM_ADDRESS_2
'
,
[
{
functionName
:
'
ovmSSTORE
'
,
functionParams
:
[
NULL_BYTES32
,
NON_NULL_BYTES32
,
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
{
functionName
:
'
ovmSLOAD
'
,
functionParams
:
[
NULL_BYTES32
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
NON_NULL_BYTES32
],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
CREATED_CONTRACT_1
],
},
{
functionName
:
'
ovmCALL
'
,
functionParams
:
[
GAS_LIMIT
,
'
$DUMMY_OVM_ADDRESS_2
'
,
[
{
functionName
:
'
ovmSLOAD
'
,
functionParams
:
[
NULL_BYTES32
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
NON_NULL_BYTES32
],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
],
],
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
],
},
},
],
],
},
},
{
{
name
:
name
:
'
ovmCREATE => ovmREVERT, ovmEXTCODEHASH(CREATED)
'
,
'
External storage manipulation during initcode subcalls should correctly NOT be persisted if ovmREVERTed
'
,
steps
:
[
preState
:
{
{
StateManager
:
{
functionName
:
'
ovmCREATE
'
,
accounts
:
{
functionParams
:
{
$DUMMY_OVM_ADDRESS_1
:
{
subSteps
:
[
codeHash
:
NON_NULL_BYTES32
,
{
ethAddress
:
'
$OVM_CALL_HELPER
'
,
functionName
:
'
ovmREVERT
'
,
},
revertData
:
DUMMY_REVERT_DATA
,
$DUMMY_OVM_ADDRESS_2
:
{
expectedReturnStatus
:
true
,
codeHash
:
NON_NULL_BYTES32
,
expectedReturnValue
:
'
0x00
'
,
ethAddress
:
'
$OVM_CALL_HELPER
'
,
},
},
],
[
CREATED_CONTRACT_1
]:
{
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
},
},
},
verifiedContractStorage
:
{
expectedReturnStatus
:
true
,
$DUMMY_OVM_ADDRESS_2
:
{
expectedReturnValue
:
ZERO_ADDRESS
,
[
NULL_BYTES32
]:
true
,
},
},
{
functionName
:
'
ovmEXTCODEHASH
'
,
functionParams
:
{
address
:
CREATED_CONTRACT_1
,
},
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
NULL_BYTES32
,
},
},
},
],
parameters
:
[
},
{
name
:
'
ovmCREATE => ovmREVERT, ovmEXTCODECOPY(CREATED)
'
,
steps
:
[
{
functionName
:
'
ovmCREATE
'
,
functionParams
:
{
subSteps
:
[
{
functionName
:
'
ovmREVERT
'
,
revertData
:
DUMMY_REVERT_DATA
,
expectedReturnStatus
:
true
,
expectedReturnValue
:
'
0x00
'
,
},
],
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
ZERO_ADDRESS
,
},
{
functionName
:
'
ovmEXTCODECOPY
'
,
functionParams
:
{
address
:
CREATED_CONTRACT_1
,
offset
:
0
,
length
:
256
,
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
'
0x
'
+
'
00
'
.
repeat
(
256
),
},
],
},
{
name
:
'
ovmCREATE => ovmADDRESS
'
,
steps
:
[
{
{
steps
:
[
functionName
:
'
ovmCREATE
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
subSteps
:
[
functionParams
:
[
{
GAS_LIMIT
/
2
,
functionName
:
'
ovmADDRESS
'
,
'
$DUMMY_OVM_ADDRESS_1
'
,
expectedReturnValue
:
CREATED_CONTRACT_1
,
[
},
{
],
functionName
:
'
ovmCREATE
'
,
},
functionParams
:
[
expectedReturnStatus
:
true
,
// code to deploy:
expectedReturnValue
:
CREATED_CONTRACT_1
,
'
$OVM_CALL_HELPER_CODE
'
,
},
// expect ovmCREATE to successfully deploy?
],
false
,
},
// steps for initcode:
{
[
name
:
'
ovmCREATE => ovmSLOAD
'
,
{
steps
:
[
functionName
:
'
ovmCALL
'
,
{
functionParams
:
[
functionName
:
'
ovmCREATE
'
,
GAS_LIMIT
,
functionParams
:
{
'
$DUMMY_OVM_ADDRESS_2
'
,
subSteps
:
[
[
{
{
functionName
:
'
ovmSLOAD
'
,
functionName
:
'
ovmSSTORE
'
,
functionParams
:
{
functionParams
:
[
key
:
NON_NULL_BYTES32
,
NULL_BYTES32
,
},
NON_NULL_BYTES32
,
expectedReturnStatus
:
true
,
],
expectedReturnValue
:
NULL_BYTES32
,
expectedReturnStatus
:
true
,
},
expectedReturnValues
:
[],
],
},
},
],
expectedReturnStatus
:
true
,
],
expectedReturnValue
:
CREATED_CONTRACT_1
,
expectedReturnStatus
:
true
,
},
expectedReturnValues
:
[],
],
},
},
{
{
functionName
:
'
ovmREVERT
'
,
name
:
'
ovmCALL => ovmCREATE => ovmCALLER
'
,
functionParams
:
[
'
0xdeadbeef
'
],
steps
:
[
expectedReturnStatus
:
true
,
{
expectedReturnValues
:
[],
// technically will return 1 single byte but impossible to assert
functionName
:
'
ovmCALL
'
,
},
functionParams
:
{
],
gasLimit
:
GAS_LIMIT
,
],
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
expectedReturnStatus
:
true
,
subSteps
:
[
expectedReturnValues
:
[
ZERO_ADDRESS
],
{
},
functionName
:
'
ovmCREATE
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
subSteps
:
[
functionParams
:
[
{
GAS_LIMIT
,
functionName
:
'
ovmSLOAD
'
,
'
$DUMMY_OVM_ADDRESS_2
'
,
functionParams
:
{
[
key
:
NON_NULL_BYTES32
,
{
},
functionName
:
'
ovmSLOAD
'
,
expectedReturnStatus
:
true
,
functionParams
:
[
NULL_BYTES32
],
expectedReturnValue
:
NULL_BYTES32
,
expectedReturnStatus
:
true
,
},
expectedReturnValues
:
[
NULL_BYTES32
],
],
},
},
],
expectedReturnStatus
:
true
,
],
expectedReturnValue
:
CREATED_CONTRACT_2
,
expectedReturnStatus
:
true
,
},
expectedReturnValues
:
[],
],
},
},
],
expectedReturnStatus
:
true
,
],
},
expectedReturnStatus
:
true
,
],
expectedReturnValues
:
[],
},
},
{
],
name
:
'
ovmCREATE => ovmSSTORE + ovmSLOAD
'
,
steps
:
[
{
functionName
:
'
ovmCREATE
'
,
functionParams
:
{
subSteps
:
[
{
functionName
:
'
ovmSSTORE
'
,
functionParams
:
{
key
:
NON_NULL_BYTES32
,
value
:
NON_NULL_BYTES32
,
},
expectedReturnStatus
:
true
,
},
{
functionName
:
'
ovmSLOAD
'
,
functionParams
:
{
key
:
NON_NULL_BYTES32
,
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
NON_NULL_BYTES32
,
},
],
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
CREATED_CONTRACT_1
,
},
},
],
],
},
},
{
{
name
:
name
:
'
Should correctly revert on invalid state access in initcode made by a call
'
,
'
ovmCREATE => ovmSSTORE, ovmCALL(CREATED) => ovmSLOAD(EXIST) + ovmSLOAD(NONEXIST)
'
,
preState
:
{
steps
:
[
StateManager
:
{
{
accounts
:
{
functionName
:
'
ovmCREATE
'
,
$DUMMY_OVM_ADDRESS_1
:
{
functionParams
:
{
codeHash
:
NON_NULL_BYTES32
,
subSteps
:
[
ethAddress
:
'
$OVM_CALL_HELPER
'
,
{
},
functionName
:
'
ovmSSTORE
'
,
[
CREATED_CONTRACT_1
]:
{
functionParams
:
{
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
key
:
NON_NULL_BYTES32
,
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
value
:
NON_NULL_BYTES32
,
},
},
expectedReturnStatus
:
true
,
},
],
},
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
CREATED_CONTRACT_1
,
},
},
},
parameters
:
[
{
{
steps
:
[
functionName
:
'
ovmCALL
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
gasLimit
:
GAS_LIMIT
,
functionParams
:
[
target
:
CREATED_CONTRACT_1
,
GAS_LIMIT
/
2
,
subSteps
:
[
'
$DUMMY_OVM_ADDRESS_1
'
,
{
[
functionName
:
'
ovmSLOAD
'
,
{
functionParams
:
{
functionName
:
'
ovmCREATE
'
,
key
:
NON_NULL_BYTES32
,
functionParams
:
[
},
// code to deploy:
expectedReturnStatus
:
true
,
'
$OVM_CALL_HELPER_CODE
'
,
expectedReturnValue
:
NON_NULL_BYTES32
,
// expect ovmCREATE to successfully deploy?
},
false
,
{
// steps for initcode:
functionName
:
'
ovmSLOAD
'
,
[
functionParams
:
{
{
key
:
NULL_BYTES32
,
functionName
:
'
ovmCALL
'
,
},
functionParams
:
[
expectedReturnStatus
:
true
,
GAS_LIMIT
,
expectedReturnValue
:
NULL_BYTES32
,
'
$DUMMY_OVM_ADDRESS_3
'
,
// invalid state access, not in prestate.SM.accounts
},
[],
],
],
},
expectedReturnStatus
:
undefined
,
expectedReturnStatus
:
true
,
expectedReturnValues
:
undefined
,
},
],
],
expectedReturnStatus
:
false
,
expectedReturnValues
:
[
REVERT_FLAGS
.
INVALID_STATE_ACCESS
,
'
0x
'
,
476756501
,
0
,
],
},
],
],
// note: this would be false in practice, but our code contracts are unsafe, so they do not enforce propagation of ISA flag.
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
],
},
},
],
],
},
},
{
{
name
:
'
Invalid state access on nested CREATE should be surfaced
'
,
name
:
preState
:
{
'
ovmCREATE => ovmCALL(ADDRESS_1) => ovmSSTORE, ovmCALL(ADDRESS_1) => ovmSLOAD
'
,
StateManager
:
{
steps
:
[
accounts
:
{
{
$DUMMY_OVM_ADDRESS_1
:
{
functionName
:
'
ovmCREATE
'
,
codeHash
:
NON_NULL_BYTES32
,
functionParams
:
{
ethAddress
:
'
$OVM_CALL_HELPER
'
,
subSteps
:
[
},
{
[
CREATED_CONTRACT_1
]:
{
functionName
:
'
ovmCALL
'
,
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
functionParams
:
{
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
gasLimit
:
GAS_LIMIT
,
},
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
[
NESTED_CREATED_CONTRACT
]:
{
subSteps
:
[
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
{
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
functionName
:
'
ovmSSTORE
'
,
},
functionParams
:
{
key
:
NON_NULL_BYTES32
,
value
:
NON_NULL_BYTES32
,
},
expectedReturnStatus
:
true
,
},
],
},
expectedReturnStatus
:
true
,
},
],
},
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
CREATED_CONTRACT_1
,
},
},
},
parameters
:
[
{
{
steps
:
[
functionName
:
'
ovmCALL
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
gasLimit
:
GAS_LIMIT
,
functionParams
:
[
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
GAS_LIMIT
/
2
,
subSteps
:
[
'
$DUMMY_OVM_ADDRESS_1
'
,
{
[
functionName
:
'
ovmSLOAD
'
,
{
functionParams
:
{
functionName
:
'
ovmCREATE
'
,
key
:
NON_NULL_BYTES32
,
functionParams
:
[
},
// code to deploy:
expectedReturnStatus
:
true
,
'
$OVM_CALL_HELPER_CODE
'
,
expectedReturnValue
:
NON_NULL_BYTES32
,
// expect ovmCREATE to successfully deploy?
},
false
,
],
// steps for initcode:
},
[
expectedReturnStatus
:
true
,
{
},
functionName
:
'
ovmCREATE
'
,
],
functionParams
:
[
},
// code to deploy:
{
'
$OVM_CALL_HELPER_CODE
'
,
name
:
// expect ovmCREATE to successfully deploy?
'
ovmCREATE => (ovmCALL(ADDRESS_2) => ovmSSTORE) + ovmREVERT, ovmCALL(ADDRESS_2) => ovmSLOAD
'
,
false
,
steps
:
[
// steps for initcode:
{
[
functionName
:
'
ovmCREATE
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
subSteps
:
[
functionParams
:
[
{
GAS_LIMIT
,
functionName
:
'
ovmCALL
'
,
'
$DUMMY_OVM_ADDRESS_3
'
,
// invalid state access, not in prestate.SM.accounts
functionParams
:
{
[],
gasLimit
:
GAS_LIMIT
,
],
target
:
'
$DUMMY_OVM_ADDRESS_2
'
,
expectedReturnStatus
:
undefined
,
subSteps
:
[
expectedReturnValues
:
undefined
,
{
},
functionName
:
'
ovmSSTORE
'
,
],
functionParams
:
{
],
key
:
NULL_BYTES32
,
expectedReturnStatus
:
undefined
,
value
:
NON_NULL_BYTES32
,
expectedReturnValues
:
undefined
,
},
},
expectedReturnStatus
:
true
,
],
},
],
],
expectedReturnStatus
:
false
,
},
expectedReturnValues
:
[
expectedReturnStatus
:
true
,
REVERT_FLAGS
.
INVALID_STATE_ACCESS
,
},
'
0x
'
,
{
476709610
,
functionName
:
'
ovmREVERT
'
,
0
,
revertData
:
DUMMY_REVERT_DATA
,
],
expectedReturnStatus
:
true
,
},
expectedReturnValue
:
'
0x00
'
,
],
},
],
],
// note: this would be false in practice, but our code contracts are unsafe, so they do not enforce propagation of ISA flag.
},
expectedReturnStatus
:
true
,
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
expectedReturnValue
:
ZERO_ADDRESS
,
},
},
],
{
functionName
:
'
ovmCALL
'
,
functionParams
:
{
gasLimit
:
GAS_LIMIT
,
target
:
'
$DUMMY_OVM_ADDRESS_2
'
,
subSteps
:
[
{
functionName
:
'
ovmSLOAD
'
,
functionParams
:
{
key
:
NULL_BYTES32
,
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
NULL_BYTES32
,
},
],
},
expectedReturnStatus
:
true
,
},
],
},
{
name
:
'
ovmCREATE => ovmCALL(ADDRESS_NONEXIST)
'
,
steps
:
[
{
functionName
:
'
ovmCREATE
'
,
functionParams
:
{
subSteps
:
[
{
functionName
:
'
ovmCALL
'
,
functionParams
:
{
gasLimit
:
GAS_LIMIT
,
target
:
'
$DUMMY_OVM_ADDRESS_3
'
,
calldata
:
'
0x
'
,
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
'
0x00
'
,
},
],
},
expectedReturnStatus
:
false
,
expectedReturnValue
:
{
flag
:
REVERT_FLAGS
.
INVALID_STATE_ACCESS
,
},
},
},
],
],
},
},
{
{
name
:
'
CREATE should fail and return 0 address if out of gas
'
,
name
:
'
ovmCREATE => ovmCREATE => ovmCALL(ADDRESS_NONEXIST)
'
,
focus
:
true
,
focus
:
true
,
preState
:
{
steps
:
[
StateManager
:
{
{
accounts
:
{
functionName
:
'
ovmCREATE
'
,
$DUMMY_OVM_ADDRESS_1
:
{
functionParams
:
{
codeHash
:
NON_NULL_BYTES32
,
subSteps
:
[
ethAddress
:
'
$OVM_CALL_HELPER
'
,
{
},
functionName
:
'
ovmCREATE
'
,
[
CREATED_CONTRACT_1
]:
{
functionParams
:
{
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
subSteps
:
[
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
{
},
functionName
:
'
ovmCALL
'
,
[
NESTED_CREATED_CONTRACT
]:
{
functionParams
:
{
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
gasLimit
:
GAS_LIMIT
,
ethAddress
:
'
0x
'
+
'
00
'
.
repeat
(
20
),
target
:
'
$DUMMY_OVM_ADDRESS_3
'
,
},
calldata
:
'
0x
'
,
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
'
0x00
'
,
},
],
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
'
0x00
'
,
},
],
},
expectedReturnStatus
:
false
,
expectedReturnValue
:
{
flag
:
REVERT_FLAGS
.
INVALID_STATE_ACCESS
,
},
},
},
},
},
],
parameters
:
[
},
{
name
:
'
ovmCREATE => OUT_OF_GAS
'
,
steps
:
[
{
{
steps
:
[
functionName
:
'
ovmCREATE
'
,
{
functionParams
:
{
functionName
:
'
ovmCALL
'
,
subSteps
:
[
functionParams
:
[
{
GAS_LIMIT
/
2
,
functionName
:
'
evmINVALID
'
,
'
$DUMMY_OVM_ADDRESS_1
'
,
},
[
],
{
},
functionName
:
'
ovmCREATEToInvalid
'
,
expectedReturnStatus
:
true
,
functionParams
:
[],
expectedReturnValue
:
ZERO_ADDRESS
,
expectedReturnStatus
:
true
,
expectedReturnValues
:
[
ZERO_ADDRESS
],
},
],
],
// note: this would be false in practice, but our code contracts are unsafe, so they do not enforce propagation of ISA flag.
expectedReturnStatus
:
true
,
expectedReturnValues
:
[],
},
],
},
},
],
],
},
},
],
],
}
}
runExecutionManagerTest
(
test_ovmCREATE
)
const
runner
=
new
ExecutionManagerTestRunner
()
runner
.
run
(
test_ovmCREATE
)
packages/contracts/test/contracts/OVM/execution/OVM_test.spec.ts
0 → 100644
View file @
cf113fec
import
{
ExecutionManagerTestRunner
}
from
'
../../../helpers/test-utils/test-runner
'
import
{
TestDefinition
}
from
'
../../../helpers/test-utils/test.types2
'
import
{
GAS_LIMIT
,
NULL_BYTES32
,
NON_NULL_BYTES32
,
REVERT_FLAGS
,
DUMMY_BYTECODE
,
VERIFIED_EMPTY_CONTRACT_HASH
,
}
from
'
../../../helpers
'
const
CREATED_CONTRACT_1
=
'
0x2bda4a99d5be88609d23b1e4ab5d1d34fb1c2feb
'
const
DUMMY_REVERT_DATA
=
'
0xdeadbeef1e5420deadbeef1e5420deadbeef1e5420deadbeef1e5420deadbeef1e5420
'
const
test
:
TestDefinition
=
{
name
:
'
An Example Test
'
,
preState
:
{
ExecutionManager
:
{
ovmStateManager
:
'
$OVM_STATE_MANAGER
'
,
ovmSafetyChecker
:
'
$OVM_SAFETY_CHECKER
'
,
messageRecord
:
{
nuisanceGasLeft
:
GAS_LIMIT
,
},
},
StateManager
:
{
owner
:
'
$OVM_EXECUTION_MANAGER
'
,
accounts
:
{
$DUMMY_OVM_ADDRESS_1
:
{
codeHash
:
NON_NULL_BYTES32
,
ethAddress
:
'
$OVM_CALL_HELPER
'
,
},
$DUMMY_OVM_ADDRESS_2
:
{
codeHash
:
NON_NULL_BYTES32
,
ethAddress
:
'
$OVM_CALL_HELPER
'
,
},
[
CREATED_CONTRACT_1
]:
{
codeHash
:
VERIFIED_EMPTY_CONTRACT_HASH
,
},
},
},
},
subTests
:
[
{
name
:
'
An Example Subtest
'
,
parameters
:
[
{
name
:
'
An Example CALL revert test
'
,
steps
:
[
{
functionName
:
'
ovmCALL
'
,
functionParams
:
{
gasLimit
:
GAS_LIMIT
,
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
subSteps
:
[
{
functionName
:
'
ovmCALL
'
,
functionParams
:
{
gasLimit
:
GAS_LIMIT
,
target
:
'
$DUMMY_OVM_ADDRESS_2
'
,
subSteps
:
[
{
functionName
:
'
evmREVERT
'
,
returnData
:
{
flag
:
REVERT_FLAGS
.
INTENTIONAL_REVERT
,
data
:
DUMMY_REVERT_DATA
,
},
},
],
},
expectedReturnStatus
:
false
,
expectedReturnValue
:
DUMMY_REVERT_DATA
,
},
],
},
expectedReturnStatus
:
true
,
},
],
},
{
name
:
'
An Example CREATE test
'
,
steps
:
[
{
functionName
:
'
ovmCALL
'
,
functionParams
:
{
gasLimit
:
GAS_LIMIT
,
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
subSteps
:
[
{
functionName
:
'
ovmCREATE
'
,
functionParams
:
{
subSteps
:
[
{
functionName
:
'
ovmCALLER
'
,
expectedReturnStatus
:
true
,
expectedReturnValue
:
'
$DUMMY_OVM_ADDRESS_1
'
,
},
],
},
expectedReturnStatus
:
true
,
expectedReturnValue
:
CREATED_CONTRACT_1
,
},
],
},
expectedReturnStatus
:
true
,
},
],
},
{
name
:
'
An Example CALL test
'
,
steps
:
[
{
functionName
:
'
ovmCALL
'
,
functionParams
:
{
gasLimit
:
GAS_LIMIT
,
target
:
'
$DUMMY_OVM_ADDRESS_1
'
,
subSteps
:
[
{
functionName
:
'
ovmADDRESS
'
,
expectedReturnStatus
:
true
,
expectedReturnValue
:
'
$DUMMY_OVM_ADDRESS_1
'
,
},
{
functionName
:
'
ovmCALL
'
,
functionParams
:
{
gasLimit
:
GAS_LIMIT
,
target
:
'
$DUMMY_OVM_ADDRESS_2
'
,
subSteps
:
[
{
functionName
:
'
ovmADDRESS
'
,
expectedReturnStatus
:
true
,
expectedReturnValue
:
'
$DUMMY_OVM_ADDRESS_2
'
,
},
{
functionName
:
'
ovmCALLER
'
,
expectedReturnStatus
:
true
,
expectedReturnValue
:
'
$DUMMY_OVM_ADDRESS_1
'
,
},
],
},
expectedReturnStatus
:
true
,
},
],
},
expectedReturnStatus
:
true
,
},
],
},
],
},
],
}
const
runner
=
new
ExecutionManagerTestRunner
()
runner
.
run
(
test
)
packages/contracts/test/helpers/constants.ts
View file @
cf113fec
...
@@ -20,4 +20,5 @@ export const NON_NULL_BYTES32 = makeHexString('11', 32)
...
@@ -20,4 +20,5 @@ export const NON_NULL_BYTES32 = makeHexString('11', 32)
export
const
ZERO_ADDRESS
=
makeAddress
(
'
00
'
)
export
const
ZERO_ADDRESS
=
makeAddress
(
'
00
'
)
export
const
NON_ZERO_ADDRESS
=
makeAddress
(
'
11
'
)
export
const
NON_ZERO_ADDRESS
=
makeAddress
(
'
11
'
)
export
const
VERIFIED_EMPTY_CONTRACT_HASH
=
makeHexString
(
'
69
'
,
32
)
export
const
VERIFIED_EMPTY_CONTRACT_HASH
=
'
0x00004B1DC0DE000000004B1DC0DE000000004B1DC0DE000000004B1DC0DE0000
'
packages/contracts/test/helpers/mocks/mock-binding.ts
View file @
cf113fec
...
@@ -93,7 +93,7 @@ export const bindMockWatcherToVM = (): void => {
...
@@ -93,7 +93,7 @@ export const bindMockWatcherToVM = (): void => {
// Modify the post-message handler to insert the correct return data.
// Modify the post-message handler to insert the correct return data.
const
originalAfterMessageHandler
=
vmTracer
[
'
_afterMessageHandler
'
as
any
]
const
originalAfterMessageHandler
=
vmTracer
[
'
_afterMessageHandler
'
as
any
]
function
modifiedAfterMessageHandler
(
result
:
any
,
next
:
any
)
{
async
function
modifiedAfterMessageHandler
(
result
:
any
,
next
:
any
)
{
// We don't need to do anything if we haven't stored any mock messages.
// We don't need to do anything if we haven't stored any mock messages.
if
(
messages
.
length
>
0
)
{
if
(
messages
.
length
>
0
)
{
// We need to look at the messages backwards since the first result will
// We need to look at the messages backwards since the first result will
...
...
packages/contracts/test/helpers/test-utils/index.ts
View file @
cf113fec
export
*
from
'
./test-generation
'
export
*
from
'
./test-runner
'
export
*
from
'
./test-parsing
'
export
*
from
'
./test.types
'
export
*
from
'
./test.types
'
packages/contracts/test/helpers/test-utils/test-generation.ts
deleted
100644 → 0
View file @
3e81548f
/* External Imports */
import
{
Contract
}
from
'
ethers
'
import
{
Interface
,
AbiCoder
}
from
'
ethers/lib/utils
'
import
*
as
path
from
'
path
'
import
{
REVERT_FLAGS
,
encodeRevertData
,
decodeRevertData
}
from
'
../codec
'
/* Internal Imports */
import
{
TestStep
}
from
'
./test.types
'
const
abi
=
new
AbiCoder
()
const
getContractDefinition
=
(
name
:
string
):
any
=>
{
return
require
(
path
.
join
(
__dirname
,
'
../../../artifacts
'
,
`
${
name
}
.json`
))
}
export
const
getInitcode
=
(
name
:
string
):
string
=>
{
return
getContractDefinition
(
name
).
bytecode
}
export
const
getBytecode
=
(
name
:
string
):
string
=>
{
return
getContractDefinition
(
name
).
deployedBytecode
}
export
interface
TestCallGenerator
{
getCalldata
():
string
shouldCallSucceed
():
boolean
getReturnData
():
string
getFunctionName
():
string
interpretActualReturnData
(
data
:
string
,
succeeded
:
boolean
):
string
}
export
class
DefaultTestGenerator
implements
TestCallGenerator
{
constructor
(
protected
ovmExecutionManager
:
Contract
,
protected
ovmCallHelper
:
Contract
,
protected
ovmCreateStorer
:
Contract
,
protected
ovmCreateHelper
:
Interface
,
protected
ovmRevertHelper
:
Contract
,
protected
ovmInvalidHelper
:
Contract
,
protected
step
:
TestStep
)
{}
getFunctionParams
():
any
[]
{
return
this
.
step
.
functionParams
}
getReturnValues
():
any
[]
{
return
this
.
step
.
expectedReturnValues
}
getCalldata
():
string
{
return
this
.
ovmExecutionManager
.
interface
.
encodeFunctionData
(
this
.
step
.
functionName
,
this
.
getFunctionParams
()
)
}
shouldCallSucceed
():
boolean
{
return
this
.
step
.
expectedReturnStatus
}
getFunctionName
():
string
{
return
this
.
step
.
functionName
}
getReturnData
():
string
{
let
expectedReturnData
if
(
this
.
step
.
expectedReturnStatus
)
{
expectedReturnData
=
this
.
ovmExecutionManager
.
interface
.
encodeFunctionResult
(
this
.
step
.
functionName
,
this
.
getReturnValues
()
)
}
else
{
expectedReturnData
=
encodeRevertData
(
this
.
step
.
expectedReturnValues
[
0
],
this
.
step
.
expectedReturnValues
[
1
],
this
.
step
.
expectedReturnValues
[
2
],
this
.
step
.
expectedReturnValues
[
3
]
)
}
return
expectedReturnData
}
interpretActualReturnData
(
data
:
string
,
succeeded
:
boolean
):
string
{
let
interpretation
:
string
=
'
call to EM.
'
+
this
.
step
.
functionName
+
'
returned values:
'
interpretation
+=
succeeded
?
this
.
ovmExecutionManager
.
interface
.
decodeFunctionResult
(
this
.
step
.
functionName
,
data
)
:
decodeRevertData
(
data
)
return
interpretation
}
}
export
class
ovmCALLGenerator
extends
DefaultTestGenerator
{
getCalleeGenerators
():
TestCallGenerator
[]
{
return
(
this
.
step
.
functionParams
[
2
]
as
TestStep
[]).
map
((
step
)
=>
{
return
getTestGenerator
(
step
,
this
.
ovmExecutionManager
,
this
.
ovmCallHelper
,
this
.
ovmCreateStorer
,
this
.
ovmCreateHelper
,
this
.
ovmRevertHelper
,
this
.
ovmInvalidHelper
)
})
}
getFunctionParams
():
any
[]
{
return
[
this
.
step
.
functionParams
[
0
],
this
.
step
.
functionParams
[
1
],
this
.
ovmCallHelper
.
interface
.
encodeFunctionData
(
'
runSteps
'
,
[
this
.
getCalleeGenerators
().
map
((
calleeGenerator
)
=>
{
return
calleeGenerator
.
getCalldata
()
}),
!
this
.
step
.
expectedReturnStatus
,
this
.
ovmCreateStorer
.
address
,
]),
]
}
getReturnValues
():
any
[]
{
if
(
this
.
step
.
expectedReturnValues
.
length
<=
1
)
{
return
[
!
this
.
step
.
expectedReturnValues
[
0
],
this
.
ovmCallHelper
.
interface
.
encodeFunctionResult
(
'
runSteps
'
,
[
this
.
getCalleeGenerators
().
map
((
calleeGenerator
)
=>
{
return
{
success
:
calleeGenerator
.
shouldCallSucceed
(),
data
:
calleeGenerator
.
getReturnData
(),
}
}),
]),
]
}
else
{
return
this
.
step
.
expectedReturnValues
}
}
interpretActualReturnData
(
data
:
string
,
success
:
boolean
):
string
{
if
(
!
success
)
{
return
'
ovmCALL-type reverted with flag:
'
+
decodeRevertData
(
data
)
}
if
(
this
.
step
.
expectedReturnValues
.
length
>
1
)
{
return
(
'
ovmCALL-type returned successfully with overridden return data:
'
+
data
)
}
const
resultOfOvmCALL
=
this
.
ovmExecutionManager
.
interface
.
decodeFunctionResult
(
this
.
step
.
functionName
,
data
)
const
resultOfSubcalls
=
this
.
ovmCallHelper
.
interface
.
decodeFunctionResult
(
'
runSteps
'
,
resultOfOvmCALL
[
1
]
)[
0
]
const
calleeGenerators
=
this
.
getCalleeGenerators
()
const
interpretedResults
=
resultOfSubcalls
.
map
((
result
,
i
)
=>
{
const
generator
=
calleeGenerators
[
i
]
const
EMsuccess
=
result
[
0
]
const
EMdata
=
result
[
1
]
return
(
'
subcall
'
+
i
+
'
(
'
+
generator
.
getFunctionName
()
+
'
) had return status:
'
+
EMsuccess
+
'
and appears to have done:
'
+
generator
.
interpretActualReturnData
(
EMdata
,
EMsuccess
)
)
})
return
(
'
ovmCALL returned
'
+
resultOfOvmCALL
[
0
]
+
'
\n
with subcalls:
'
+
JSON
.
stringify
(
interpretedResults
)
+
'
\n
'
)
}
}
export
class
ovmCREATEGenerator
extends
DefaultTestGenerator
{
getInitcodeGenerators
():
TestCallGenerator
[]
{
return
(
this
.
step
.
functionParams
[
2
]
as
TestStep
[]).
map
((
step
)
=>
{
return
getTestGenerator
(
step
,
this
.
ovmExecutionManager
,
this
.
ovmCallHelper
,
this
.
ovmCreateStorer
,
this
.
ovmCreateHelper
,
this
.
ovmRevertHelper
,
this
.
ovmInvalidHelper
)
})
}
getFunctionParams
():
any
[]
{
return
[
getInitcode
(
'
Helper_CodeContractForCreates
'
)
+
this
.
ovmCreateHelper
.
encodeDeploy
([
this
.
getInitcodeGenerators
().
map
((
initcodeGenerator
)
=>
{
return
initcodeGenerator
.
getCalldata
()
}),
!
this
.
step
.
expectedReturnStatus
,
this
.
step
.
functionParams
[
0
],
this
.
ovmCreateStorer
.
address
,
])
.
slice
(
2
),
]
}
getReturnData
():
string
{
const
expectedDirectEMReturnData
=
this
.
step
.
expectedReturnStatus
?
this
.
ovmExecutionManager
.
interface
.
encodeFunctionResult
(
this
.
step
.
functionName
,
this
.
getReturnValues
()
)
:
encodeRevertData
(
this
.
step
.
expectedReturnValues
[
0
],
this
.
step
.
expectedReturnValues
[
1
],
this
.
step
.
expectedReturnValues
[
2
],
this
.
step
.
expectedReturnValues
[
3
]
)
const
responsesShouldBeReverted
=
!
this
.
step
.
functionParams
[
1
]
const
expectedStoredValues
=
responsesShouldBeReverted
?
[]
:
this
.
getInitcodeGenerators
().
map
((
initcodeGenerator
)
=>
{
return
{
success
:
initcodeGenerator
.
shouldCallSucceed
(),
// TODO: figure out if we need this and expose in generator interface if so.
data
:
initcodeGenerator
.
getReturnData
(),
}
})
const
expectedReturnData
=
abi
.
encode
(
[
'
bytes
'
,
'
bytes
'
],
[
expectedDirectEMReturnData
,
this
.
ovmCreateStorer
.
interface
.
encodeFunctionResult
(
'
getLastResponses
'
,
[
expectedStoredValues
]
),
]
)
return
expectedReturnData
}
interpretActualReturnData
(
data
:
string
,
success
:
boolean
):
string
{
const
ovmCREATEDataAndInitcodeResults
=
abi
.
decode
([
'
bytes
'
,
'
bytes
'
],
data
)
const
ovmCREATEData
=
ovmCREATEDataAndInitcodeResults
[
0
]
if
(
!
success
)
{
return
(
'
ovmCREATE reverted with:
'
+
decodeRevertData
(
ovmCREATEData
.
toString
())
)
}
// const decodedDataFromOvmCREATE = this.ovmExecutionManager.interface.decodeFunctionResult(this.step.functionName, ovmCREATEData)
const
initcodeResultsRaw
=
ovmCREATEDataAndInitcodeResults
[
1
]
const
initcodeResults
=
this
.
ovmCreateStorer
.
interface
.
decodeFunctionResult
(
'
getLastResponses
'
,
initcodeResultsRaw
)[
0
]
const
interpretedInitcodeResults
=
initcodeResults
.
map
((
result
,
i
)
=>
{
return
(
'
\n
initcode subcall
'
+
i
+
'
had response status
'
+
result
[
0
]
+
'
and appears to have done:
'
+
this
.
getInitcodeGenerators
()[
i
].
interpretActualReturnData
(
result
[
1
],
result
[
0
]
)
)
})
return
JSON
.
stringify
(
interpretedInitcodeResults
)
}
}
class
ovmCALLToRevertGenerator
extends
DefaultTestGenerator
{
getCalldata
():
string
{
return
this
.
ovmExecutionManager
.
interface
.
encodeFunctionData
(
'
ovmCALL
'
,
[
this
.
step
.
functionParams
[
0
],
this
.
step
.
functionParams
[
1
],
this
.
ovmRevertHelper
.
interface
.
encodeFunctionData
(
'
doRevert
'
,
[
encodeRevertData
(
this
.
step
.
functionParams
[
2
][
0
],
this
.
step
.
functionParams
[
2
][
1
],
this
.
step
.
functionParams
[
2
][
2
],
this
.
step
.
functionParams
[
2
][
3
]
),
]),
])
}
getReturnData
():
string
{
let
expectedReturnData
if
(
this
.
step
.
expectedReturnStatus
)
{
expectedReturnData
=
this
.
ovmExecutionManager
.
interface
.
encodeFunctionResult
(
'
ovmCALL
'
,
this
.
step
.
expectedReturnValues
)
}
else
{
expectedReturnData
=
encodeRevertData
(
this
.
step
.
expectedReturnValues
[
0
],
this
.
step
.
expectedReturnValues
[
1
],
this
.
step
.
expectedReturnValues
[
2
],
this
.
step
.
expectedReturnValues
[
3
]
)
}
return
expectedReturnData
}
interpretActualReturnData
(
data
:
string
,
success
:
boolean
):
string
{
if
(
success
)
{
return
(
'
ovmCALL to revert heler, which succeeded with return params:
'
+
JSON
.
stringify
(
this
.
ovmExecutionManager
.
interface
.
decodeFunctionResult
(
'
ovmCALL
'
,
data
)
)
)
}
else
{
return
(
'
ovmCALL to revert helper did itself revert with flag:
'
+
JSON
.
stringify
(
decodeRevertData
(
data
))
)
}
}
}
class
ovmSTATICCALLToRevertGenerator
extends
DefaultTestGenerator
{
getCalldata
():
string
{
return
this
.
ovmExecutionManager
.
interface
.
encodeFunctionData
(
'
ovmSTATICCALL
'
,
[
this
.
step
.
functionParams
[
0
],
this
.
step
.
functionParams
[
1
],
this
.
ovmRevertHelper
.
interface
.
encodeFunctionData
(
'
doRevert
'
,
[
encodeRevertData
(
this
.
step
.
functionParams
[
2
][
0
],
this
.
step
.
functionParams
[
2
][
1
],
this
.
step
.
functionParams
[
2
][
2
],
this
.
step
.
functionParams
[
2
][
3
]
),
]),
]
)
}
getReturnData
():
string
{
let
expectedReturnData
if
(
this
.
step
.
expectedReturnStatus
)
{
expectedReturnData
=
this
.
ovmExecutionManager
.
interface
.
encodeFunctionResult
(
'
ovmCALL
'
,
this
.
step
.
expectedReturnValues
)
}
else
{
expectedReturnData
=
encodeRevertData
(
this
.
step
.
expectedReturnValues
[
0
],
this
.
step
.
expectedReturnValues
[
1
],
this
.
step
.
expectedReturnValues
[
2
],
this
.
step
.
expectedReturnValues
[
3
]
)
}
return
expectedReturnData
}
interpretActualReturnData
(
data
:
string
,
success
:
boolean
):
string
{
if
(
success
)
{
return
(
'
ovmCALL to revert heler, which succeeded with return params:
'
+
JSON
.
stringify
(
this
.
ovmExecutionManager
.
interface
.
decodeFunctionResult
(
'
ovmCALL
'
,
data
)
)
)
}
else
{
return
(
'
ovmCALL to revert helper did itself revert with flag:
'
+
JSON
.
stringify
(
decodeRevertData
(
data
))
)
}
}
}
class
ovmCALLToInvalidGenerator
extends
DefaultTestGenerator
{
getCalldata
():
string
{
return
this
.
ovmExecutionManager
.
interface
.
encodeFunctionData
(
'
ovmCALL
'
,
[
this
.
step
.
functionParams
[
0
],
this
.
step
.
functionParams
[
1
],
this
.
ovmInvalidHelper
.
interface
.
encodeFunctionData
(
'
doInvalid
'
,
[]),
])
}
getReturnData
():
string
{
let
expectedReturnData
if
(
this
.
step
.
expectedReturnStatus
)
{
expectedReturnData
=
this
.
ovmExecutionManager
.
interface
.
encodeFunctionResult
(
'
ovmCALL
'
,
this
.
step
.
expectedReturnValues
)
}
else
{
expectedReturnData
=
encodeRevertData
(
this
.
step
.
expectedReturnValues
[
2
][
0
],
this
.
step
.
expectedReturnValues
[
2
][
1
],
this
.
step
.
expectedReturnValues
[
2
][
2
],
this
.
step
.
expectedReturnValues
[
2
][
3
]
)
}
return
expectedReturnData
}
interpretActualReturnData
(
data
:
string
,
success
:
boolean
):
string
{
if
(
success
)
{
return
(
'
ovmCALL to InvalidJump/OutOfGas heler, which succeeded with return params:
'
+
JSON
.
stringify
(
this
.
ovmExecutionManager
.
interface
.
decodeFunctionResult
(
'
ovmCALL
'
,
data
)
)
)
}
else
{
return
(
'
ovmCALL to InvalidJump/OutOfGas helper did itself revert with flag:
'
+
JSON
.
stringify
(
decodeRevertData
(
data
))
)
}
}
}
class
ovmCREATEToInvalidGenerator
extends
DefaultTestGenerator
{
getCalldata
():
string
{
return
this
.
ovmExecutionManager
.
interface
.
encodeFunctionData
(
'
ovmCREATE
'
,
[
getInitcode
(
'
Helper_CodeContractForInvalidInCreation
'
),
])
}
getReturnData
():
string
{
let
expectedEMResponse
if
(
this
.
step
.
expectedReturnStatus
)
{
expectedEMResponse
=
this
.
ovmExecutionManager
.
interface
.
encodeFunctionResult
(
'
ovmCREATE
'
,
this
.
step
.
expectedReturnValues
)
}
else
{
expectedEMResponse
=
encodeRevertData
(
this
.
step
.
expectedReturnValues
[
2
][
0
],
this
.
step
.
expectedReturnValues
[
2
][
1
],
this
.
step
.
expectedReturnValues
[
2
][
2
],
this
.
step
.
expectedReturnValues
[
2
][
3
]
)
}
return
abi
.
encode
(
[
'
bytes
'
,
'
bytes
'
],
[
expectedEMResponse
,
this
.
ovmCreateStorer
.
interface
.
encodeFunctionResult
(
'
getLastResponses
'
,
[[]]
),
]
)
}
interpretActualReturnData
(
data
:
string
,
success
:
boolean
):
string
{
const
EMResponse
=
abi
.
decode
([
'
bytes
'
,
'
bytes
'
],
data
)[
0
]
console
.
log
(
`EMResponse is
${
EMResponse
}
, success is
${
success
}
`
)
if
(
success
)
{
return
(
'
ovmCREATE to InvalidJump/OutOfGas IN CONSTRUCTOR heler, which succeeded returning address:
'
+
JSON
.
stringify
(
this
.
ovmExecutionManager
.
interface
.
decodeFunctionResult
(
'
ovmCREATE
'
,
EMResponse
)
)
)
}
else
{
return
(
'
ovmCALL to InvalidJump/OutOfGas IN CONSTRUCTOR heler did itself revert with flag:
'
+
JSON
.
stringify
(
decodeRevertData
(
EMResponse
))
)
}
}
}
export
const
getTestGenerator
=
(
step
:
TestStep
,
ovmExecutionManager
:
Contract
,
ovmCallHelper
:
Contract
,
ovmCreateStorer
:
Contract
,
ovmCreateHelper
:
Interface
,
ovmRevertHelper
:
Contract
,
ovmInvalidHelper
:
Contract
):
TestCallGenerator
=>
{
switch
(
step
.
functionName
)
{
case
'
ovmCALL
'
:
case
'
ovmDELEGATECALL
'
:
case
'
ovmSTATICCALL
'
:
return
new
ovmCALLGenerator
(
ovmExecutionManager
,
ovmCallHelper
,
ovmCreateStorer
,
ovmCreateHelper
,
ovmRevertHelper
,
ovmInvalidHelper
,
step
)
case
'
ovmCREATE
'
:
return
new
ovmCREATEGenerator
(
ovmExecutionManager
,
ovmCallHelper
,
ovmCreateStorer
,
ovmCreateHelper
,
ovmRevertHelper
,
ovmInvalidHelper
,
step
)
case
'
ovmCALLToRevert
'
:
return
new
ovmCALLToRevertGenerator
(
ovmExecutionManager
,
ovmCallHelper
,
ovmCreateStorer
,
ovmCreateHelper
,
ovmRevertHelper
,
ovmInvalidHelper
,
step
)
case
'
ovmCALLToInvalid
'
:
return
new
ovmCALLToInvalidGenerator
(
ovmExecutionManager
,
ovmCallHelper
,
ovmCreateStorer
,
ovmCreateHelper
,
ovmRevertHelper
,
ovmInvalidHelper
,
step
)
case
'
ovmSTATICCALLToRevert
'
:
return
new
ovmSTATICCALLToRevertGenerator
(
ovmExecutionManager
,
ovmCallHelper
,
ovmCreateStorer
,
ovmCreateHelper
,
ovmRevertHelper
,
ovmInvalidHelper
,
step
)
case
'
ovmCREATEToInvalid
'
:
return
new
ovmCREATEToInvalidGenerator
(
ovmExecutionManager
,
ovmCallHelper
,
ovmCreateStorer
,
ovmCreateHelper
,
ovmRevertHelper
,
ovmInvalidHelper
,
step
)
default
:
return
new
DefaultTestGenerator
(
ovmExecutionManager
,
ovmCallHelper
,
ovmCreateStorer
,
ovmCreateHelper
,
ovmRevertHelper
,
ovmInvalidHelper
,
step
)
}
}
packages/contracts/test/helpers/test-utils/test-parsing.ts
deleted
100644 → 0
View file @
3e81548f
import
{
expect
}
from
'
../../setup
'
/* External Imports */
import
{
Contract
}
from
'
ethers
'
import
{
cloneDeep
}
from
'
lodash
'
import
{
ethers
}
from
'
@nomiclabs/buidler
'
/* Internal Imports */
import
{
getModifiableStorageFactory
}
from
'
../storage/contract-storage
'
import
{
GAS_LIMIT
,
NON_NULL_BYTES32
}
from
'
../constants
'
import
{
getTestGenerator
,
getInitcode
,
getBytecode
}
from
'
./test-generation
'
import
{
TestParameters
,
TestDefinition
,
isTestDefinition
}
from
'
./test.types
'
import
{
int
}
from
'
@nomiclabs/buidler/internal/core/params/argumentTypes
'
const
getDummyOVMAddress
=
(
kv
:
string
):
string
=>
{
return
'
0x
'
+
(
kv
.
split
(
'
$DUMMY_OVM_ADDRESS_
'
)[
1
]
+
'
0
'
).
repeat
(
20
)
}
const
setPlaceholderStrings
=
(
test
:
any
,
ovmExecutionManager
:
Contract
,
ovmStateManager
:
Contract
,
ovmSafetyChecker
:
Contract
,
ovmCallHelper
:
Contract
,
ovmRevertHelper
:
Contract
):
any
=>
{
const
setPlaceholder
=
(
kv
:
string
):
string
=>
{
if
(
kv
===
'
$OVM_EXECUTION_MANAGER
'
)
{
return
ovmExecutionManager
.
address
}
else
if
(
kv
===
'
$OVM_STATE_MANAGER
'
)
{
return
ovmStateManager
.
address
}
else
if
(
kv
===
'
$OVM_SAFETY_CHECKER
'
)
{
return
ovmSafetyChecker
.
address
}
else
if
(
kv
===
'
$OVM_CALL_HELPER_CODE
'
)
{
return
getBytecode
(
'
Helper_CodeContractForCalls
'
)
}
else
if
(
kv
===
'
$OVM_CALL_HELPER
'
)
{
return
ovmCallHelper
.
address
}
else
if
(
kv
===
'
$OVM_REVERT_HELPER
'
)
{
return
ovmRevertHelper
.
address
}
else
if
(
kv
.
startsWith
(
'
$DUMMY_OVM_ADDRESS_
'
))
{
return
getDummyOVMAddress
(
kv
)
}
else
{
return
kv
}
}
if
(
Array
.
isArray
(
test
))
{
test
=
test
.
map
((
element
)
=>
{
return
setPlaceholderStrings
(
element
,
ovmExecutionManager
,
ovmStateManager
,
ovmSafetyChecker
,
ovmCallHelper
,
ovmRevertHelper
)
})
}
else
if
(
typeof
test
===
'
object
'
&&
test
!==
null
)
{
for
(
const
key
of
Object
.
keys
(
test
))
{
const
replacedKey
=
setPlaceholder
(
key
)
if
(
replacedKey
!==
key
)
{
test
[
replacedKey
]
=
test
[
key
]
delete
test
[
key
]
}
test
[
replacedKey
]
=
setPlaceholderStrings
(
test
[
replacedKey
],
ovmExecutionManager
,
ovmStateManager
,
ovmSafetyChecker
,
ovmCallHelper
,
ovmRevertHelper
)
}
}
else
if
(
typeof
test
===
'
string
'
)
{
test
=
setPlaceholder
(
test
)
}
return
test
}
const
fixtureDeployContracts
=
async
():
Promise
<
{
OVM_SafetyChecker
:
Contract
OVM_StateManager
:
Contract
OVM_ExecutionManager
:
Contract
OVM_CallHelper
:
Contract
OVM_RevertHelper
:
Contract
OVM_CreateStorer
:
Contract
OVM_InvalidHelper
:
Contract
}
>
=>
{
const
Factory__OVM_SafetyChecker
=
await
ethers
.
getContractFactory
(
'
OVM_SafetyChecker
'
)
const
Factory__OVM_StateManager
=
await
getModifiableStorageFactory
(
'
OVM_StateManager
'
)
const
Factory__OVM_ExecutionManager
=
await
getModifiableStorageFactory
(
'
OVM_ExecutionManager
'
)
const
Factory__Helper_CodeContractForCalls
=
await
getModifiableStorageFactory
(
'
Helper_CodeContractForCalls
'
)
const
Factory__Helper_CodeContractForReverts
=
await
ethers
.
getContractFactory
(
'
Helper_CodeContractForReverts
'
)
const
Factory__Helper_CreateEMResponsesStorer
=
await
ethers
.
getContractFactory
(
'
Helper_CreateEMResponsesStorer
'
)
const
Helper_CodeContractForInvalid
=
await
ethers
.
getContractFactory
(
'
Helper_CodeContractForInvalid
'
)
const
OVM_SafetyChecker
=
await
Factory__OVM_SafetyChecker
.
deploy
()
const
OVM_ExecutionManager
=
await
Factory__OVM_ExecutionManager
.
deploy
(
OVM_SafetyChecker
.
address
)
const
OVM_StateManager
=
await
Factory__OVM_StateManager
.
deploy
(
OVM_ExecutionManager
.
address
)
const
OVM_CallHelper
=
await
Factory__Helper_CodeContractForCalls
.
deploy
()
const
OVM_RevertHelper
=
await
Factory__Helper_CodeContractForReverts
.
deploy
()
const
OVM_CreateStorer
=
await
Factory__Helper_CreateEMResponsesStorer
.
deploy
()
const
OVM_InvalidHelper
=
await
Helper_CodeContractForInvalid
.
deploy
()
return
{
OVM_SafetyChecker
,
OVM_StateManager
,
OVM_ExecutionManager
,
OVM_CallHelper
,
OVM_RevertHelper
,
OVM_CreateStorer
,
OVM_InvalidHelper
,
}
}
export
const
runExecutionManagerTest
=
(
test
:
TestDefinition
):
void
=>
{
test
.
preState
=
test
.
preState
||
{}
test
.
postState
=
test
.
postState
||
{}
describe
(
`Standard test:
${
test
.
name
}
`
,
()
=>
{
test
.
parameters
.
map
((
parameters
)
=>
{
if
(
isTestDefinition
(
parameters
))
{
runExecutionManagerTest
({
...
parameters
,
preState
:
{
...
test
.
preState
,
...
parameters
.
preState
,
},
postState
:
{
...
test
.
postState
,
...
parameters
.
postState
,
},
})
}
else
{
let
OVM_SafetyChecker
:
Contract
let
OVM_StateManager
:
Contract
let
OVM_ExecutionManager
:
Contract
let
OVM_CallHelper
:
Contract
let
OVM_RevertHelper
:
Contract
let
OVM_CreateStorer
:
Contract
let
OVM_InvalidHelper
:
Contract
beforeEach
(
async
()
=>
{
const
contracts
=
await
fixtureDeployContracts
()
OVM_SafetyChecker
=
contracts
.
OVM_SafetyChecker
OVM_StateManager
=
contracts
.
OVM_StateManager
OVM_ExecutionManager
=
contracts
.
OVM_ExecutionManager
OVM_CallHelper
=
contracts
.
OVM_CallHelper
OVM_RevertHelper
=
contracts
.
OVM_RevertHelper
OVM_CreateStorer
=
contracts
.
OVM_CreateStorer
OVM_InvalidHelper
=
contracts
.
OVM_InvalidHelper
})
let
replacedParams
:
TestParameters
let
replacedTest
:
TestDefinition
beforeEach
(
async
()
=>
{
replacedParams
=
setPlaceholderStrings
(
cloneDeep
(
parameters
),
OVM_ExecutionManager
,
OVM_StateManager
,
OVM_SafetyChecker
,
OVM_CallHelper
,
OVM_RevertHelper
)
replacedTest
=
setPlaceholderStrings
(
cloneDeep
(
test
),
OVM_ExecutionManager
,
OVM_StateManager
,
OVM_SafetyChecker
,
OVM_CallHelper
,
OVM_RevertHelper
)
})
beforeEach
(
async
()
=>
{
await
OVM_ExecutionManager
.
__setContractStorage
(
replacedTest
.
preState
.
ExecutionManager
)
await
OVM_StateManager
.
__setContractStorage
(
replacedTest
.
preState
.
StateManager
)
})
afterEach
(
async
()
=>
{
await
OVM_ExecutionManager
.
__checkContractStorage
({
...
replacedTest
.
postState
.
ExecutionManager
,
})
await
OVM_StateManager
.
__checkContractStorage
({
...
replacedTest
.
postState
.
StateManager
,
})
})
parameters
.
steps
.
map
((
step
,
idx
)
=>
{
const
scopedFunction
=
!!
test
.
focus
?
it
.
only
:
it
scopedFunction
(
`should run test:
${
test
.
name
}
${
idx
}
`
,
async
()
=>
{
const
testGenerator
=
getTestGenerator
(
replacedParams
.
steps
[
idx
],
OVM_ExecutionManager
,
OVM_CallHelper
,
OVM_CreateStorer
,
(
await
ethers
.
getContractFactory
(
'
Helper_CodeContractForCreates
'
))
.
interface
,
OVM_RevertHelper
,
OVM_InvalidHelper
)
const
callResult
=
await
OVM_ExecutionManager
.
provider
.
call
({
to
:
OVM_ExecutionManager
.
address
,
data
:
testGenerator
.
getCalldata
(),
gasLimit
:
GAS_LIMIT
,
})
await
OVM_ExecutionManager
.
signer
.
sendTransaction
({
to
:
OVM_ExecutionManager
.
address
,
data
:
testGenerator
.
getCalldata
(),
gasLimit
:
GAS_LIMIT
,
})
const
interpretation
=
testGenerator
.
interpretActualReturnData
(
callResult
,
true
)
console
.
log
(
'
interpretation of actual results:
\n
'
+
interpretation
)
// in future we can add conditional here but for now always assume succeed
const
interpretationOfExpected
=
testGenerator
.
interpretActualReturnData
(
testGenerator
.
getReturnData
(),
true
)
console
.
log
(
'
interpretation of expected:
\n
'
+
interpretationOfExpected
)
expect
(
callResult
).
to
.
equal
(
testGenerator
.
getReturnData
())
//, 'got bad response, looks like it did:\n' + testGenerator.interpretActualReturnData(callResult))
})
})
}
})
})
}
packages/contracts/test/helpers/test-utils/test-runner.ts
0 → 100644
View file @
cf113fec
import
{
expect
}
from
'
../../setup
'
/* External Imports */
import
{
ethers
}
from
'
@nomiclabs/buidler
'
import
{
Contract
,
BigNumber
,
ContractFactory
}
from
'
ethers
'
import
{
cloneDeep
}
from
'
lodash
'
/* Internal Imports */
import
{
TestDefinition
,
TestStep
,
isTestStep_SSTORE
,
isTestStep_SLOAD
,
isTestStep_CALL
,
isTestStep_CREATE
,
isTestStep_CREATE2
,
isTestStep_Context
,
ParsedTestStep
,
isRevertFlagError
,
TestParameter
,
isTestStep_evm
,
isTestStep_EXTCODESIZE
,
isTestStep_EXTCODEHASH
,
isTestStep_EXTCODECOPY
,
isTestStep_REVERT
,
}
from
'
./test.types
'
import
{
encodeRevertData
}
from
'
../codec
'
import
{
getModifiableStorageFactory
}
from
'
../storage/contract-storage
'
import
{
GAS_LIMIT
,
NON_NULL_BYTES32
}
from
'
../constants
'
export
class
ExecutionManagerTestRunner
{
private
snapshot
:
string
private
contracts
:
{
OVM_SafetyChecker
:
Contract
OVM_StateManager
:
Contract
OVM_ExecutionManager
:
Contract
Helper_TestRunner
:
Contract
Factory__Helper_TestRunner_CREATE
:
ContractFactory
}
=
{
OVM_SafetyChecker
:
undefined
,
OVM_StateManager
:
undefined
,
OVM_ExecutionManager
:
undefined
,
Helper_TestRunner
:
undefined
,
Factory__Helper_TestRunner_CREATE
:
undefined
,
}
public
run
(
test
:
TestDefinition
)
{
test
.
preState
=
test
.
preState
||
{}
test
.
postState
=
test
.
postState
||
{}
describe
(
`OVM_ExecutionManager Test:
${
test
.
name
}
`
,
()
=>
{
test
.
subTests
?.
map
((
subTest
)
=>
{
this
.
run
({
...
subTest
,
preState
:
{
...
test
.
preState
,
...
subTest
.
preState
,
},
postState
:
{
...
test
.
postState
,
...
subTest
.
postState
,
},
})
})
test
.
parameters
?.
map
((
parameter
)
=>
{
beforeEach
(
async
()
=>
{
await
this
.
initContracts
()
})
let
replacedTest
:
TestDefinition
let
replacedParameter
:
TestParameter
beforeEach
(
async
()
=>
{
replacedTest
=
this
.
setPlaceholderStrings
(
test
)
replacedParameter
=
this
.
setPlaceholderStrings
(
parameter
)
})
beforeEach
(
async
()
=>
{
await
this
.
contracts
.
OVM_StateManager
.
__setContractStorage
({
accounts
:
{
[
this
.
contracts
.
Helper_TestRunner
.
address
]:
{
nonce
:
0
,
codeHash
:
NON_NULL_BYTES32
,
ethAddress
:
this
.
contracts
.
Helper_TestRunner
.
address
,
},
},
})
})
beforeEach
(
async
()
=>
{
await
this
.
contracts
.
OVM_ExecutionManager
.
__setContractStorage
(
replacedTest
.
preState
.
ExecutionManager
)
await
this
.
contracts
.
OVM_StateManager
.
__setContractStorage
(
replacedTest
.
preState
.
StateManager
)
})
afterEach
(
async
()
=>
{
await
this
.
contracts
.
OVM_ExecutionManager
.
__checkContractStorage
(
replacedTest
.
postState
.
ExecutionManager
)
await
this
.
contracts
.
OVM_StateManager
.
__checkContractStorage
(
replacedTest
.
postState
.
StateManager
)
})
if
(
parameter
.
focus
)
{
it
.
only
(
`should execute:
${
parameter
.
name
}
`
,
async
()
=>
{
for
(
const
step
of
replacedParameter
.
steps
)
{
await
this
.
runTestStep
(
step
)
}
})
}
else
{
it
(
`should execute:
${
parameter
.
name
}
`
,
async
()
=>
{
for
(
const
step
of
replacedParameter
.
steps
)
{
await
this
.
runTestStep
(
step
)
}
})
}
})
})
}
private
async
initContracts
()
{
if
(
this
.
snapshot
)
{
await
ethers
.
provider
.
send
(
'
evm_revert
'
,
[
this
.
snapshot
])
return
}
this
.
contracts
.
OVM_SafetyChecker
=
await
(
await
ethers
.
getContractFactory
(
'
OVM_SafetyChecker
'
)
).
deploy
()
this
.
contracts
.
OVM_ExecutionManager
=
await
(
await
getModifiableStorageFactory
(
'
OVM_ExecutionManager
'
)
).
deploy
(
this
.
contracts
.
OVM_SafetyChecker
.
address
)
this
.
contracts
.
OVM_StateManager
=
await
(
await
getModifiableStorageFactory
(
'
OVM_StateManager
'
)
).
deploy
(
this
.
contracts
.
OVM_ExecutionManager
.
address
)
this
.
contracts
.
Helper_TestRunner
=
await
(
await
ethers
.
getContractFactory
(
'
Helper_TestRunner
'
)
).
deploy
()
this
.
contracts
.
Factory__Helper_TestRunner_CREATE
=
await
ethers
.
getContractFactory
(
'
Helper_TestRunner_CREATE
'
)
this
.
snapshot
=
await
ethers
.
provider
.
send
(
'
evm_snapshot
'
,
[])
}
private
setPlaceholderStrings
(
obj
:
any
)
{
const
getReplacementString
=
(
kv
:
string
):
string
=>
{
if
(
kv
===
'
$OVM_EXECUTION_MANAGER
'
)
{
return
this
.
contracts
.
OVM_ExecutionManager
.
address
}
else
if
(
kv
===
'
$OVM_STATE_MANAGER
'
)
{
return
this
.
contracts
.
OVM_StateManager
.
address
}
else
if
(
kv
===
'
$OVM_SAFETY_CHECKER
'
)
{
return
this
.
contracts
.
OVM_SafetyChecker
.
address
}
else
if
(
kv
===
'
$OVM_CALL_HELPER
'
)
{
return
this
.
contracts
.
Helper_TestRunner
.
address
}
else
if
(
kv
.
startsWith
(
'
$DUMMY_OVM_ADDRESS_
'
))
{
return
'
0x
'
+
(
kv
.
split
(
'
$DUMMY_OVM_ADDRESS_
'
)[
1
]
+
'
0
'
).
repeat
(
20
)
}
else
{
return
kv
}
}
let
ret
:
any
=
cloneDeep
(
obj
)
if
(
Array
.
isArray
(
ret
))
{
ret
=
ret
.
map
((
element
:
any
)
=>
{
return
this
.
setPlaceholderStrings
(
element
)
})
}
else
if
(
typeof
ret
===
'
object
'
&&
ret
!==
null
)
{
for
(
const
key
of
Object
.
keys
(
ret
))
{
const
replacedKey
=
getReplacementString
(
key
)
if
(
replacedKey
!==
key
)
{
ret
[
replacedKey
]
=
ret
[
key
]
delete
ret
[
key
]
}
ret
[
replacedKey
]
=
this
.
setPlaceholderStrings
(
ret
[
replacedKey
])
}
}
else
if
(
typeof
ret
===
'
string
'
)
{
ret
=
getReplacementString
(
ret
)
}
return
ret
}
private
async
runTestStep
(
step
:
TestStep
)
{
await
this
.
contracts
.
OVM_ExecutionManager
.
ovmCALL
(
GAS_LIMIT
/
2
,
this
.
contracts
.
Helper_TestRunner
.
address
,
this
.
contracts
.
Helper_TestRunner
.
interface
.
encodeFunctionData
(
'
runSingleTestStep
'
,
[
this
.
parseTestStep
(
step
)]
)
)
}
private
parseTestStep
(
step
:
TestStep
):
ParsedTestStep
{
return
{
functionName
:
step
.
functionName
,
functionData
:
this
.
encodeFunctionData
(
step
),
expectedReturnStatus
:
this
.
getReturnStatus
(
step
),
expectedReturnData
:
this
.
encodeExpectedReturnData
(
step
),
}
}
private
getReturnStatus
(
step
:
TestStep
):
boolean
{
if
(
isTestStep_evm
(
step
))
{
return
false
}
else
if
(
isTestStep_Context
(
step
))
{
return
true
}
else
{
return
step
.
expectedReturnStatus
}
}
private
encodeFunctionData
(
step
:
TestStep
):
string
{
if
(
isTestStep_evm
(
step
))
{
if
(
isRevertFlagError
(
step
.
returnData
))
{
return
encodeRevertData
(
step
.
returnData
.
flag
,
step
.
returnData
.
data
,
step
.
returnData
.
nuisanceGasLeft
,
step
.
returnData
.
ovmGasRefund
)
}
else
{
return
step
.
returnData
||
'
0x
'
}
}
let
functionParams
:
any
[]
=
[]
if
(
isTestStep_SSTORE
(
step
)
||
isTestStep_SLOAD
(
step
)
||
isTestStep_EXTCODESIZE
(
step
)
||
isTestStep_EXTCODEHASH
(
step
)
||
isTestStep_EXTCODECOPY
(
step
)
)
{
functionParams
=
Object
.
values
(
step
.
functionParams
)
}
else
if
(
isTestStep_CALL
(
step
))
{
functionParams
=
[
step
.
functionParams
.
gasLimit
,
step
.
functionParams
.
target
,
step
.
functionParams
.
calldata
||
this
.
contracts
.
Helper_TestRunner
.
interface
.
encodeFunctionData
(
'
runMultipleTestSteps
'
,
[
step
.
functionParams
.
subSteps
.
map
((
subStep
)
=>
{
return
this
.
parseTestStep
(
subStep
)
}),
]
),
]
}
else
if
(
isTestStep_CREATE
(
step
))
{
functionParams
=
[
this
.
contracts
.
Factory__Helper_TestRunner_CREATE
.
getDeployTransaction
(
step
.
functionParams
.
bytecode
||
'
0x
'
,
step
.
functionParams
.
subSteps
?.
map
((
subStep
)
=>
{
return
this
.
parseTestStep
(
subStep
)
})
||
[]
).
data
,
]
}
else
if
(
isTestStep_REVERT
(
step
))
{
functionParams
=
[
step
.
revertData
||
'
0x
'
]
}
return
this
.
contracts
.
OVM_ExecutionManager
.
interface
.
encodeFunctionData
(
step
.
functionName
,
functionParams
)
}
private
encodeExpectedReturnData
(
step
:
TestStep
):
string
{
if
(
isTestStep_evm
(
step
))
{
return
'
0x
'
}
if
(
isTestStep_REVERT
(
step
))
{
return
step
.
expectedReturnValue
||
'
0x
'
}
if
(
isRevertFlagError
(
step
.
expectedReturnValue
))
{
return
encodeRevertData
(
step
.
expectedReturnValue
.
flag
,
step
.
expectedReturnValue
.
data
,
step
.
expectedReturnValue
.
nuisanceGasLeft
,
step
.
expectedReturnValue
.
ovmGasRefund
)
}
let
returnData
:
any
[]
=
[]
if
(
isTestStep_CALL
(
step
))
{
if
(
step
.
expectedReturnValue
===
'
0x00
'
)
{
return
step
.
expectedReturnValue
}
else
{
returnData
=
[
step
.
expectedReturnStatus
,
step
.
expectedReturnValue
||
'
0x
'
,
]
}
}
else
if
(
BigNumber
.
isBigNumber
(
step
.
expectedReturnValue
))
{
returnData
=
[
step
.
expectedReturnValue
.
toHexString
()]
}
else
if
(
step
.
expectedReturnValue
!==
undefined
)
{
if
(
step
.
expectedReturnValue
===
'
0x00
'
)
{
return
step
.
expectedReturnValue
}
else
{
returnData
=
[
step
.
expectedReturnValue
]
}
}
return
this
.
contracts
.
OVM_ExecutionManager
.
interface
.
encodeFunctionResult
(
step
.
functionName
,
returnData
)
}
}
packages/contracts/test/helpers/test-utils/test.types.ts
View file @
cf113fec
/* External Imports */
/* External Imports */
import
{
BigNumber
}
from
'
ethers
'
import
{
BigNumber
}
from
'
ethers
'
export
type
SolidityFunctionParameter
=
string
|
number
|
BigNumber
export
type
ContextOpcode
=
|
'
ovmCALLER
'
|
'
ovmADDRESS
'
|
'
ovmORIGIN
'
|
'
ovmTIMESTAMP
'
|
'
ovmGASLIMIT
'
|
'
ovmCHAINID
'
export
interface
TestStep
{
type
CallOpcode
=
'
ovmCALL
'
|
'
ovmSTATICCALL
'
|
'
ovmDELEGATECALL
'
type
RevertFlagError
=
{
flag
:
number
nuisanceGasLeft
?:
number
ovmGasRefund
?:
number
data
?:
string
}
interface
TestStep_evm
{
functionName
:
'
evmRETURN
'
|
'
evmREVERT
'
|
'
evmINVALID
'
returnData
?:
string
|
RevertFlagError
}
interface
TestStep_Context
{
functionName
:
ContextOpcode
expectedReturnValue
:
string
|
number
|
BigNumber
}
interface
TestStep_REVERT
{
functionName
:
'
ovmREVERT
'
revertData
?:
string
expectedReturnStatus
:
boolean
expectedReturnValue
?:
string
}
interface
TestStep_EXTCODESIZE
{
functionName
:
'
ovmEXTCODESIZE
'
functionParams
:
{
address
:
string
}
expectedReturnStatus
:
boolean
expectedReturnValue
:
number
|
RevertFlagError
}
interface
TestStep_EXTCODEHASH
{
functionName
:
'
ovmEXTCODEHASH
'
functionParams
:
{
address
:
string
}
expectedReturnStatus
:
boolean
expectedReturnValue
:
string
|
RevertFlagError
}
interface
TestStep_EXTCODECOPY
{
functionName
:
'
ovmEXTCODECOPY
'
functionParams
:
{
address
:
string
offset
:
number
length
:
number
}
expectedReturnStatus
:
boolean
expectedReturnValue
:
string
|
RevertFlagError
}
interface
TestStep_SSTORE
{
functionName
:
'
ovmSSTORE
'
functionParams
:
{
key
:
string
value
:
string
}
expectedReturnStatus
:
boolean
expectedReturnValue
?:
RevertFlagError
}
interface
TestStep_SLOAD
{
functionName
:
'
ovmSLOAD
'
functionParams
:
{
key
:
string
}
expectedReturnStatus
:
boolean
expectedReturnValue
:
string
|
RevertFlagError
}
interface
TestStep_CALL
{
functionName
:
CallOpcode
functionParams
:
{
gasLimit
:
number
|
BigNumber
target
:
string
calldata
?:
string
subSteps
?:
TestStep
[]
}
expectedReturnStatus
:
boolean
expectedReturnValue
?:
string
|
RevertFlagError
}
interface
TestStep_CREATE
{
functionName
:
'
ovmCREATE
'
functionParams
:
{
bytecode
?:
string
subSteps
?:
TestStep
[]
}
expectedReturnStatus
:
boolean
expectedReturnValue
:
string
|
RevertFlagError
}
interface
TestStep_CREATE2
{
functionName
:
'
ovmCREATE2
'
functionParams
:
{
salt
:
string
bytecode
?:
string
subSteps
?:
TestStep
[]
}
expectedReturnStatus
:
boolean
expectedReturnValue
:
string
|
RevertFlagError
}
export
type
TestStep
=
|
TestStep_Context
|
TestStep_SSTORE
|
TestStep_SLOAD
|
TestStep_CALL
|
TestStep_CREATE
|
TestStep_CREATE2
|
TestStep_EXTCODESIZE
|
TestStep_EXTCODEHASH
|
TestStep_EXTCODECOPY
|
TestStep_REVERT
|
TestStep_evm
export
interface
ParsedTestStep
{
functionName
:
string
functionName
:
string
functionParams
:
Array
<
functionData
:
string
|
SolidityFunctionParameter
|
SolidityFunctionParameter
[]
|
TestStep
[]
|
boolean
>
expectedReturnStatus
:
boolean
expectedReturnStatus
:
boolean
expectedReturn
Values
:
any
[]
expectedReturn
Data
:
string
}
}
export
interface
TestParameters
{
export
const
isRevertFlagError
=
(
steps
:
TestStep
[]
expectedReturnValue
:
any
):
expectedReturnValue
is
RevertFlagError
=>
{
return
(
typeof
expectedReturnValue
===
'
object
'
&&
expectedReturnValue
!==
null
&&
expectedReturnValue
.
flag
!==
undefined
)
}
}
export
interface
TestDefinition
{
export
const
isTestStep_evm
=
(
step
:
TestStep
):
step
is
TestStep_evm
=>
{
return
[
'
evmRETURN
'
,
'
evmREVERT
'
,
'
evmINVALID
'
].
includes
(
step
.
functionName
)
}
export
const
isTestStep_Context
=
(
step
:
TestStep
):
step
is
TestStep_Context
=>
{
return
[
'
ovmCALLER
'
,
'
ovmADDRESS
'
,
'
ovmORIGIN
'
,
'
ovmTIMESTAMP
'
,
'
ovmGASLIMIT
'
,
'
ovmCHAINID
'
,
].
includes
(
step
.
functionName
)
}
export
const
isTestStep_SSTORE
=
(
step
:
TestStep
):
step
is
TestStep_SSTORE
=>
{
return
step
.
functionName
==
'
ovmSSTORE
'
}
export
const
isTestStep_SLOAD
=
(
step
:
TestStep
):
step
is
TestStep_SLOAD
=>
{
return
step
.
functionName
==
'
ovmSLOAD
'
}
export
const
isTestStep_EXTCODESIZE
=
(
step
:
TestStep
):
step
is
TestStep_EXTCODESIZE
=>
{
return
step
.
functionName
==
'
ovmEXTCODESIZE
'
}
export
const
isTestStep_EXTCODEHASH
=
(
step
:
TestStep
):
step
is
TestStep_EXTCODEHASH
=>
{
return
step
.
functionName
==
'
ovmEXTCODEHASH
'
}
export
const
isTestStep_EXTCODECOPY
=
(
step
:
TestStep
):
step
is
TestStep_EXTCODECOPY
=>
{
return
step
.
functionName
==
'
ovmEXTCODECOPY
'
}
export
const
isTestStep_REVERT
=
(
step
:
TestStep
):
step
is
TestStep_REVERT
=>
{
return
step
.
functionName
==
'
ovmREVERT
'
}
export
const
isTestStep_CALL
=
(
step
:
TestStep
):
step
is
TestStep_CALL
=>
{
return
[
'
ovmCALL
'
,
'
ovmSTATICCALL
'
,
'
ovmDELEGATECALL
'
].
includes
(
step
.
functionName
)
}
export
const
isTestStep_CREATE
=
(
step
:
TestStep
):
step
is
TestStep_CREATE
=>
{
return
step
.
functionName
==
'
ovmCREATE
'
}
export
const
isTestStep_CREATE2
=
(
step
:
TestStep
):
step
is
TestStep_CREATE2
=>
{
return
step
.
functionName
==
'
ovmCREATE2
'
}
interface
TestState
{
ExecutionManager
:
any
StateManager
:
any
}
export
interface
TestParameter
{
name
:
string
name
:
string
focus
?:
boolean
focus
?:
boolean
preState
?:
{
steps
:
TestStep
[]
ExecutionManager
?:
any
StateManager
?:
any
}
parameters
:
Array
<
TestParameters
|
TestDefinition
>
postState
?:
{
ExecutionManager
?:
any
StateManager
?:
any
}
}
}
export
const
isTestDefinition
=
(
export
interface
TestDefinition
{
parameters
:
TestParameters
|
TestDefinition
name
:
string
):
parameters
is
TestDefinition
=>
{
focus
?:
boolean
return
(
parameters
as
TestDefinition
).
name
!==
undefined
preState
?:
Partial
<
TestState
>
postState
?:
Partial
<
TestState
>
parameters
?:
TestParameter
[]
subTests
?:
TestDefinition
[]
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment