Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial StateTransitioner & FraudProver #156

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 47 additions & 6 deletions packages/rollup-contracts/contracts/ExecutionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pragma experimental ABIEncoderV2;
import {DataTypes as dt} from "./DataTypes.sol";
import {FullStateManager} from "./FullStateManager.sol";
import {ContractAddressGenerator} from "./ContractAddressGenerator.sol";
import {StubSafetyChecker} from "./ovm/test-helpers/StubSafetyChecker.sol";
import {SafetyChecker} from "./SafetyChecker.sol";
import {RLPEncode} from "./RLPEncode.sol";
import {L2ToL1MessagePasser} from "./precompiles/L2ToL1MessagePasser.sol";
import {L1MessageSender} from "./precompiles/L1MessageSender.sol";
Expand Down Expand Up @@ -34,6 +36,7 @@ contract ExecutionManager {
FullStateManager stateManager;
ContractAddressGenerator contractAddressGenerator;
RLPEncode rlp;
SafetyChecker safetyChecker;

/***************
* Other Fields *
Expand Down Expand Up @@ -76,7 +79,13 @@ contract ExecutionManager {
// Initialize new contract address generator
contractAddressGenerator = new ContractAddressGenerator();
// Deploy a default state manager
stateManager = new FullStateManager(_opcodeWhitelistMask, _overrideSafetyChecker);
stateManager = new FullStateManager();
// Deploy a safety checker. TODO: Pass this in as a constructor and remove `_overrideSafetyChecker`
if (!_overrideSafetyChecker) {
safetyChecker = new SafetyChecker(_opcodeWhitelistMask, address(this));
} else {
safetyChecker = new StubSafetyChecker();
}

// Associate all Ethereum precompiles
for (uint160 i = 1; i < 20; i++) {
Expand All @@ -96,6 +105,14 @@ contract ExecutionManager {
// TODO
}

/**
* @notice Sets a new state manager to be associated with the execution manager.
* This is used when we want to swap out a new backend to be used for a different execution.
*/
function setStateManager(address _stateManagerAddress) external {
stateManager = FullStateManager(_stateManagerAddress);
}
Comment on lines +112 to +114
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this function meant to be atomically called before executeTransaction? If so, might be able to move that logic there in a future PR. If not atomic, do we need to authenticate that it's coming from the fraud prover?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah i totally agree we might as well put it into executeTransaction(..) itself


/**
* @notice Increments the provided address's nonce.
* This is only used by the sequencer to correct nonces when transactions fail.
Expand Down Expand Up @@ -573,18 +590,23 @@ contract ExecutionManager {
* @return True if this succeeded, false otherwise.
*/
function createNewContract(address _newOvmContractAddress, bytes memory _ovmInitcode) internal returns (bool){
if (!safetyChecker.isBytecodeSafe(_ovmInitcode)) {
// Contract init code is not safe.
return false;
}
// Switch the context to be the new contract
(address oldMsgSender, address oldActiveContract) = switchActiveContract(_newOvmContractAddress);
// Deploy the _ovmInitcode as a code contract -- Note the init script will run in the newly set context
address codeContractAddress = stateManager.deployContract(_newOvmContractAddress, _ovmInitcode);
// Return false if the contract failed to deploy
if (codeContractAddress == ZERO_ADDRESS) {
restoreContractContext(oldMsgSender, oldActiveContract);
address codeContractAddress = deployCodeContract(_ovmInitcode);
// Get the runtime bytecode
bytes memory codeContractBytecode = stateManager.getCodeContractBytecode(codeContractAddress);
// Safety check the runtime bytecode
if (!safetyChecker.isBytecodeSafe(codeContractBytecode)) {
// Contract runtime bytecode is not safe.
return false;
}
// Associate the code contract with our ovm contract
stateManager.associateCodeContract(_newOvmContractAddress, codeContractAddress);
bytes memory codeContractBytecode = stateManager.getCodeContractBytecode(codeContractAddress);
// Get the code contract address to be emitted by a CreatedContract event
bytes32 codeContractHash = keccak256(codeContractBytecode);
// Revert to the previous the context
Expand All @@ -594,6 +616,24 @@ contract ExecutionManager {
return true;
}

/**
* @notice Deploys a code contract, and then registers it to the state
* @param _ovmContractInitcode The bytecode of the contract to be deployed
* @return the codeContractAddress.
*/
function deployCodeContract(bytes memory _ovmContractInitcode) internal returns(address codeContractAddress) {
// Deploy a new contract with this _ovmContractInitCode
assembly {
// Set our codeContractAddress to the address returned by our CREATE operation
codeContractAddress := create(0, add(_ovmContractInitcode, 0x20), mload(_ovmContractInitcode))
// Make sure that the CREATE was successful (actually deployed something)
if iszero(extcodesize(codeContractAddress)) {
revert(0, 0)
}
}
return codeContractAddress;
}

/************************
* Contract CALL Opcodes *
************************/
Expand Down Expand Up @@ -894,6 +934,7 @@ contract ExecutionManager {
address _targetOvmContractAddress = address(bytes20(_targetAddressBytes));
address codeContractAddress = stateManager.getCodeContractAddress(_targetOvmContractAddress);

// TODO: Replace `getCodeContractHash(...) with `getOvmContractHash(...)
bytes32 hash = stateManager.getCodeContractHash(codeContractAddress);

assembly {
Expand Down
55 changes: 1 addition & 54 deletions packages/rollup-contracts/contracts/FullStateManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,12 @@ import {SafetyChecker} from "./SafetyChecker.sol";
* of all chain storage.
*/
contract FullStateManager is StateManager {
// Add Safety Checker contract
SafetyChecker safetyChecker;
// for testing: if true, then do not perform safety checking on init code or deployed bytecode
bool overrideSafetyChecker;

address ZERO_ADDRESS = 0x0000000000000000000000000000000000000000;

mapping(address=>mapping(bytes32=>bytes32)) ovmContractStorage;
mapping(address=>uint) ovmContractNonces;
mapping(address=>address) ovmCodeContracts;

/**
* @notice Construct a new FullStateManager with a specified safety checker.
* @param _opcodeWhitelistMask A bit mask representing which opcodes are whitelisted or not for our safety checker
* @param _overrideSafetyChecker Set to true to disable safety checking (WARNING: Only do this in test environments)
*/
constructor(uint256 _opcodeWhitelistMask, bool _overrideSafetyChecker) public {
// Set override safety checker flag
overrideSafetyChecker = _overrideSafetyChecker;
// Set the safety checker address -- NOTE: `msg.sender` is used as EM address because we assume
// the FullStateManager is deployed by the ExecutionManager
safetyChecker = new SafetyChecker(_opcodeWhitelistMask, msg.sender);
}


/**********
* Storage *
Expand Down Expand Up @@ -104,7 +86,7 @@ contract FullStateManager is StateManager {
* @param _ovmContractAddress The address of the OVM contract we'd like to associate with some code.
* @param _codeContractAddress The address of the code contract that's been deployed.
*/
function associateCodeContract(address _ovmContractAddress, address _codeContractAddress) external {
function associateCodeContract(address _ovmContractAddress, address _codeContractAddress) public {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this need to be authenticated? Would expect only the Fraud Verifier to be able to populate these associations.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, whoops, I see that this isn't the PSM. Will just resurface the nit/bikeshed that TestStateManager and TestExecutionManager could be better names for these non-fraud-proof contracts.

ovmCodeContracts[_ovmContractAddress] = _codeContractAddress;
}

Expand Down Expand Up @@ -150,39 +132,4 @@ contract FullStateManager is StateManager {
_codeContractHash = keccak256(codeContractBytecode);
return _codeContractHash;
}

/**
* @notice Deploys a code contract, and then registers it to the state
* @param _newOvmContractAddress The contract address to deploy the new contract to
* @param _ovmContractInitcode The bytecode of the contract to be deployed
* @return the codeContractAddress.
*/
function deployContract(
address _newOvmContractAddress,
bytes memory _ovmContractInitcode
) public returns(address codeContractAddress) {
// Safety check the initcode, unless the overrideSafetyChecker flag is set to true
if (!overrideSafetyChecker && !safetyChecker.isBytecodeSafe(_ovmContractInitcode)) {
// Contract initcode is not pure.
return ZERO_ADDRESS;
}

// Deploy a new contract with this _ovmContractInitCode
assembly {
// Set our codeContractAddress to the address returned by our CREATE operation
codeContractAddress := create(0, add(_ovmContractInitcode, 0x20), mload(_ovmContractInitcode))
// Make sure that the CREATE was successful (actually deployed something)
if iszero(extcodesize(codeContractAddress)) {
revert(0, 0)
}
}

// Safety check the runtime bytecode, unless the overrideSafetyChecker flag is set to true
bytes memory codeContractBytecode = getCodeContractBytecode(codeContractAddress);
if (!overrideSafetyChecker && !safetyChecker.isBytecodeSafe(codeContractBytecode)) {
// Contract runtime bytecode is not pure.
return ZERO_ADDRESS;
}
return codeContractAddress;
}
}
16 changes: 0 additions & 16 deletions packages/rollup-contracts/contracts/PartialStateManager.sol

This file was deleted.

3 changes: 1 addition & 2 deletions packages/rollup-contracts/contracts/StateManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ contract StateManager {
function incrementOvmContractNonce(address _ovmContractAddress) external;

// Contract code storage / contract address retrieval
function deployContract(address _newOvmContractAddress, bytes memory _ovmContractInitcode) public returns(address codeContractAddress);
function associateCodeContract(address _ovmContractAddress, address _codeContractAddress) external;
function associateCodeContract(address _ovmContractAddress, address _codeContractAddress) public;
function getCodeContractAddress(address _ovmContractAddress) external view returns(address);
function getCodeContractBytecode(address _codeContractAddress) public view returns (bytes memory codeContractBytecode);
function getCodeContractHash(address _codeContractAddress) external view returns (bytes32 _codeContractHash);
Expand Down
27 changes: 27 additions & 0 deletions packages/rollup-contracts/contracts/ovm/FraudVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
pragma solidity ^0.5.0;

import {StateTransitioner} from "./StateTransitioner.sol";

/**
* @title FraudVerifier
* @notice The contract which is able to delete invalid state roots.
*/
contract FraudVerifier {
mapping(uint=>StateTransitioner) stateTransitioners;

function initNewStateTransitioner(uint _preStateTransitionIndex) public returns(bool) {
// TODO:
// Create a new state transitioner for some specific pre-state transition index (assuming one hasn't already been made).
// Note that the invalid state root that we are verifying is at _preStateTransitionIndex+1.
// Add it to the stateTransitioners mapping! -- stateTransitioners[_preStateTransitionIndex] = newStateTransitioner;
return true;
}


function verifyFraud(uint _transitionIndex) public returns(bool) {
// TODO:
// Simply verify that the state transitioner has completed, and that the state root
// at _preStateTransitionIndex+1 is not equal to the state root which was committed for that index.
return true;
}
Comment on lines +21 to +26
Copy link
Collaborator

Choose a reason for hiding this comment

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

Note that in the current contracts I believe that the FraudVerifier is meant to call out to the state commitment chain to delete if there is fraud. It's a small change, but should update either this TODO or have one for the commitment chain.

}
Loading