Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
207cbe8
Moved all OVM files and deleted the package
smartcontracts Jun 24, 2020
358ea4c
Started cleaning contracts
smartcontracts Jun 24, 2020
922536a
Quick contract cleanup
smartcontracts Jun 24, 2020
073448a
Added cleaned contracts
smartcontracts Jun 25, 2020
64b7000
Fixed merge conflicts
smartcontracts Jun 25, 2020
ba1d7bc
Fixed package.json
smartcontracts Jun 25, 2020
16b9374
Removed /ovm requirements
smartcontracts Jun 25, 2020
30e6b2e
Fixed circular dependencies
smartcontracts Jun 25, 2020
3e1801b
Fixed various linting errors
smartcontracts Jun 25, 2020
fc409d8
Fixed yet another ganache-core issue
smartcontracts Jun 25, 2020
41bc77c
Fixed bug causing tests to fail
smartcontracts Jun 26, 2020
3baed52
Fixed bug causing tests to fail
smartcontracts Jun 26, 2020
64c7f01
Merged master
smartcontracts Jun 26, 2020
78ce1bc
Merge branch 'master' of github.com:ethereum-optimism/optimism-monore…
smartcontracts Jun 26, 2020
4593033
Added older RLPEncode file again
smartcontracts Jun 26, 2020
5840831
Renamed rollup-contracts => contracts
smartcontracts Jun 26, 2020
45e94f4
Transitioned contracts to use buidler
smartcontracts Jun 30, 2020
470fbe1
Linted and added better export method
smartcontracts Jun 30, 2020
a2b9b85
Fixed a typo
smartcontracts Jun 30, 2020
9b94f0d
Merged master
smartcontracts Jul 1, 2020
2e3fa36
Removed unused imports
smartcontracts Jul 1, 2020
ef6a154
Removed unused variables
smartcontracts Jul 1, 2020
a0c695c
Started reworking test helpers
smartcontracts Jul 1, 2020
5af729c
Clean up test helpers
smartcontracts Jul 2, 2020
0259ab4
Fixed linting errors
smartcontracts Jul 2, 2020
4519577
Support globs in solcover
smartcontracts Jul 6, 2020
f35b7dc
Started to add proof details
smartcontracts Jul 6, 2020
5d0c209
Merged master and linted
smartcontracts Jul 6, 2020
64635a6
Merge branch 'YAS-467/contracts/coverage' of github.com:ethereum-opti…
smartcontracts Jul 6, 2020
59afd25
Started adding real tests, fixed bugs
smartcontracts Jul 7, 2020
e987569
Added more tests
smartcontracts Jul 9, 2020
1986594
Added defaults to merkle trie
smartcontracts Jul 9, 2020
7e50548
Added tests for the fraud verifier
smartcontracts Jul 10, 2020
029ba29
Fixed package.json
smartcontracts Jul 10, 2020
0e09468
Fixed merge conflicts
smartcontracts Jul 10, 2020
b3f72d8
Added various suggested fixes
smartcontracts Jul 13, 2020
3c92950
Added more suggested fixes
smartcontracts Jul 13, 2020
62e1bd6
Resolved final suggestions
smartcontracts Jul 13, 2020
7d7728b
Merge branch 'master' into YAS-202/FraudVerifier/proofs
smartcontracts Jul 21, 2020
7642f91
Linted and fixed package.json
smartcontracts Jul 21, 2020
8d5f9ee
Fixed StateCommitmentChain errors
smartcontracts Jul 21, 2020
fe8bae9
Merge branch 'master' of github.com:ethereum-optimism/optimism-monore…
smartcontracts Jul 21, 2020
0aeecb7
Fixed issue with function visibility
smartcontracts Jul 21, 2020
a33fc96
Fixed fn visibility issue in contract tests
smartcontracts Jul 21, 2020
9dcb546
Removed incorrect test
smartcontracts Jul 21, 2020
d159864
Fixed linting errors
smartcontracts Jul 21, 2020
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
8 changes: 4 additions & 4 deletions packages/contracts/.solcover.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
/**
* SolCover configuration management:
*
*
* SolCover unfortunately doesn't provide us with the ability to exclusively
* generate coverage reports for a given file. Although we can use the
* `--testfiles`` parameter to limit tests to a particular glob, SolCover will
* still try to generate coverage reports for anything not covered within the
* `skipFiles` option exported below. `skipFiles` additionally does not parse
* globs, creating a mismatch between it and the `--testfiles` option.
*
*
* To address the above issues, we take the following steps:
* 1. Parse the `--testfiles` option from our command-line arguments.
* 2. Use the `--testfiles` option to find the list of contracts to be tested.
* 3. Find *all* contracts and exclude the results of (2).
* 4. Add the result of (3) to `skipFiles`.
*
*
* NOTE: The above will *only* work if contract test files follow the
* `<ContractName>.spec.ts` convention. Our function will fail to find the
* correct contracts otherwise.
*/
*/

