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.
149 lines
5.0 KiB
149 lines
5.0 KiB
4 years ago
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||
3 years ago
|
pragma solidity >=0.8.0;
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Internal Imports ============
|
||
2 years ago
|
import {Versioned} from "./upgrade/Versioned.sol";
|
||
3 years ago
|
import {Mailbox} from "./Mailbox.sol";
|
||
2 years ago
|
import {MerkleLib} from "./libs/Merkle.sol";
|
||
|
import {Message} from "./libs/Message.sol";
|
||
|
import {TypeCasts} from "./libs/TypeCasts.sol";
|
||
4 years ago
|
import {IMessageRecipient} from "../interfaces/IMessageRecipient.sol";
|
||
3 years ago
|
import {IInbox} from "../interfaces/IInbox.sol";
|
||
3 years ago
|
|
||
3 years ago
|
// ============ External Imports ============
|
||
|
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
|
||
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @title Inbox
|
||
4 years ago
|
* @author Celo Labs Inc.
|
||
3 years ago
|
* @notice Track root updates on Outbox, prove and dispatch messages to end
|
||
|
* recipients.
|
||
4 years ago
|
*/
|
||
2 years ago
|
contract Inbox is IInbox, ReentrancyGuardUpgradeable, Versioned, Mailbox {
|
||
3 years ago
|
// ============ Libraries ============
|
||
|
|
||
4 years ago
|
using MerkleLib for MerkleLib.Tree;
|
||
3 years ago
|
using Message for bytes;
|
||
|
using TypeCasts for bytes32;
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Enums ============
|
||
|
|
||
|
// Status of Message:
|
||
3 years ago
|
// 0 - None - message has not been processed
|
||
|
// 1 - Processed - message has been dispatched to recipient
|
||
3 years ago
|
enum MessageStatus {
|
||
|
None,
|
||
|
Processed
|
||
|
}
|
||
|
|
||
3 years ago
|
// ============ Public Storage ============
|
||
4 years ago
|
|
||
3 years ago
|
// Domain of outbox chain
|
||
3 years ago
|
uint32 public override remoteDomain;
|
||
3 years ago
|
// Mapping of message leaves to MessageStatus
|
||
|
mapping(bytes32 => MessageStatus) public messages;
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Upgrade Gap ============
|
||
3 years ago
|
|
||
3 years ago
|
// gap for upgrade safety
|
||
3 years ago
|
uint256[48] private __GAP;
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Events ============
|
||
3 years ago
|
|
||
3 years ago
|
/**
|
||
3 years ago
|
* @notice Emitted when message is processed
|
||
3 years ago
|
* @dev This event allows watchers to observe the merkle proof they need
|
||
|
* to prove fraud on the Outbox.
|
||
|
* @param messageHash Hash of message that was processed.
|
||
3 years ago
|
*/
|
||
3 years ago
|
event Process(bytes32 indexed messageHash);
|
||
3 years ago
|
|
||
|
// ============ Constructor ============
|
||
|
|
||
|
// solhint-disable-next-line no-empty-blocks
|
||
3 years ago
|
constructor(uint32 _localDomain) Mailbox(_localDomain) {}
|
||
3 years ago
|
|
||
|
// ============ Initializer ============
|
||
3 years ago
|
|
||
3 years ago
|
function initialize(uint32 _remoteDomain, address _validatorManager)
|
||
2 years ago
|
external
|
||
3 years ago
|
initializer
|
||
|
{
|
||
3 years ago
|
__ReentrancyGuard_init();
|
||
3 years ago
|
__Mailbox_initialize(_validatorManager);
|
||
3 years ago
|
remoteDomain = _remoteDomain;
|
||
4 years ago
|
}
|
||
|
|
||
3 years ago
|
// ============ External Functions ============
|
||
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @notice Attempts to process the provided formatted `message`. Performs
|
||
|
* verification against root of the proof
|
||
3 years ago
|
* @dev Called by the validator manager, which is responsible for verifying a
|
||
|
* quorum of validator signatures on the checkpoint.
|
||
3 years ago
|
* @dev Reverts if verification of the message fails.
|
||
3 years ago
|
* @param _root The merkle root of the checkpoint used to prove message inclusion.
|
||
|
* @param _index The index of the checkpoint used to prove message inclusion.
|
||
3 years ago
|
* @param _message Formatted message (refer to Mailbox.sol Message library)
|
||
4 years ago
|
* @param _proof Merkle proof of inclusion for message's leaf
|
||
3 years ago
|
* @param _leafIndex Index of leaf in outbox's merkle tree
|
||
3 years ago
|
*/
|
||
3 years ago
|
function process(
|
||
3 years ago
|
bytes32 _root,
|
||
|
uint256 _index,
|
||
3 years ago
|
bytes calldata _message,
|
||
4 years ago
|
bytes32[32] calldata _proof,
|
||
3 years ago
|
uint256 _leafIndex
|
||
|
) external override nonReentrant onlyValidatorManager {
|
||
3 years ago
|
require(_index >= _leafIndex, "!index");
|
||
3 years ago
|
bytes32 _messageHash = _message.leaf(_leafIndex);
|
||
3 years ago
|
// ensure that message has not been processed
|
||
3 years ago
|
require(
|
||
|
messages[_messageHash] == MessageStatus.None,
|
||
|
"!MessageStatus.None"
|
||
|
);
|
||
3 years ago
|
// calculate the expected root based on the proof
|
||
|
bytes32 _calculatedRoot = MerkleLib.branchRoot(
|
||
|
_messageHash,
|
||
|
_proof,
|
||
3 years ago
|
_leafIndex
|
||
3 years ago
|
);
|
||
3 years ago
|
// verify the merkle proof
|
||
3 years ago
|
require(_calculatedRoot == _root, "!proof");
|
||
3 years ago
|
_process(_message, _messageHash);
|
||
4 years ago
|
}
|
||
|
|
||
3 years ago
|
// ============ Internal Functions ============
|
||
3 years ago
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @notice Marks a message as processed and calls handle on the recipient
|
||
|
* @dev Internal function that can be called by contracts like TestInbox
|
||
3 years ago
|
* @param _message Formatted message (refer to Mailbox.sol Message library)
|
||
3 years ago
|
* @param _messageHash keccak256 hash of the message
|
||
3 years ago
|
*/
|
||
3 years ago
|
function _process(bytes calldata _message, bytes32 _messageHash) internal {
|
||
3 years ago
|
(
|
||
|
uint32 origin,
|
||
|
bytes32 sender,
|
||
|
uint32 destination,
|
||
|
bytes32 recipient,
|
||
|
bytes calldata body
|
||
|
) = _message.destructure();
|
||
|
|
||
2 years ago
|
// ensure message came from the correct domain
|
||
|
require(origin == remoteDomain, "!origin");
|
||
3 years ago
|
// ensure message was meant for this domain
|
||
3 years ago
|
require(destination == localDomain, "!destination");
|
||
3 years ago
|
|
||
3 years ago
|
// update message status as processed
|
||
3 years ago
|
messages[_messageHash] = MessageStatus.Processed;
|
||
3 years ago
|
|
||
|
IMessageRecipient(recipient.bytes32ToAddress()).handle(
|
||
|
origin,
|
||
|
sender,
|
||
|
body
|
||
|
);
|
||
2 years ago
|
emit Process(_messageHash);
|
||
4 years ago
|
}
|
||
|
}
|