The home for Hyperlane core contracts, sdk packages, and other infrastructure
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.
hyperlane-monorepo/solidity/optics-core/contracts/Common.sol

145 lines
4.5 KiB

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
import "./Queue.sol";
import "../libs/Message.sol";
import "@openzeppelin/contracts/cryptography/ECDSA.sol";
/**
* @title Common
* @author Celo Labs Inc.
* @notice Shared utilities between Home and Replica.
**/
abstract contract Common is QueueManager {
enum States {
UNINITIALIZED,
ACTIVE,
FAILED
}
/// @notice Domain of owning contract
uint32 public immutable localDomain;
/// @notice Address of bonded updater
address public updater;
/// @notice Current state of contract
States public state;
/// @notice Current root
bytes32 public current;
// gap for upgrade safety
uint256[47] private __GAP;
/**
* @notice Event emitted when update is made on Home or unconfirmed update
* root is enqueued on Replica
* @param homeDomain Domain of home contract
* @param oldRoot Old merkle root
* @param newRoot New merkle root
* @param signature Updater's signature on `oldRoot` and `newRoot`
**/
event Update(
uint32 indexed homeDomain,
bytes32 indexed oldRoot,
bytes32 indexed newRoot,
bytes signature
);
/**
* @notice Event emitted when valid double update proof is provided to
* contract
* @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]
**/
event DoubleUpdate(
bytes32 oldRoot,
bytes32[2] newRoot,
bytes signature,
bytes signature2
);
constructor(uint32 _localDomain) {
localDomain = _localDomain;
}
function __Common_initialize(address _updater) internal initializer {
__QueueManager_intialize();
updater = _updater;
state = States.ACTIVE;
}
/// @notice Ensures that contract state != FAILED
modifier notFailed() {
require(state != States.FAILED, "failed state");
_;
}
/**
* @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]
**/
function doubleUpdate(
bytes32 _oldRoot,
bytes32[2] calldata _newRoot,
bytes calldata _signature,
bytes calldata _signature2
) external notFailed {
if (
Common._isUpdaterSignature(_oldRoot, _newRoot[0], _signature) &&
Common._isUpdaterSignature(_oldRoot, _newRoot[1], _signature2) &&
_newRoot[0] != _newRoot[1]
) {
_fail();
emit DoubleUpdate(_oldRoot, _newRoot, _signature, _signature2);
}
}
/// @notice Hash of Home domain concatenated with "OPTICS"
function homeDomainHash() public view virtual returns (bytes32);
/// @notice Hash of Home's domain concatenated with "OPTICS"
function _homeDomainHash(uint32 homeDomain)
internal
test: cross chain governance (#312) * fix: OpticsIdentifier as_ref casts ethereum address conditionally * feature: adds GovernanceRouter test boilerplate and fixes ConnectionManager test setup * test: adds testProcess and revert message utility * test: adds test for handle revert with unenrolled replica * test: adds test for reverting in handle on nonGovernorRouter message * rename: formattedMessage --> opticsMessage * prog: blocked on incorrect setting of governorDomain = localDomain * fix: fix after domainHash rebase * test: adds success case transfer governor test * test: adds setRouter message success case * prog: Call message success case failing due to datalen mismatches * prog: storing in dynamic struct array reverts silently * add: initial setup * add: transfer governorship test * add: signUpdate * refactor: combine bridgerouter tests * fix: cast to address, set sequence * delete: old gov router tests * Fix transfer governor test * fix: debug call storage, get sequence * fix: bad merge rust code * revert: stale changes * refactor: nits, create thirdDomain/thirdRouter vars * refactor: extract some code into formatOpticsMessage * refactor: formatOpticsMessage * refactor: deployOptics and devDeployOptics * fix: bug, clean up code * lint * fix: add numCalls (#315) * fix: initial stab at adding numCalls * debugging: numCall type conversion * fix: read _numCalls from bytes29 * use MSG_PREFIX_LEN * clean: remove unused imports * fix: data bug, refactor a bit * add: Transaction reverted silently * fix: bug in formatCalls * refactor: formatCalls * add: check ret value for testProcess from GovernorRouter * enhance: more explicit naming * rename: BYTE_LEN to NUM_ITEMS * slow down turbo * enhance: assign _numCalls variable Co-authored-by: Luke Tchang <ltchang@stanford.edu> Co-authored-by: anna-caroll <anna.s.carroll@gmail.com>
4 years ago
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(homeDomain, "OPTICS"));
}
/// @notice Sets contract state to FAILED
function _setFailed() internal {
state = States.FAILED;
}
/// @notice Called when a double update or fraudulent update is detected
function _fail() internal virtual;
/**
* @notice Called internally. Checks that signature is valid (belongs to
* updater).
* @param _oldRoot Old merkle root
* @param _newRoot New merkle root
* @param _signature Signature on `_oldRoot` and `_newRoot`
* @return Returns true if signature is valid and false if otherwise
**/
function _isUpdaterSignature(
bytes32 _oldRoot,
bytes32 _newRoot,
bytes memory _signature
) internal view returns (bool) {
bytes32 _digest = keccak256(
abi.encodePacked(homeDomainHash(), _oldRoot, _newRoot)
);
_digest = ECDSA.toEthSignedMessageHash(_digest);
return (ECDSA.recover(_digest, _signature) == updater);
}
}