Skip to content

Commit

Permalink
Add initial StateTransitioner & FraudProver (#156)
Browse files Browse the repository at this point in the history
* WIP partial state manager

* Move associate code contract into SM deploy

* Sketch out more of the partial state mgr

* Add outlines of partial state mgr & fraud verifier

* Add onlyFraudVerifier / EM modifiers

* Remove saftey checker from PSM & add setStateMgr to EM

* Split up state manager into StateTransitioner

* Make the prestate transition index more explicit

* Begin adding pre & post tx execution

* Add a basic SafeContractRegistry

* Remove unneeded SafeContractRegistry

* Add TransitionPhases & PreTransition functions

* Add Stub EM & finish phases of Transitioner

* Lint

* Rename ensureValid.. with flagIfInvalid

* Move contract deployment back into the EM

* Small fixes

- Remove extra TODO comment
- Remvoe unneeded functions from the PartialStateManager
  • Loading branch information
karlfloersch authored Jul 1, 2020
1 parent 7c08e11 commit 88f93e2
Show file tree
Hide file tree
Showing 11 changed files with 737 additions and 78 deletions.
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);
}

/**
* @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 {
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;
}
}
Loading

0 comments on commit 88f93e2

Please sign in to comment.