Commit 4c546a1f authored by Kelvin Fichter's avatar Kelvin Fichter Committed by GitHub

Integrates BondManager into master (#25)

* Upgraded to new RingBuffer

* First pass at verification function

* Removed BaseChain as a contract

* Update OVM_CanonicalTransactionChain.spec.ts

* Removed unused chain variable

* Added overwriting logic to CTC

* Corrected CTC event emit

* Remove timebound ring buffer tests

* Integrated bond manager PR
Co-authored-by: default avatarGeorgios Konstantopoulos <me@gakonst.com>
parent 43b3b3b0
...@@ -12,6 +12,8 @@ import { Lib_RingBuffer, iRingBufferOverwriter } from "../../libraries/utils/Lib ...@@ -12,6 +12,8 @@ import { Lib_RingBuffer, iRingBufferOverwriter } from "../../libraries/utils/Lib
import { iOVM_FraudVerifier } from "../../iOVM/verification/iOVM_FraudVerifier.sol"; import { iOVM_FraudVerifier } from "../../iOVM/verification/iOVM_FraudVerifier.sol";
import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitmentChain.sol"; import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitmentChain.sol";
import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol"; import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
import { iOVM_BondManager } from "../../iOVM/verification/iOVM_BondManager.sol";
/** /**
* @title OVM_StateCommitmentChain * @title OVM_StateCommitmentChain
...@@ -36,7 +38,7 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw ...@@ -36,7 +38,7 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw
Lib_RingBuffer.RingBuffer internal batches; Lib_RingBuffer.RingBuffer internal batches;
iOVM_CanonicalTransactionChain internal ovmCanonicalTransactionChain; iOVM_CanonicalTransactionChain internal ovmCanonicalTransactionChain;
iOVM_FraudVerifier internal ovmFraudVerifier; iOVM_FraudVerifier internal ovmFraudVerifier;
iOVM_BondManager internal ovmBondManager;
/*************** /***************
* Constructor * * Constructor *
...@@ -52,7 +54,8 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw ...@@ -52,7 +54,8 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw
{ {
ovmCanonicalTransactionChain = iOVM_CanonicalTransactionChain(resolve("OVM_CanonicalTransactionChain")); ovmCanonicalTransactionChain = iOVM_CanonicalTransactionChain(resolve("OVM_CanonicalTransactionChain"));
ovmFraudVerifier = iOVM_FraudVerifier(resolve("OVM_FraudVerifier")); ovmFraudVerifier = iOVM_FraudVerifier(resolve("OVM_FraudVerifier"));
ovmBondManager = iOVM_BondManager(resolve("OVM_BondManager"));
batches.init( batches.init(
16, 16,
Lib_OVMCodec.RING_BUFFER_SCC_BATCHES, Lib_OVMCodec.RING_BUFFER_SCC_BATCHES,
...@@ -69,7 +72,6 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw ...@@ -69,7 +72,6 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw
* @inheritdoc iOVM_StateCommitmentChain * @inheritdoc iOVM_StateCommitmentChain
*/ */
function getTotalElements() function getTotalElements()
virtual
override override
public public
view view
...@@ -103,6 +105,12 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw ...@@ -103,6 +105,12 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw
override override
public public
{ {
// Proposers must have previously staked at the BondManager
require(
ovmBondManager.isCollateralized(msg.sender),
"Proposer does not have enough collateral posted"
);
require( require(
_batch.length > 0, _batch.length > 0,
"Cannot submit an empty state batch." "Cannot submit an empty state batch."
...@@ -118,11 +126,11 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw ...@@ -118,11 +126,11 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw
elements[i] = abi.encodePacked(_batch[i]); elements[i] = abi.encodePacked(_batch[i]);
} }
// Pass the block's timestamp and the publisher of the data
// to be used in the fraud proofs
_appendBatch( _appendBatch(
elements, elements,
abi.encode( abi.encode(block.timestamp, msg.sender)
block.timestamp
)
); );
} }
...@@ -140,6 +148,11 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw ...@@ -140,6 +148,11 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw
"State batches can only be deleted by the OVM_FraudVerifier." "State batches can only be deleted by the OVM_FraudVerifier."
); );
require(
Lib_OVMCodec.hashBatchHeader(_batchHeader) == batches.get(uint32(_batchHeader.batchIndex)),
"Invalid batch header."
);
require( require(
insideFraudProofWindow(_batchHeader), insideFraudProofWindow(_batchHeader),
"State batches can only be deleted within the fraud proof window." "State batches can only be deleted within the fraud proof window."
...@@ -194,9 +207,9 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw ...@@ -194,9 +207,9 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, iRingBufferOverw
bool _inside bool _inside
) )
{ {
uint256 timestamp = abi.decode( (uint256 timestamp,) = abi.decode(
_batchHeader.extraData, _batchHeader.extraData,
(uint256) (uint256, address)
); );
require( require(
......
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
/* Library Imports */
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
/* Interface Imports */
import { iOVM_BondManager, Errors, ERC20 } from "../../iOVM/verification/iOVM_BondManager.sol";
import { iOVM_FraudVerifier } from "../../iOVM/verification/iOVM_FraudVerifier.sol";
/**
* @title OVM_BondManager
*/
contract OVM_BondManager is iOVM_BondManager, Lib_AddressResolver {
/****************************
* Constants and Parameters *
****************************/
/// The dispute period
uint256 public constant disputePeriodSeconds = 7 days;
/// The minimum collateral a sequencer must post
uint256 public requiredCollateral = 1 ether;
/// The maximum multiplier for updating the `requiredCollateral`
uint256 public constant MAX = 5;
/// Owner used to bump the security bond size
address immutable public owner;
/*******************************************
* Contract Variables: Contract References *
*******************************************/
/// The bond token
ERC20 immutable public token;
/// The fraud verifier contract, used to get data about transitioners for a pre-state root
address public ovmFraudVerifier;
/********************************************
* Contract Variables: Internal Accounting *
*******************************************/
/// The bonds posted by each proposer
mapping(address => Bond) public bonds;
/// For each pre-state root, there's an array of witnessProviders that must be rewarded
/// for posting witnesses
mapping(bytes32 => Rewards) public witnessProviders;
/***************
* Constructor *
***************/
/// Initializes with a ERC20 token to be used for the fidelity bonds
/// and with the Address Manager
constructor(ERC20 _token, address _libAddressManager)
Lib_AddressResolver(_libAddressManager)
{
owner = msg.sender;
token = _token;
ovmFraudVerifier = resolve("OVM_FraudVerifier");
}
/********************
* Public Functions *
********************/
/// Adds `who` to the list of witnessProviders for the provided `preStateRoot`.
function recordGasSpent(bytes32 _preStateRoot, address who, uint256 gasSpent) override public {
// The sender must be the transitioner that corresponds to the claimed pre-state root
address transitioner = address(iOVM_FraudVerifier(ovmFraudVerifier).getStateTransitioner(_preStateRoot));
require(transitioner == msg.sender, Errors.ONLY_TRANSITIONER);
witnessProviders[_preStateRoot].total += gasSpent;
witnessProviders[_preStateRoot].gasSpent[who] += gasSpent;
}
/// Slashes + distributes rewards or frees up the sequencer's bond, only called by
/// `FraudVerifier.finalizeFraudVerification`
function finalize(bytes32 _preStateRoot, uint256 batchIndex, address publisher, uint256 timestamp) override public {
require(msg.sender == ovmFraudVerifier, Errors.ONLY_FRAUD_VERIFIER);
require(witnessProviders[_preStateRoot].canClaim == false, Errors.ALREADY_FINALIZED);
// allow users to claim from that state root's
// pool of collateral (effectively slashing the sequencer)
witnessProviders[_preStateRoot].canClaim = true;
Bond storage bond = bonds[publisher];
// if the fraud proof's dispute period does not intersect with the
// withdrawal's timestamp, then the user should not be slashed
// e.g if a user at day 10 submits a withdrawal, and a fraud proof
// from day 1 gets published, the user won't be slashed since day 8 (1d + 7d)
// is before the user started their withdrawal. on the contrary, if the user
// had started their withdrawal at, say, day 6, they would be slashed
if (
bond.withdrawalTimestamp != 0 &&
uint256(bond.withdrawalTimestamp) > timestamp + disputePeriodSeconds &&
bond.state == State.WITHDRAWING
) {
return;
}
// slash!
bond.state = State.NOT_COLLATERALIZED;
}
/// Sequencers call this function to post collateral which will be used for
/// the `appendBatch` call
function deposit(uint256 amount) override public {
require(
token.transferFrom(msg.sender, address(this), amount),
Errors.ERC20_ERR
);
// This cannot overflow
bonds[msg.sender].state = State.COLLATERALIZED;
}
/// Starts the withdrawal for a publisher
function startWithdrawal() override public {
Bond storage bond = bonds[msg.sender];
require(bond.withdrawalTimestamp == 0, Errors.WITHDRAWAL_PENDING);
require(bond.state == State.COLLATERALIZED, Errors.WRONG_STATE);
bond.state = State.WITHDRAWING;
bond.withdrawalTimestamp = uint32(block.timestamp);
}
/// Finalizes a pending withdrawal from a publisher
function finalizeWithdrawal() override public {
Bond storage bond = bonds[msg.sender];
require(
block.timestamp >= uint256(bond.withdrawalTimestamp) + disputePeriodSeconds,
Errors.TOO_EARLY
);
require(bond.state == State.WITHDRAWING, Errors.SLASHED);
// refunds!
bond.state = State.NOT_COLLATERALIZED;
bond.withdrawalTimestamp = 0;
require(
token.transfer(msg.sender, requiredCollateral),
Errors.ERC20_ERR
);
}
/// Claims the user's reward for the witnesses they provided
function claim(bytes32 _preStateRoot) override public {
Rewards storage rewards = witnessProviders[_preStateRoot];
// only allow claiming if fraud was proven in `finalize`
require(rewards.canClaim, Errors.CANNOT_CLAIM);
// proportional allocation - only reward 50% (rest gets locked in the
// contract forever
uint256 amount = (requiredCollateral * rewards.gasSpent[msg.sender]) / (2 * rewards.total);
// reset the user's spent gas so they cannot double claim
rewards.gasSpent[msg.sender] = 0;
// transfer
require(token.transfer(msg.sender, amount), Errors.ERC20_ERR);
}
/// Sets the required collateral for posting a state root
/// Callable only by the contract's deployer.
function setRequiredCollateral(uint256 newValue) override public {
require(newValue > requiredCollateral, Errors.LOW_VALUE);
require(newValue < MAX * requiredCollateral, Errors.HIGH_VALUE);
require(msg.sender == owner, Errors.ONLY_OWNER);
requiredCollateral = newValue;
}
/// Checks if the user is collateralized for the batchIndex
function isCollateralized(address who) override public view returns (bool) {
return bonds[who].state == State.COLLATERALIZED;
}
/// Gets how many witnesses the user has provided for the state root
function getGasSpent(bytes32 preStateRoot, address who) override public view returns (uint256) {
return witnessProviders[preStateRoot].gasSpent[who];
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
import { iOVM_BondManager } from "../../iOVM/verification/iOVM_BondManager.sol";
/// Minimal contract to be inherited by contracts consumed by users that provide
/// data for fraud proofs
contract OVM_FraudContributor {
iOVM_BondManager internal ovmBondManager;
/// Decorate your functions with this modifier to store how much total gas was
/// consumed by the sender, to reward users fairly
modifier contributesToFraudProof(bytes32 preStateRoot) {
uint startGas = gasleft();
_;
uint gasSpent = startGas - gasleft();
ovmBondManager.recordGasSpent(preStateRoot, msg.sender, gasSpent);
}
}
...@@ -10,12 +10,16 @@ import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolve ...@@ -10,12 +10,16 @@ import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolve
import { iOVM_FraudVerifier } from "../../iOVM/verification/iOVM_FraudVerifier.sol"; import { iOVM_FraudVerifier } from "../../iOVM/verification/iOVM_FraudVerifier.sol";
import { iOVM_StateTransitioner } from "../../iOVM/verification/iOVM_StateTransitioner.sol"; import { iOVM_StateTransitioner } from "../../iOVM/verification/iOVM_StateTransitioner.sol";
import { iOVM_StateTransitionerFactory } from "../../iOVM/verification/iOVM_StateTransitionerFactory.sol"; import { iOVM_StateTransitionerFactory } from "../../iOVM/verification/iOVM_StateTransitionerFactory.sol";
import { iOVM_BondManager } from "../../iOVM/verification/iOVM_BondManager.sol";
import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol"; import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol";
import { iOVM_StateManagerFactory } from "../../iOVM/execution/iOVM_StateManagerFactory.sol"; import { iOVM_StateManagerFactory } from "../../iOVM/execution/iOVM_StateManagerFactory.sol";
import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitmentChain.sol"; import { iOVM_StateCommitmentChain } from "../../iOVM/chain/iOVM_StateCommitmentChain.sol";
import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol"; import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
contract OVM_FraudVerifier is iOVM_FraudVerifier, Lib_AddressResolver { /* Contract Imports */
import { OVM_FraudContributor } from "./OVM_FraudContributor.sol";
contract OVM_FraudVerifier is OVM_FraudContributor, iOVM_FraudVerifier, Lib_AddressResolver {
/******************************************* /*******************************************
* Contract Variables: Contract References * * Contract Variables: Contract References *
...@@ -46,6 +50,7 @@ contract OVM_FraudVerifier is iOVM_FraudVerifier, Lib_AddressResolver { ...@@ -46,6 +50,7 @@ contract OVM_FraudVerifier is iOVM_FraudVerifier, Lib_AddressResolver {
{ {
ovmStateCommitmentChain = iOVM_StateCommitmentChain(resolve("OVM_StateCommitmentChain")); ovmStateCommitmentChain = iOVM_StateCommitmentChain(resolve("OVM_StateCommitmentChain"));
ovmCanonicalTransactionChain = iOVM_CanonicalTransactionChain(resolve("OVM_CanonicalTransactionChain")); ovmCanonicalTransactionChain = iOVM_CanonicalTransactionChain(resolve("OVM_CanonicalTransactionChain"));
ovmBondManager = iOVM_BondManager(resolve("OVM_BondManager"));
} }
...@@ -97,6 +102,7 @@ contract OVM_FraudVerifier is iOVM_FraudVerifier, Lib_AddressResolver { ...@@ -97,6 +102,7 @@ contract OVM_FraudVerifier is iOVM_FraudVerifier, Lib_AddressResolver {
) )
override override
public public
contributesToFraudProof(_preStateRoot)
{ {
if (_hasStateTransitioner(_preStateRoot)) { if (_hasStateTransitioner(_preStateRoot)) {
return; return;
...@@ -150,6 +156,7 @@ contract OVM_FraudVerifier is iOVM_FraudVerifier, Lib_AddressResolver { ...@@ -150,6 +156,7 @@ contract OVM_FraudVerifier is iOVM_FraudVerifier, Lib_AddressResolver {
) )
override override
public public
contributesToFraudProof(_preStateRoot)
{ {
iOVM_StateTransitioner transitioner = transitioners[_preStateRoot]; iOVM_StateTransitioner transitioner = transitioners[_preStateRoot];
...@@ -181,14 +188,27 @@ contract OVM_FraudVerifier is iOVM_FraudVerifier, Lib_AddressResolver { ...@@ -181,14 +188,27 @@ contract OVM_FraudVerifier is iOVM_FraudVerifier, Lib_AddressResolver {
"Invalid post-state root inclusion proof." "Invalid post-state root inclusion proof."
); );
// If the post state root did not match, then there was fraud and we should delete the batch
require( require(
_postStateRoot != transitioner.getPostStateRoot(), _postStateRoot != transitioner.getPostStateRoot(),
"State transition has not been proven fraudulent." "State transition has not been proven fraudulent."
); );
// delete the state batch
ovmStateCommitmentChain.deleteStateBatch( ovmStateCommitmentChain.deleteStateBatch(
_postStateRootBatchHeader _postStateRootBatchHeader
); );
// Get the timestamp and publisher for that block
(uint256 timestamp, address publisher) = abi.decode(_postStateRootBatchHeader.extraData, (uint256, address));
// slash the bonds at the bond manager
ovmBondManager.finalize(
_preStateRoot,
_postStateRootBatchHeader.batchIndex,
publisher,
timestamp
);
} }
......
...@@ -10,17 +10,21 @@ import { Lib_SecureMerkleTrie } from "../../libraries/trie/Lib_SecureMerkleTrie. ...@@ -10,17 +10,21 @@ import { Lib_SecureMerkleTrie } from "../../libraries/trie/Lib_SecureMerkleTrie.
/* Interface Imports */ /* Interface Imports */
import { iOVM_StateTransitioner } from "../../iOVM/verification/iOVM_StateTransitioner.sol"; import { iOVM_StateTransitioner } from "../../iOVM/verification/iOVM_StateTransitioner.sol";
import { iOVM_BondManager } from "../../iOVM/verification/iOVM_BondManager.sol";
import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol"; import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol";
import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol"; import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
import { iOVM_StateManagerFactory } from "../../iOVM/execution/iOVM_StateManagerFactory.sol"; import { iOVM_StateManagerFactory } from "../../iOVM/execution/iOVM_StateManagerFactory.sol";
/* Contract Imports */
import { OVM_FraudContributor } from "./OVM_FraudContributor.sol";
/* Logging Imports */ /* Logging Imports */
import { console } from "@nomiclabs/buidler/console.sol"; import { console } from "@nomiclabs/buidler/console.sol";
/** /**
* @title OVM_StateTransitioner * @title OVM_StateTransitioner
*/ */
contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { contract OVM_StateTransitioner is OVM_FraudContributor, iOVM_StateTransitioner, Lib_AddressResolver {
/******************* /*******************
* Data Structures * * Data Structures *
...@@ -77,6 +81,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -77,6 +81,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
ovmExecutionManager = iOVM_ExecutionManager(resolve("OVM_ExecutionManager")); ovmExecutionManager = iOVM_ExecutionManager(resolve("OVM_ExecutionManager"));
ovmStateManager = iOVM_StateManagerFactory(resolve("OVM_StateManagerFactory")).create(address(this)); ovmStateManager = iOVM_StateManagerFactory(resolve("OVM_StateManagerFactory")).create(address(this));
ovmBondManager = iOVM_BondManager(resolve("OVM_BondManager"));
} }
...@@ -168,6 +173,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -168,6 +173,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
override override
public public
onlyDuringPhase(TransitionPhase.PRE_EXECUTION) onlyDuringPhase(TransitionPhase.PRE_EXECUTION)
contributesToFraudProof(preStateRoot)
{ {
// Exit quickly to avoid unnecessary work. // Exit quickly to avoid unnecessary work.
require( require(
...@@ -215,6 +221,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -215,6 +221,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
override override
public public
onlyDuringPhase(TransitionPhase.PRE_EXECUTION) onlyDuringPhase(TransitionPhase.PRE_EXECUTION)
contributesToFraudProof(preStateRoot)
{ {
// Exit quickly to avoid unnecessary work. // Exit quickly to avoid unnecessary work.
require( require(
...@@ -250,6 +257,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -250,6 +257,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
override override
public public
onlyDuringPhase(TransitionPhase.PRE_EXECUTION) onlyDuringPhase(TransitionPhase.PRE_EXECUTION)
contributesToFraudProof(preStateRoot)
{ {
// Exit quickly to avoid unnecessary work. // Exit quickly to avoid unnecessary work.
require( require(
...@@ -305,6 +313,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -305,6 +313,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
override override
public public
onlyDuringPhase(TransitionPhase.PRE_EXECUTION) onlyDuringPhase(TransitionPhase.PRE_EXECUTION)
contributesToFraudProof(preStateRoot)
{ {
require( require(
Lib_OVMCodec.hashTransaction(_transaction) == transactionHash, Lib_OVMCodec.hashTransaction(_transaction) == transactionHash,
...@@ -341,6 +350,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -341,6 +350,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
override override
public public
onlyDuringPhase(TransitionPhase.POST_EXECUTION) onlyDuringPhase(TransitionPhase.POST_EXECUTION)
contributesToFraudProof(preStateRoot)
{ {
require( require(
ovmStateManager.commitAccount(_ovmContractAddress) == true, ovmStateManager.commitAccount(_ovmContractAddress) == true,
...@@ -375,6 +385,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -375,6 +385,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
override override
public public
onlyDuringPhase(TransitionPhase.POST_EXECUTION) onlyDuringPhase(TransitionPhase.POST_EXECUTION)
contributesToFraudProof(preStateRoot)
{ {
require( require(
ovmStateManager.commitContractStorage(_ovmContractAddress, _key) == true, ovmStateManager.commitContractStorage(_ovmContractAddress, _key) == true,
......
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
interface ERC20 {
function transfer(address, uint256) external returns (bool);
function transferFrom(address, address, uint256) external returns (bool);
}
/// All the errors which may be encountered on the bond manager
library Errors {
string constant ERC20_ERR = "BondManager: Could not post bond";
string constant LOW_VALUE = "BondManager: New collateral value must be greater than the previous one";
string constant HIGH_VALUE = "BondManager: New collateral value cannot be more than 5x of the previous one";
string constant ALREADY_FINALIZED = "BondManager: Fraud proof for this pre-state root has already been finalized";
string constant SLASHED = "BondManager: Cannot finalize withdrawal, you probably got slashed";
string constant WRONG_STATE = "BondManager: Wrong bond state for proposer";
string constant CANNOT_CLAIM = "BondManager: Cannot claim yet. Dispute must be finalized first";
string constant WITHDRAWAL_PENDING = "BondManager: Withdrawal already pending";
string constant TOO_EARLY = "BondManager: Too early to finalize your withdrawal";
string constant ONLY_OWNER = "BondManager: Only the contract's owner can call this function";
string constant ONLY_TRANSITIONER = "BondManager: Only the transitioner for this pre-state root may call this function";
string constant ONLY_FRAUD_VERIFIER = "BondManager: Only the fraud verifier may call this function";
string constant ONLY_STATE_COMMITMENT_CHAIN = "BondManager: Only the state commitment chain may call this function";
}
/**
* @title iOVM_BondManager
*/
interface iOVM_BondManager {
/*******************
* Data Structures *
*******************/
/// The lifecycle of a proposer's bond
enum State {
// Before depositing or after getting slashed, a user is uncollateralized
NOT_COLLATERALIZED,
// After depositing, a user is collateralized
COLLATERALIZED,
// After a user has initiated a withdrawal
WITHDRAWING
}
/// A bond posted by a proposer
struct Bond {
// The user's state
State state;
// The timestamp at which a proposer issued their withdrawal request
uint32 withdrawalTimestamp;
}
// Per pre-state root, store the number of state provisions that were made
// and how many of these calls were made by each user. Payouts will then be
// claimed by users proportionally for that dispute.
struct Rewards {
// Flag to check if rewards for a fraud proof are claimable
bool canClaim;
// Total number of `recordGasSpent` calls made
uint256 total;
// The gas spent by each user to provide witness data. The sum of all
// values inside this map MUST be equal to the value of `total`
mapping(address => uint256) gasSpent;
}
/********************
* Public Functions *
********************/
function recordGasSpent(
bytes32 _preStateRoot,
address _who,
uint256 _gasSpent
) external;
function finalize(
bytes32 _preStateRoot,
uint256 _batchIndex,
address _publisher,
uint256 _timestamp
) external;
function deposit(
uint256 _amount
) external;
function startWithdrawal() external;
function finalizeWithdrawal() external;
function claim(
bytes32 _preStateRoot
) external;
function setRequiredCollateral(
uint256 _newValue
) external;
function isCollateralized(
address _who
) external view returns (bool);
function getGasSpent(
bytes32 _preStateRoot,
address _who
) external view returns (uint256);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
import { OVM_BondManager } from "./../optimistic-ethereum/OVM/verification/OVM_BondManager.sol";
contract Mock_FraudVerifier {
OVM_BondManager bondManager;
mapping (bytes32 => address) transitioners;
function setBondManager(OVM_BondManager _bondManager) public {
bondManager = _bondManager;
}
function setStateTransitioner(bytes32 preStateRoot, address addr) public {
transitioners[preStateRoot] = addr;
}
function getStateTransitioner(bytes32 preStateRoot) public view returns (address) {
return transitioners[preStateRoot];
}
function finalize(bytes32 _preStateRoot, uint256 batchIndex, address publisher, uint256 timestamp) public {
bondManager.finalize(_preStateRoot, batchIndex, publisher, timestamp);
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
// a test ERC20 token with an open mint function
contract TestERC20 {
using SafeMath for uint;
string public constant name = 'Test';
string public constant symbol = 'TST';
uint8 public constant decimals = 18;
uint public totalSupply;
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
constructor() public {}
function mint(address to, uint value) public {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _approve(address owner, address spender, uint value) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(address from, address to, uint value) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint value) external returns (bool) {
if (allowance[from][msg.sender] != uint(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
}
library SafeMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, 'ds-math-add-overflow');
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x, 'ds-math-sub-underflow');
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
}
}
This diff is collapsed.
...@@ -29,6 +29,7 @@ describe('OVM_StateCommitmentChain', () => { ...@@ -29,6 +29,7 @@ describe('OVM_StateCommitmentChain', () => {
}) })
let Mock__OVM_CanonicalTransactionChain: MockContract let Mock__OVM_CanonicalTransactionChain: MockContract
let Mock__OVM_BondManager: MockContract
before(async () => { before(async () => {
Mock__OVM_CanonicalTransactionChain = smockit( Mock__OVM_CanonicalTransactionChain = smockit(
await ethers.getContractFactory('OVM_CanonicalTransactionChain') await ethers.getContractFactory('OVM_CanonicalTransactionChain')
...@@ -39,6 +40,18 @@ describe('OVM_StateCommitmentChain', () => { ...@@ -39,6 +40,18 @@ describe('OVM_StateCommitmentChain', () => {
'OVM_CanonicalTransactionChain', 'OVM_CanonicalTransactionChain',
Mock__OVM_CanonicalTransactionChain Mock__OVM_CanonicalTransactionChain
) )
Mock__OVM_BondManager = smockit(
await ethers.getContractFactory('OVM_BondManager')
)
await setProxyTarget(
AddressManager,
'OVM_BondManager',
Mock__OVM_BondManager
)
Mock__OVM_BondManager.smocked.isCollateralized.will.return.with(true)
}) })
let Factory__OVM_StateCommitmentChain: ContractFactory let Factory__OVM_StateCommitmentChain: ContractFactory
...@@ -116,8 +129,8 @@ describe('OVM_StateCommitmentChain', () => { ...@@ -116,8 +129,8 @@ describe('OVM_StateCommitmentChain', () => {
) )
await OVM_StateCommitmentChain.appendStateBatch(batch) await OVM_StateCommitmentChain.appendStateBatch(batch)
batchHeader.extraData = defaultAbiCoder.encode( batchHeader.extraData = defaultAbiCoder.encode(
['uint256'], ['uint256', 'address'],
[await getEthTime(ethers.provider)] [await getEthTime(ethers.provider), await signer.getAddress()]
) )
}) })
...@@ -150,7 +163,7 @@ describe('OVM_StateCommitmentChain', () => { ...@@ -150,7 +163,7 @@ describe('OVM_StateCommitmentChain', () => {
...batchHeader, ...batchHeader,
batchIndex: 1, batchIndex: 1,
}) })
).to.be.revertedWith('Invalid batch index.') ).to.be.revertedWith('Index out of bounds.')
}) })
}) })
......
...@@ -36,6 +36,7 @@ describe('OVM_FraudVerifier', () => { ...@@ -36,6 +36,7 @@ describe('OVM_FraudVerifier', () => {
let Mock__OVM_CanonicalTransactionChain: MockContract let Mock__OVM_CanonicalTransactionChain: MockContract
let Mock__OVM_StateTransitioner: MockContract let Mock__OVM_StateTransitioner: MockContract
let Mock__OVM_StateTransitionerFactory: MockContract let Mock__OVM_StateTransitionerFactory: MockContract
let Mock__OVM_BondManager: MockContract
before(async () => { before(async () => {
Mock__OVM_StateCommitmentChain = smockit( Mock__OVM_StateCommitmentChain = smockit(
await ethers.getContractFactory('OVM_StateCommitmentChain') await ethers.getContractFactory('OVM_StateCommitmentChain')
...@@ -52,6 +53,9 @@ describe('OVM_FraudVerifier', () => { ...@@ -52,6 +53,9 @@ describe('OVM_FraudVerifier', () => {
Mock__OVM_StateTransitionerFactory = smockit( Mock__OVM_StateTransitionerFactory = smockit(
await ethers.getContractFactory('OVM_StateTransitionerFactory') await ethers.getContractFactory('OVM_StateTransitionerFactory')
) )
Mock__OVM_BondManager = smockit(
await ethers.getContractFactory('OVM_BondManager')
)
await setProxyTarget( await setProxyTarget(
AddressManager, AddressManager,
...@@ -71,6 +75,12 @@ describe('OVM_FraudVerifier', () => { ...@@ -71,6 +75,12 @@ describe('OVM_FraudVerifier', () => {
Mock__OVM_StateTransitionerFactory Mock__OVM_StateTransitionerFactory
) )
await setProxyTarget(
AddressManager,
'OVM_BondManager',
Mock__OVM_BondManager
)
Mock__OVM_StateTransitionerFactory.smocked.create.will.return.with( Mock__OVM_StateTransitionerFactory.smocked.create.will.return.with(
Mock__OVM_StateTransitioner.address Mock__OVM_StateTransitioner.address
) )
......
...@@ -33,6 +33,7 @@ describe('OVM_StateTransitioner', () => { ...@@ -33,6 +33,7 @@ describe('OVM_StateTransitioner', () => {
let Mock__OVM_ExecutionManager: MockContract let Mock__OVM_ExecutionManager: MockContract
let Mock__OVM_StateManagerFactory: MockContract let Mock__OVM_StateManagerFactory: MockContract
let Mock__OVM_StateManager: MockContract let Mock__OVM_StateManager: MockContract
let Mock__OVM_BondManager: MockContract
before(async () => { before(async () => {
Mock__OVM_ExecutionManager = smockit( Mock__OVM_ExecutionManager = smockit(
await ethers.getContractFactory('OVM_ExecutionManager') await ethers.getContractFactory('OVM_ExecutionManager')
...@@ -43,6 +44,16 @@ describe('OVM_StateTransitioner', () => { ...@@ -43,6 +44,16 @@ describe('OVM_StateTransitioner', () => {
Mock__OVM_StateManager = smockit( Mock__OVM_StateManager = smockit(
await ethers.getContractFactory('OVM_StateManager') await ethers.getContractFactory('OVM_StateManager')
) )
Mock__OVM_BondManager = smockit(
await ethers.getContractFactory('OVM_BondManager')
)
await setProxyTarget(
AddressManager,
'OVM_BondManager',
Mock__OVM_BondManager
)
Mock__OVM_BondManager.smocked.recordGasSpent.will.return()
await setProxyTarget( await setProxyTarget(
AddressManager, AddressManager,
......
import { NULL_BYTES32 } from '../constants' import { NULL_BYTES32, NON_ZERO_ADDRESS } from '../constants'
import { ethers } from '@nomiclabs/buidler'
export const DUMMY_BATCH_HEADERS = [ export const DUMMY_BATCH_HEADERS = [
{ {
...@@ -6,7 +7,10 @@ export const DUMMY_BATCH_HEADERS = [ ...@@ -6,7 +7,10 @@ export const DUMMY_BATCH_HEADERS = [
batchRoot: NULL_BYTES32, batchRoot: NULL_BYTES32,
batchSize: 0, batchSize: 0,
prevTotalElements: 0, prevTotalElements: 0,
extraData: NULL_BYTES32, extraData: ethers.utils.defaultAbiCoder.encode(
['uint256', 'address'],
[NULL_BYTES32, NON_ZERO_ADDRESS]
),
}, },
] ]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment