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.
192 lines
6.3 KiB
192 lines
6.3 KiB
4 years ago
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||
|
pragma solidity >=0.6.11;
|
||
|
|
||
3 years ago
|
// ============ Internal Imports ============
|
||
|
import {Version0} from "./Version0.sol";
|
||
|
import {Common} from "./Common.sol";
|
||
|
import {MerkleLib} from "../libs/Merkle.sol";
|
||
|
import {Message} from "../libs/Message.sol";
|
||
|
import {MerkleTreeManager} from "./Merkle.sol";
|
||
4 years ago
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @title Outbox
|
||
4 years ago
|
* @author Celo Labs Inc.
|
||
3 years ago
|
* @notice Accepts messages to be dispatched to remote chains,
|
||
|
* constructs a Merkle tree of the messages,
|
||
3 years ago
|
* and accepts signatures from a bonded Validator
|
||
3 years ago
|
* which notarize the Merkle tree roots.
|
||
|
* Accepts submissions of fraudulent signatures
|
||
3 years ago
|
* by the Validator and slashes the Validator in this case.
|
||
4 years ago
|
*/
|
||
3 years ago
|
contract Outbox is Version0, MerkleTreeManager, Common {
|
||
3 years ago
|
// ============ Libraries ============
|
||
|
|
||
4 years ago
|
using MerkleLib for MerkleLib.Tree;
|
||
|
|
||
3 years ago
|
// ============ Constants ============
|
||
|
|
||
|
// Maximum bytes per message = 2 KiB
|
||
|
// (somewhat arbitrarily set to begin)
|
||
4 years ago
|
uint256 public constant MAX_MESSAGE_BODY_BYTES = 2 * 2**10;
|
||
|
|
||
3 years ago
|
// ============ Enums ============
|
||
|
|
||
|
// States:
|
||
|
// 0 - UnInitialized - before initialize function is called
|
||
|
// note: the contract is initialized at deploy time, so it should never be in this state
|
||
|
// 1 - Active - as long as the contract has not become fraudulent
|
||
|
// 2 - Failed - after a valid fraud proof has been submitted;
|
||
|
// contract will no longer accept updates or new messages
|
||
|
enum States {
|
||
|
UnInitialized,
|
||
|
Active,
|
||
|
Failed
|
||
|
}
|
||
|
|
||
3 years ago
|
// ============ Public Storage Variables ============
|
||
4 years ago
|
|
||
3 years ago
|
// Current state of contract
|
||
|
States public state;
|
||
3 years ago
|
// domain => next available nonce for the domain
|
||
|
mapping(uint32 => uint32) public nonces;
|
||
3 years ago
|
|
||
3 years ago
|
// ============ Upgrade Gap ============
|
||
|
|
||
|
// gap for upgrade safety
|
||
|
uint256[48] private __GAP;
|
||
|
|
||
|
// ============ Events ============
|
||
4 years ago
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @notice Emitted when a new message is dispatched via Abacus
|
||
3 years ago
|
* @param messageHash Hash of message; the leaf inserted to the Merkle tree for the message
|
||
4 years ago
|
* @param leafIndex Index of message's leaf in merkle tree
|
||
3 years ago
|
* @param destinationAndNonce Destination and destination-specific
|
||
|
* nonce combined in single field ((destination << 32) & nonce)
|
||
3 years ago
|
* @param checkpointedRoot the latest checkpointed root
|
||
3 years ago
|
* @param message Raw bytes of message
|
||
4 years ago
|
*/
|
||
4 years ago
|
event Dispatch(
|
||
3 years ago
|
bytes32 indexed messageHash,
|
||
4 years ago
|
uint256 indexed leafIndex,
|
||
3 years ago
|
uint64 indexed destinationAndNonce,
|
||
3 years ago
|
// Remove checkpointedRoot.
|
||
|
bytes32 checkpointedRoot,
|
||
4 years ago
|
bytes message
|
||
|
);
|
||
4 years ago
|
|
||
3 years ago
|
event Fail();
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Constructor ============
|
||
4 years ago
|
|
||
4 years ago
|
constructor(uint32 _localDomain) Common(_localDomain) {} // solhint-disable-line no-empty-blocks
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Initializer ============
|
||
|
|
||
3 years ago
|
function initialize(address _validatorManager) public initializer {
|
||
|
__Common_initialize(_validatorManager);
|
||
|
state = States.Active;
|
||
4 years ago
|
}
|
||
|
|
||
3 years ago
|
// ============ Modifiers ============
|
||
|
|
||
|
/**
|
||
3 years ago
|
* @notice Ensures that contract state != FAILED when the function is called
|
||
3 years ago
|
*/
|
||
3 years ago
|
modifier notFailed() {
|
||
|
require(state != States.Failed, "failed state");
|
||
4 years ago
|
_;
|
||
|
}
|
||
|
|
||
3 years ago
|
/**
|
||
3 years ago
|
* @notice Ensures that function is called by the ValidatorManager contract
|
||
3 years ago
|
*/
|
||
3 years ago
|
modifier onlyValidatorManager() {
|
||
|
require(msg.sender == address(validatorManager), "!validatorManager");
|
||
|
_;
|
||
4 years ago
|
}
|
||
|
|
||
3 years ago
|
// ============ External Functions ============
|
||
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @notice Dispatch the message it to the destination domain & recipient
|
||
|
* @dev Format the message, insert its hash into Merkle tree,
|
||
3 years ago
|
* and emit `Dispatch` event with message information.
|
||
3 years ago
|
* @param _destinationDomain Domain of destination chain
|
||
|
* @param _recipientAddress Address of recipient on destination chain as bytes32
|
||
|
* @param _messageBody Raw bytes content of message
|
||
4 years ago
|
*/
|
||
3 years ago
|
function dispatch(
|
||
3 years ago
|
uint32 _destinationDomain,
|
||
|
bytes32 _recipientAddress,
|
||
|
bytes memory _messageBody
|
||
4 years ago
|
) external notFailed {
|
||
3 years ago
|
require(_messageBody.length <= MAX_MESSAGE_BODY_BYTES, "msg too long");
|
||
3 years ago
|
// get the next nonce for the destination domain, then increment it
|
||
|
uint32 _nonce = nonces[_destinationDomain];
|
||
|
nonces[_destinationDomain] = _nonce + 1;
|
||
3 years ago
|
// format the message into packed bytes
|
||
3 years ago
|
bytes memory _message = Message.formatMessage(
|
||
|
localDomain,
|
||
|
bytes32(uint256(uint160(msg.sender))),
|
||
3 years ago
|
_nonce,
|
||
3 years ago
|
_destinationDomain,
|
||
|
_recipientAddress,
|
||
|
_messageBody
|
||
3 years ago
|
);
|
||
3 years ago
|
// insert the hashed message into the Merkle tree
|
||
|
bytes32 _messageHash = keccak256(_message);
|
||
|
tree.insert(_messageHash);
|
||
|
// Emit Dispatch event with message information
|
||
|
// note: leafIndex is count() - 1 since new leaf has already been inserted
|
||
4 years ago
|
emit Dispatch(
|
||
3 years ago
|
_messageHash,
|
||
3 years ago
|
count() - 1,
|
||
|
_destinationAndNonce(_destinationDomain, _nonce),
|
||
3 years ago
|
checkpointedRoot,
|
||
4 years ago
|
_message
|
||
|
);
|
||
4 years ago
|
}
|
||
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @notice Checkpoints the latest root and index.
|
||
|
* Validators are expected to sign this checkpoint so that it can be
|
||
3 years ago
|
* relayed to the Inbox contracts.
|
||
3 years ago
|
* @dev emits Checkpoint event
|
||
4 years ago
|
*/
|
||
3 years ago
|
function checkpoint() external notFailed {
|
||
|
uint256 count = count();
|
||
|
require(count > 0, "!count");
|
||
|
bytes32 root = root();
|
||
|
_checkpoint(root, count);
|
||
4 years ago
|
}
|
||
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @notice Set contract state to FAILED.
|
||
|
* @dev Called by the ValidatorManager when fraud is proven.
|
||
4 years ago
|
*/
|
||
3 years ago
|
function fail() external onlyValidatorManager {
|
||
|
// set contract to FAILED
|
||
|
state = States.Failed;
|
||
|
emit Fail();
|
||
4 years ago
|
}
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Internal Functions ============
|
||
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @notice Internal utility function that combines
|
||
3 years ago
|
* `_destination` and `_nonce`.
|
||
|
* @dev Both destination and nonce should be less than 2^32 - 1
|
||
4 years ago
|
* @param _destination Domain of destination chain
|
||
3 years ago
|
* @param _nonce Current nonce for given destination chain
|
||
|
* @return Returns (`_destination` << 32) & `_nonce`
|
||
4 years ago
|
*/
|
||
3 years ago
|
function _destinationAndNonce(uint32 _destination, uint32 _nonce)
|
||
4 years ago
|
internal
|
||
|
pure
|
||
|
returns (uint64)
|
||
4 years ago
|
{
|
||
3 years ago
|
return (uint64(_destination) << 32) | _nonce;
|
||
4 years ago
|
}
|
||
4 years ago
|
}
|