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.
186 lines
6.4 KiB
186 lines
6.4 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";
|
||
4 years ago
|
import {IMessageRecipient} from "../interfaces/IMessageRecipient.sol";
|
||
3 years ago
|
// ============ External Imports ============
|
||
|
import {TypedMemView} from "@summa-tx/memview-sol/contracts/TypedMemView.sol";
|
||
4 years ago
|
|
||
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
|
*/
|
||
3 years ago
|
contract Inbox is Version0, Common {
|
||
3 years ago
|
// ============ Libraries ============
|
||
|
|
||
4 years ago
|
using MerkleLib for MerkleLib.Tree;
|
||
|
using TypedMemView for bytes;
|
||
|
using TypedMemView for bytes29;
|
||
|
using Message for bytes29;
|
||
4 years ago
|
|
||
3 years ago
|
// ============ Enums ============
|
||
|
|
||
|
// Status of Message:
|
||
|
// 0 - None - message has not been proven or processed
|
||
|
// 1 - Proven - message inclusion proof has been validated
|
||
|
// 2 - Processed - message has been dispatched to recipient
|
||
3 years ago
|
enum MessageStatus {
|
||
|
None,
|
||
3 years ago
|
Proven,
|
||
3 years ago
|
Processed
|
||
|
}
|
||
|
|
||
3 years ago
|
// ============ Public Storage ============
|
||
4 years ago
|
|
||
3 years ago
|
// Domain of outbox chain
|
||
3 years ago
|
uint32 public remoteDomain;
|
||
|
// re-entrancy guard
|
||
|
uint8 private entered;
|
||
|
// 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[47] 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
|
* @param messageHash Hash of message that failed to process
|
||
|
*/
|
||
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) Common(_localDomain) {}
|
||
3 years ago
|
|
||
|
// ============ Initializer ============
|
||
3 years ago
|
|
||
4 years ago
|
function initialize(
|
||
4 years ago
|
uint32 _remoteDomain,
|
||
3 years ago
|
address _validatorManager,
|
||
|
bytes32 _checkpointedRoot,
|
||
|
uint256 _checkpointedIndex
|
||
4 years ago
|
) public initializer {
|
||
3 years ago
|
__Common_initialize(_validatorManager);
|
||
3 years ago
|
entered = 1;
|
||
|
remoteDomain = _remoteDomain;
|
||
3 years ago
|
_checkpoint(_checkpointedRoot, _checkpointedIndex);
|
||
4 years ago
|
}
|
||
|
|
||
3 years ago
|
// ============ External Functions ============
|
||
|
|
||
3 years ago
|
/**
|
||
3 years ago
|
* @notice Checkpoints the provided root and index given a signature.
|
||
|
* @dev Reverts if checkpoints's index is not greater than our latest index.
|
||
|
* @param _root Checkpoint's merkle root
|
||
|
* @param _index Checkpoint's index
|
||
|
* @param _signature Validator's signature on `_root` and `_index`
|
||
3 years ago
|
*/
|
||
3 years ago
|
function checkpoint(
|
||
|
bytes32 _root,
|
||
|
uint256 _index,
|
||
4 years ago
|
bytes memory _signature
|
||
3 years ago
|
) external {
|
||
|
// ensure that update is more recent than the latest we've seen
|
||
|
require(_index > checkpoints[checkpointedRoot], "old checkpoint");
|
||
|
// validate validator signature
|
||
4 years ago
|
require(
|
||
3 years ago
|
validatorManager.isValidatorSignature(
|
||
|
remoteDomain,
|
||
|
_root,
|
||
|
_index,
|
||
|
_signature
|
||
|
),
|
||
|
"!validator sig"
|
||
4 years ago
|
);
|
||
3 years ago
|
_checkpoint(_root, _index);
|
||
4 years ago
|
}
|
||
|
|
||
4 years ago
|
/**
|
||
|
* @notice First attempts to prove the validity of provided formatted
|
||
|
* `message`. If the message is successfully proven, then tries to process
|
||
|
* message.
|
||
|
* @dev Reverts if `prove` call returns false
|
||
4 years ago
|
* @param _message Formatted message (refer to Common.sol Message library)
|
||
|
* @param _proof Merkle proof of inclusion for message's leaf
|
||
3 years ago
|
* @param _index Index of leaf in outbox's merkle tree
|
||
3 years ago
|
*/
|
||
4 years ago
|
function proveAndProcess(
|
||
4 years ago
|
bytes memory _message,
|
||
|
bytes32[32] calldata _proof,
|
||
|
uint256 _index
|
||
4 years ago
|
) external {
|
||
4 years ago
|
require(prove(keccak256(_message), _proof, _index), "!prove");
|
||
|
process(_message);
|
||
4 years ago
|
}
|
||
|
|
||
3 years ago
|
// ============ Public Functions ============
|
||
|
|
||
4 years ago
|
/**
|
||
3 years ago
|
* @notice Given formatted message, attempts to dispatch
|
||
|
* message payload to end recipient.
|
||
|
* @dev Recipient must implement a `handle` method (refer to IMessageRecipient.sol)
|
||
3 years ago
|
* Reverts if formatted message's destination domain is not the Inbox's domain,
|
||
3 years ago
|
* if message has not been proven, or if the dispatch transaction fails.
|
||
3 years ago
|
* @param _message Formatted message
|
||
|
*/
|
||
3 years ago
|
function process(bytes memory _message) public {
|
||
4 years ago
|
bytes29 _m = _message.ref(0);
|
||
3 years ago
|
// ensure message was meant for this domain
|
||
4 years ago
|
require(_m.destination() == localDomain, "!destination");
|
||
3 years ago
|
// ensure message has been proven
|
||
|
bytes32 _messageHash = _m.keccak();
|
||
|
require(messages[_messageHash] == MessageStatus.Proven, "!proven");
|
||
|
// check re-entrancy guard
|
||
3 years ago
|
require(entered == 1, "!reentrant");
|
||
|
entered = 0;
|
||
3 years ago
|
// update message status as processed
|
||
3 years ago
|
messages[_messageHash] = MessageStatus.Processed;
|
||
3 years ago
|
IMessageRecipient _recipient = IMessageRecipient(_m.recipientAddress());
|
||
|
_recipient.handle(_m.origin(), _m.sender(), _m.body().clone());
|
||
3 years ago
|
// emit process results
|
||
3 years ago
|
emit Process(_messageHash);
|
||
3 years ago
|
// reset re-entrancy guard
|
||
3 years ago
|
entered = 1;
|
||
4 years ago
|
}
|
||
|
|
||
4 years ago
|
/**
|
||
|
* @notice Attempts to prove the validity of message given its leaf, the
|
||
|
* merkle proof of inclusion for the leaf, and the index of the leaf.
|
||
|
* @dev Reverts if message's MessageStatus != None (i.e. if message was
|
||
|
* already proven or processed)
|
||
3 years ago
|
* @dev For convenience, we allow proving against any previous root.
|
||
|
* This means that witnesses never need to be updated for the new root
|
||
4 years ago
|
* @param _leaf Leaf of message to prove
|
||
|
* @param _proof Merkle proof of inclusion for leaf
|
||
3 years ago
|
* @param _index Index of leaf in outbox's merkle tree
|
||
4 years ago
|
* @return Returns true if proof was valid and `prove` call succeeded
|
||
|
**/
|
||
4 years ago
|
function prove(
|
||
4 years ago
|
bytes32 _leaf,
|
||
|
bytes32[32] calldata _proof,
|
||
|
uint256 _index
|
||
4 years ago
|
) public returns (bool) {
|
||
3 years ago
|
// ensure that message has not been proven or processed
|
||
4 years ago
|
require(messages[_leaf] == MessageStatus.None, "!MessageStatus.None");
|
||
3 years ago
|
// calculate the expected root based on the proof
|
||
|
bytes32 _calculatedRoot = MerkleLib.branchRoot(_leaf, _proof, _index);
|
||
|
// if the root is valid, change status to Proven
|
||
3 years ago
|
if (checkpoints[_calculatedRoot] > 0) {
|
||
3 years ago
|
messages[_leaf] = MessageStatus.Proven;
|
||
4 years ago
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|