You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
6.2 KiB
204 lines
6.2 KiB
4 years ago
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||
|
pragma solidity >=0.6.11;
|
||
|
|
||
3 years ago
|
// ============ Internal Imports ============
|
||
|
import {Message} from "../libs/Message.sol";
|
||
|
// ============ External Imports ============
|
||
|
import {ECDSA} from "@openzeppelin/contracts/cryptography/ECDSA.sol";
|
||
3 years ago
|
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
|
||
4 years ago
|
|
||
4 years ago
|
/**
|
||
|
* @title Common
|
||
|
* @author Celo Labs Inc.
|
||
|
* @notice Shared utilities between Home and Replica.
|
||
3 years ago
|
*/
|
||
3 years ago
|
abstract contract Common is Initializable {
|
||
3 years ago
|
// ============ Enums ============
|
||
|
|
||
|
// States:
|
||
3 years ago
|
// 0 - UnInitialized - before initialize function is called
|
||
3 years ago
|
// note: the contract is initialized at deploy time, so it should never be in this state
|
||
3 years ago
|
// 1 - Active - as long as the contract has not become fraudulent
|
||
|
// 2 - Failed - after a valid fraud proof has been submitted;
|
||
3 years ago
|
// contract will no longer accept updates or new messages
|
||
3 years ago
|
enum States {
|
||
3 years ago
|
UnInitialized,
|
||
|
Active,
|
||
|
Failed
|
||
3 years ago
|
}
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Immutable Variables ============
|
||
|
|
||
|
// Domain of chain on which the contract is deployed
|
||
4 years ago
|
uint32 public immutable localDomain;
|
||
3 years ago
|
|
||
|
// ============ Public Variables ============
|
||
|
|
||
|
// Address of bonded Updater
|
||
4 years ago
|
address public updater;
|
||
3 years ago
|
// Current state of contract
|
||
4 years ago
|
States public state;
|
||
3 years ago
|
// The latest root that has been signed by the Updater
|
||
3 years ago
|
bytes32 public committedRoot;
|
||
3 years ago
|
|
||
|
// ============ Upgrade Gap ============
|
||
|
|
||
3 years ago
|
// gap for upgrade safety
|
||
|
uint256[47] private __GAP;
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Events ============
|
||
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @notice Emitted when update is made on Home
|
||
|
* or unconfirmed update root is submitted on Replica
|
||
4 years ago
|
* @param homeDomain Domain of home contract
|
||
4 years ago
|
* @param oldRoot Old merkle root
|
||
|
* @param newRoot New merkle root
|
||
|
* @param signature Updater's signature on `oldRoot` and `newRoot`
|
||
3 years ago
|
*/
|
||
4 years ago
|
event Update(
|
||
4 years ago
|
uint32 indexed homeDomain,
|
||
4 years ago
|
bytes32 indexed oldRoot,
|
||
|
bytes32 indexed newRoot,
|
||
4 years ago
|
bytes signature
|
||
|
);
|
||
4 years ago
|
|
||
|
/**
|
||
3 years ago
|
* @notice Emitted when proof of a double update is submitted,
|
||
|
* which sets the contract to FAILED state
|
||
4 years ago
|
* @param oldRoot Old root shared between two conflicting updates
|
||
|
* @param newRoot Array containing two conflicting new roots
|
||
|
* @param signature Signature on `oldRoot` and `newRoot`[0]
|
||
|
* @param signature2 Signature on `oldRoot` and `newRoot`[1]
|
||
3 years ago
|
*/
|
||
4 years ago
|
event DoubleUpdate(
|
||
4 years ago
|
bytes32 oldRoot,
|
||
|
bytes32[2] newRoot,
|
||
|
bytes signature,
|
||
|
bytes signature2
|
||
4 years ago
|
);
|
||
|
|
||
3 years ago
|
/**
|
||
|
* @notice Emitted when Updater is rotated
|
||
|
* @param updater The address of the new updater
|
||
|
*/
|
||
|
event NewUpdater(address updater);
|
||
|
|
||
3 years ago
|
// ============ Modifiers ============
|
||
|
|
||
|
/**
|
||
|
* @notice Ensures that contract state != FAILED when the function is called
|
||
|
*/
|
||
|
modifier notFailed() {
|
||
3 years ago
|
require(state != States.Failed, "failed state");
|
||
3 years ago
|
_;
|
||
|
}
|
||
|
|
||
|
// ============ Constructor ============
|
||
|
|
||
4 years ago
|
constructor(uint32 _localDomain) {
|
||
|
localDomain = _localDomain;
|
||
|
}
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Initializer ============
|
||
|
|
||
3 years ago
|
function __Common_initialize(address _updater) internal initializer {
|
||
4 years ago
|
updater = _updater;
|
||
3 years ago
|
state = States.Active;
|
||
4 years ago
|
}
|
||
|
|
||
3 years ago
|
// ============ External Functions ============
|
||
4 years ago
|
|
||
4 years ago
|
/**
|
||
|
* @notice Called by external agent. Checks that signatures on two sets of
|
||
|
* roots are valid and that the new roots conflict with each other. If both
|
||
|
* cases hold true, the contract is failed and a `DoubleUpdate` event is
|
||
|
* emitted.
|
||
|
* @dev When `fail()` is called on Home, updater is slashed.
|
||
|
* @param _oldRoot Old root shared between two conflicting updates
|
||
|
* @param _newRoot Array containing two conflicting new roots
|
||
|
* @param _signature Signature on `_oldRoot` and `_newRoot`[0]
|
||
|
* @param _signature2 Signature on `_oldRoot` and `_newRoot`[1]
|
||
3 years ago
|
*/
|
||
4 years ago
|
function doubleUpdate(
|
||
4 years ago
|
bytes32 _oldRoot,
|
||
4 years ago
|
bytes32[2] calldata _newRoot,
|
||
4 years ago
|
bytes calldata _signature,
|
||
|
bytes calldata _signature2
|
||
|
) external notFailed {
|
||
|
if (
|
||
4 years ago
|
Common._isUpdaterSignature(_oldRoot, _newRoot[0], _signature) &&
|
||
|
Common._isUpdaterSignature(_oldRoot, _newRoot[1], _signature2) &&
|
||
3 years ago
|
_newRoot[0] != _newRoot[1]
|
||
4 years ago
|
) {
|
||
4 years ago
|
_fail();
|
||
4 years ago
|
emit DoubleUpdate(_oldRoot, _newRoot, _signature, _signature2);
|
||
|
}
|
||
|
}
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Public Functions ============
|
||
|
|
||
|
/**
|
||
|
* @notice Hash of Home domain concatenated with "OPTICS"
|
||
|
*/
|
||
4 years ago
|
function homeDomainHash() public view virtual returns (bytes32);
|
||
|
|
||
3 years ago
|
// ============ Internal Functions ============
|
||
|
|
||
|
/**
|
||
|
* @notice Hash of Home domain concatenated with "OPTICS"
|
||
|
* @param _homeDomain the Home domain to hash
|
||
|
*/
|
||
|
function _homeDomainHash(uint32 _homeDomain)
|
||
4 years ago
|
internal
|
||
4 years ago
|
pure
|
||
4 years ago
|
returns (bytes32)
|
||
|
{
|
||
3 years ago
|
return keccak256(abi.encodePacked(_homeDomain, "OPTICS"));
|
||
4 years ago
|
}
|
||
4 years ago
|
|
||
3 years ago
|
/**
|
||
|
* @notice Set contract state to FAILED
|
||
|
* @dev Called when a valid fraud proof is submitted
|
||
|
*/
|
||
4 years ago
|
function _setFailed() internal {
|
||
3 years ago
|
state = States.Failed;
|
||
4 years ago
|
}
|
||
|
|
||
3 years ago
|
/**
|
||
3 years ago
|
* @notice Moves the contract into failed state
|
||
|
* @dev Called when fraud is proven
|
||
|
* (Double Update is submitted on Home or Replica,
|
||
|
* or Improper Update is submitted on Home)
|
||
3 years ago
|
*/
|
||
4 years ago
|
function _fail() internal virtual;
|
||
4 years ago
|
|
||
|
/**
|
||
3 years ago
|
* @notice Checks that signature was signed by Updater
|
||
4 years ago
|
* @param _oldRoot Old merkle root
|
||
|
* @param _newRoot New merkle root
|
||
|
* @param _signature Signature on `_oldRoot` and `_newRoot`
|
||
3 years ago
|
* @return TRUE iff signature is valid signed by updater
|
||
4 years ago
|
**/
|
||
4 years ago
|
function _isUpdaterSignature(
|
||
4 years ago
|
bytes32 _oldRoot,
|
||
|
bytes32 _newRoot,
|
||
|
bytes memory _signature
|
||
|
) internal view returns (bool) {
|
||
3 years ago
|
bytes32 _digest = keccak256(
|
||
|
abi.encodePacked(homeDomainHash(), _oldRoot, _newRoot)
|
||
|
);
|
||
4 years ago
|
_digest = ECDSA.toEthSignedMessageHash(_digest);
|
||
4 years ago
|
return (ECDSA.recover(_digest, _signature) == updater);
|
||
4 years ago
|
}
|
||
3 years ago
|
|
||
|
/**
|
||
3 years ago
|
* @notice Set the Updater
|
||
|
* @param _updater Address of the Updater
|
||
|
*/
|
||
|
function _setUpdater(address _updater) internal {
|
||
|
updater = _updater;
|
||
|
emit NewUpdater(_updater);
|
||
3 years ago
|
}
|
||
4 years ago
|
}
|