const path = require('path')
const glob = require('glob')
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/buidler.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const config: BuidlerConfig = {
buidlerevm: {
accounts: DEFAULT_ACCOUNTS_BUIDLER,
blockGasLimit: GAS_LIMIT * 2,
allowUnlimitedContractSize: true, // TEMPORARY: Will be fixed by AddressResolver PR.
},
coverage: {
url: 'http://localhost:8555',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,20 @@ contract StateCommitmentChain {

constructor(
address _rollupMerkleUtilsAddress,
address _canonicalTransactionChain,
address _fraudVerifier
address _canonicalTransactionChain
) public {
merkleUtils = RollupMerkleUtils(_rollupMerkleUtilsAddress);
canonicalTransactionChain = CanonicalTransactionChain(_canonicalTransactionChain);
fraudVerifier = _fraudVerifier;
}

/*
* Public Functions
*/

function setFraudVerifier(address _fraudVerifier) public {
fraudVerifier = _fraudVerifier;
}

function getBatchesLength() public view returns (uint) {
return batches.length;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,9 @@ contract ExecutionManager {
// Next we need to actually create the contract in our state at that address
createNewContract(_newOvmContractAddress, _ovmInitcode);

// Insert the newly created contract into our state manager.
stateManager.associateCreatedContract(_newOvmContractAddress);

// We also need to increment the contract nonce
stateManager.incrementOvmContractNonce(creator);

Expand Down Expand Up @@ -665,6 +668,7 @@ contract ExecutionManager {

// Associate the code contract with our ovm contract
stateManager.associateCodeContract(_newOvmContractAddress, codeContractAddress);

// Get the code contract address to be emitted by a CreatedContract event
bytes32 codeContractHash = keccak256(codeContractBytecode);

Expand Down Expand Up @@ -899,7 +903,7 @@ contract ExecutionManager {
* [storageSlot (bytes32)]
* returndata: [storageValue (bytes32)]
*/
function ovmSLOAD() public view {
function ovmSLOAD() public {
bytes32 _storageSlot;
assembly {
// skip methodID (4 bytes)
Expand Down
294 changes: 277 additions & 17 deletions packages/contracts/contracts/optimistic-ethereum/ovm/FraudVerifier.sol
Original file line number Diff line number Diff line change
@@ -1,29 +1,289 @@
pragma solidity ^0.5.0;
pragma experimental ABIEncoderV2;

import {StateTransitioner} from "./StateTransitioner.sol";
/* Internal Imports */
import { DataTypes } from "../utils/DataTypes.sol";
import { RLPWriter } from "../utils/RLPWriter.sol";
import { StateCommitmentChain } from "../chain/StateCommitmentChain.sol";
import { CanonicalTransactionChain } from "../chain/CanonicalTransactionChain.sol";
import { ExecutionManager } from "./ExecutionManager.sol";
import { StateTransitioner } from "./StateTransitioner.sol";
import { IStateTransitioner } from "./interfaces/IStateTransitioner.sol";
import { StubStateTransitioner } from "./test-helpers/StubStateTransitioner.sol";
import { TransactionParser } from "./TransactionParser.sol";

/**
* @title FraudVerifier
* @notice The contract which is able to delete invalid state roots.
* @notice Manages fraud proof verification and modifies the state commitment
* chain in the case that a transaction is shown to be invalid.
*/
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;
/*
* Contract Variables
*/

ExecutionManager executionManager;
StateCommitmentChain stateCommitmentChain;
CanonicalTransactionChain canonicalTransactionChain;
mapping (uint256 => IStateTransitioner) public stateTransitioners;

bool isTest;

/*
* Constructor
*/

/**
* @param _executionManagerAddress Address of the ExecutionManager to use
* during the execution of transactions suspected to be fraudulent.
* @param _stateCommitmentChainAddress Address of the StateCommitmentChain
* to read state roots from and write to in the case that a fraud proof is
* successfully verified.
*/
constructor(
address _executionManagerAddress,
address _stateCommitmentChainAddress,
address _canonicalTransactionChainAddress,
bool _isTest
) public {
executionManager = ExecutionManager(_executionManagerAddress);
stateCommitmentChain = StateCommitmentChain(_stateCommitmentChainAddress);
canonicalTransactionChain = CanonicalTransactionChain(_canonicalTransactionChainAddress);

isTest = _isTest;
}


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;
/*
* Public Functions
*/

/**
* @notice Initializes the fraud proof verification process. Creates a new
* StateTransitioner instance if none already exists for the given state
* transition index.
* @param _preStateTransitionIndex Index of the state transition suspected
* to be fraudulent.
* @param _preStateRoot Root of the state trie before the state transition
* was executed.
* @param _preStateRootProof Inclusion proof for the given pre-state root.
* Since state roots are submitted in batches and merklized, we cannot
* simply read the state roots from the StateCommitmentChain.
* @param _transactionData Data for the transaction suspected to be
* fraudulent.
* @param _transactionProof Inclusion proof for the given transaction data.
* Since transactions are submitted in batches and merklized, we cannot
* simply read the state roots from the CanonicalTransactionChain.
*/
function initializeFraudVerification(
uint256 _preStateTransitionIndex,
bytes32 _preStateRoot,
DataTypes.StateElementInclusionProof memory _preStateRootProof,
DataTypes.OVMTransactionData memory _transactionData,
DataTypes.TxElementInclusionProof memory _transactionProof
) public {
// For user convenience; no point in carrying out extra work here if a
// StateTransitioner instance already exists for the given state
// transition index. Return early to save the user some gas.
if (hasStateTransitioner(_preStateTransitionIndex, _preStateRoot)) {
return;
}

require(
verifyStateRoot(
_preStateRoot,
_preStateTransitionIndex,
_preStateRootProof
),
"Provided pre-state root inclusion proof is invalid."
);

require(
verifyTransaction(
_transactionData,
_preStateTransitionIndex,
_transactionProof
),
"Provided transaction data is invalid."
);

// Note that a StateTransitioner may be overwritten when a state root
// *before* its pre-state root is shown to be fraudulent. This would
// invalidate the old StateTransitioner, creating the need to
// initialize a new one with the correct pre-state root. A case like
// this is handled by the hasStateTransitioner check above, which would
// fail when the existing StateTransitioner's pre-state root does not
// match the provided one.
if (isTest) {
stateTransitioners[_preStateTransitionIndex] = new StubStateTransitioner(
_preStateTransitionIndex,
_preStateRoot,
TransactionParser.getTransactionHash(_transactionData),
address(executionManager)
);
} else {
stateTransitioners[_preStateTransitionIndex] = new StateTransitioner(
_preStateTransitionIndex,
_preStateRoot,
TransactionParser.getTransactionHash(_transactionData),
address(executionManager)
);
}
}

/**
* @notice Finalizes the fraud verification process. Checks that the state
* transitioner has executed the transition to completion and that the
* resulting state root differs from the one previous published.
* @param _preStateTransitionIndex Index of the state transition suspected
* to be fraudulent.
* @param _postStateRoot Published root of the state trie after the state
* transition was executed. If the transition was indeed fraudulent, then
* this root will differ from the one computed by the StateTransitioner.
* @param _postStateRootProof Inclusion proof for the given pre-state root.
* Since state roots are submitted in batches and merklized, we cannot
* simply read the state roots from the StateCommitmentChain.
*/
function finalizeFraudVerification(
uint256 _preStateTransitionIndex,
bytes32 _preStateRoot,
DataTypes.StateElementInclusionProof memory _preStateRootProof,
bytes32 _postStateRoot,
DataTypes.StateElementInclusionProof memory _postStateRootProof
) public {
IStateTransitioner stateTransitioner = stateTransitioners[_preStateTransitionIndex];

// Fraud cannot be verified until the StateTransitioner has fully
// executed the given state transition. Otherwise, the
// StateTransitioner will always report an invalid root.
require(
stateTransitioner.isComplete(),
"State transition process has not been completed."
);

// We want the StateTransitioner to be reusable in the case that yet
// another invalid state root is published for the post-state. This
// saves users the gas cost of executing the entire state transition
// more than once. However, if a state root *before* the pre-state root
// was found to be fraudulent, then the StateTransitioner is no longer
// valid (since its execution is based on an outdated pre-state root).
// We therefore need to check that the StateTransitioner was based on
// the given pre-state root and that the pre-state root is still part
// of the StateCommitmentChain.
require(
_preStateRoot == stateTransitioner.preStateRoot(),
"Provided pre-state root does not match StateTransitioner."
);
require(
verifyStateRoot(
_preStateRoot,
_preStateTransitionIndex,
_preStateRootProof
),
"Provided pre-state root inclusion proof is invalid."
);

require(
verifyStateRoot(
_postStateRoot,
_preStateTransitionIndex + 1,
_postStateRootProof
),
"Provided post-state root inclusion proof is invalid."
);

// State transitions are fraudlent when the state root published to the
// StateCommitmentChain differs from the one computed by the
// StateTransitioner.
require(
_postStateRoot != stateTransitioner.stateRoot(),
"State transition has not been proven fraudulent."
);

// If we're here, then the state transition was found to be fraudulent.
// We therefore need to remove all state roots from the
// StateCommitmentChain after (and including) the fraudulent root.
// However, since state roots are submitted in batches, we'll actually
// need to remove all *batches* after (and including) the one in which
// the fraudulent root was published.
stateCommitmentChain.deleteAfterInclusive(
_postStateRootProof.batchIndex,
_postStateRootProof.batchHeader
);
}

/**
* @notice Utility; checks whether a StateTransitioner exists for a given
* state transition index. Can be used by clients to preemtively avoid
* attempts to initialize the same StateTransitioner multiple times.
* @param _stateTransitionIndex Index of the state transition suspected to
* be fraudulent.
* @param _preStateRoot Pre-state root used to initialize the transitioner.
* @return `true` if a StateTransitioner exists, `false` otherwise.
*/
function hasStateTransitioner(
uint256 _stateTransitionIndex,
bytes32 _preStateRoot
) public view returns (bool) {
IStateTransitioner stateTransitioner = stateTransitioners[_stateTransitionIndex];

return (
(address(stateTransitioner) != address(0x0)) &&
(stateTransitioner.preStateRoot() == _preStateRoot)
);
}


/*
* Internal Functions
*/

/**
* @notice Utility; verifies that a given state root is valid. Mostly just
* a convenience wrapper around the current verification method within
* StateCommitmentChain.
* @param _stateRoot State trie root to prove is included in the commitment
* chain.
* @param _stateRootIndex Global index of the state root within the list of
* all state roots.
* @param _stateRootProof Inclusion proof for the given state root and
* index pair.
* @return `true` if the root exists within the StateCommitmentChain,
* `false` otherwise.
*/
function verifyStateRoot(
bytes32 _stateRoot,
uint256 _stateRootIndex,
DataTypes.StateElementInclusionProof memory _stateRootProof
) internal view returns (bool) {
return stateCommitmentChain.verifyElement(
abi.encodePacked(_stateRoot),
_stateRootIndex,
_stateRootProof
);
}

/**
* @notice Utility; verifies that a given transaction is valid. Mostly just
* a convenience wrapper around the current verification method within
* CanonicalTransactionChain.
* @param _transaction OVM transaction data to verify.
* @param _transactionIndex Global index of the transaction within the list
* of all transactions
* @param _transactionProof Inclusion proof for the given transaction and
* index pair.
* @return `true` if the transaction exists within the
* CanonicalTransactionChain, `false` otherwise.
*/
function verifyTransaction(
DataTypes.OVMTransactionData memory _transaction,
uint256 _transactionIndex,
DataTypes.TxElementInclusionProof memory _transactionProof
) internal view returns (bool) {
return canonicalTransactionChain.verifyElement(
TransactionParser.encodeTransactionData(_transaction),
_transactionIndex,
_transactionProof
);
}
}
Loading