Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

L1<>L2 basic contracts - Inbox, outbox, message bridge #540

Merged
merged 8 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@
"*.macros": "cpp",
"*.tpp": "cpp"
},
"solidity.compileUsingRemoteVersion": "v0.6.10+commit.00c0fcaf",
"solidity.compileUsingRemoteVersion": "v0.8.18",
"solidity.formatter": "forge",
"search.exclude": {
"**/.yarn": true,
"**/.yalc": true,
Expand Down
9 changes: 5 additions & 4 deletions l1-contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ solc = "0.8.18"

remappings = [
"@oz/=lib/openzeppelin-contracts/contracts/",
"@aztec3/core/=src/core/",
"@aztec3/periphery/=src/periphery/",
"@aztec3/mock/=src/mock/",
"@aztec3/verifier/=lib/aztec-verifier-contracts/src/"
"@aztec/core/=src/core/",
"@aztec/interfaces/=src/core/interfaces/",
"@aztec/periphery/=src/periphery/",
"@aztec/mock/=src/mock/",
"@aztec/verifier/=lib/aztec-verifier-contracts/src/"
]

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright 2023 Aztec Labs.
pragma solidity >=0.8.18;

import {MockVerifier} from "@aztec3/mock/MockVerifier.sol";
import {MockVerifier} from "@aztec/mock/MockVerifier.sol";
import {Decoder} from "./Decoder.sol";

/**
Expand Down
7 changes: 7 additions & 0 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Aztec Labs.
pragma solidity >=0.8.18;

interface IRollup {
function process(bytes memory _proof, bytes calldata _l2Block) external;
}
90 changes: 90 additions & 0 deletions l1-contracts/src/core/interfaces/messagebridge/IInbox.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Aztec Labs.
pragma solidity >=0.8.18;

import {IMessageBox} from "./IMessageBox.sol";

/**
* @title Inbox
* @author Aztec Labs
* @notice Lives on L1 and is used to pass messages into the rollup, e.g., L1 -> L2 messages.
*/
interface IInbox is IMessageBox {
/**
* @dev struct for sending messages from L1 to L2
* @param sender - The sender of the message
* @param recipient - The recipient of the message
* @param content - The content of the message (application specific) padded to bytes32 or hashed if larger.
* @param secretHash - The secret hash of the message (make it possible to hide when a specific message is consumed on L2)
* @param deadline - The deadline to consume a message. Only after it, can a message be cancalled.
* @param fee - The fee provided to sequencer for including the entry
*/
struct L1ToL2Msg {
L1Actor sender;
L2Actor recipient;
bytes32 content;
bytes32 secretHash;
uint32 deadline;
uint64 fee;
}

event MessageAdded(
bytes32 indexed entryKey,
address indexed sender,
bytes32 indexed recipient,
uint256 senderChainId,
uint256 recipientVersion,
uint32 deadline,
uint64 fee,
bytes32 content
);

event L1ToL2MessageCancelled(bytes32 indexed entryKey);

/// @notice Given a message, computes an entry key for the Inbox
function computeMessageKey(L1ToL2Msg memory message) external pure returns (bytes32);

/**
* @notice Inserts an entry into the Inbox
* @dev Will emit `MessageAdded` with data for easy access by the sequencer
* @dev msg.value - The fee provided to sequencer for including the entry
* @param _recipient - The recipient of the entry
* @param _deadline - The deadline to consume a message. Only after it, can a message be cancalled.
* @param _content - The content of the entry (application specific)
* @param _secretHash - The secret hash of the entry (make it possible to hide when a specific entry is consumed on L2)
* @return The key of the entry in the set
*/
function sendL2Message(
L2Actor memory _recipient,
uint32 _deadline,
bytes32 _content,
bytes32 _secretHash
) external payable returns (bytes32);

/**
* @notice Cancel a pending L2 message
* @dev Will revert if the deadline have not been crossed - message only cancellable past the deadline
* so it cannot be yanked away while the sequencer is building a block including it
* @dev Must be called by portal that inserted the entry
* @param _message - The content of the entry (application specific)
* @param _feeCollector - The address to receive the "fee"
* @return entryKey - The key of the entry removed
*/
function cancelL2Message(L1ToL2Msg memory _message, address _feeCollector)
external
returns (bytes32 entryKey);

/**
* @notice Batch consumes entries from the Inbox
* @dev Only callable by the rollup contract
* @dev Will revert if the message is already past deadline
* @param entryKeys - Array of entry keys (hash of the messages)
* @param _feeCollector - The address to receive the "fee"
*/
function batchConsume(bytes32[] memory entryKeys, address _feeCollector) external;

/**
* @notice Withdraws fees accrued by the sequencer
*/
function withdrawFees() external;
}
48 changes: 48 additions & 0 deletions l1-contracts/src/core/interfaces/messagebridge/IMessageBox.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Aztec Labs.
pragma solidity >=0.8.18;

/**
* @title IMessageBox
* @author Aztec Labs
* @notice Data structure used in both Inbox and Outbox for keeping track of entries
* Implements a multi-set storing the multiplicity (count for easy reading) at the entry.
*/
interface IMessageBox {
/// @dev Actor on L1. ChainID if multiple L1s tap into the same Aztec instance.
struct L1Actor {
LHerskind marked this conversation as resolved.
Show resolved Hide resolved
address actor;
uint256 chainId;
}

/// @dev Actor on L2. `version` specifies which Aztec instance the actor is on (useful for upgrades)
struct L2Actor {
LHerskind marked this conversation as resolved.
Show resolved Hide resolved
bytes32 actor;
uint256 version;
}

/**
* @dev Entry struct - Done as struct to easily support extensions if needed
* @param count - The occurrence of the entry in the dataset
* @param fee - The fee provided to sequencer for including in the inbox. 0 if Oubox (as not applicable).
*/
struct Entry {
uint64 count;
uint64 fee;
uint32 deadline;
}

/**
* @notice Fetch an entry
* @param _entryKey - The key to lookup
* @return The entry matching the provided key
*/
function get(bytes32 _entryKey) external view returns (Entry memory);

/**
* @notice Check if entry exists
* @param _entryKey - The key to lookup
* @return True if entry exists, false otherwise
*/
function contains(bytes32 _entryKey) external view returns (bool);
}
53 changes: 53 additions & 0 deletions l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Aztec Labs.
pragma solidity >=0.8.18;

import {IMessageBox} from "./IMessageBox.sol";

/**
* @title IOutbox
* @author Aztec Labs
* @notice Lives on L1 and is used to consume L2 -> L1 messages. Messages are inserted by the rollup contract
* and will be consumed by the portal contracts.
*/
interface IOutbox is IMessageBox {
/**
* @dev struct for sending messages from L2 to L1
* @param sender - The sender of the message
* @param recipient - The recipient of the message
* @param content - The content of the message (application specific) padded to bytes32 or hashed if larger.
*/
struct L2ToL1Msg {
L2Actor sender;
L1Actor recipient;
bytes32 content;
}

// to make it easier for portal to know when to consume the message.
event MessageAdded(bytes32 indexed entryKey);

event MessageConsumed(bytes32 indexed entryKey, address indexed recipient);

/**
* @notice Computes an entry key for the Outbox
* @param _message - The L2 to L1 message
* @return The key of the entry in the set
*/
function computeEntryKey(L2ToL1Msg memory _message) external returns (bytes32);

/**
* @notice Inserts an array of entries into the Outbox
* @dev Only callable by the rollup contract
* @param _entryKey - Array of entry keys (hash of the message) - computed by the L2 counterpart and sent to L1 via rollup block
*/
function sendL1Messages(bytes32[] memory _entryKey) external;

/**
* @notice Consumes an entry from the Outbox
* @dev Only meaningfully callable by portals, otherwise should never hit an entry
* @dev Emits the `MessageConsumed` event when consuming messages
* @param _message - The L2 to L1 message
* @return entryKey - The key of the entry removed
*/
function consume(L2ToL1Msg memory _message) external returns (bytes32 entryKey);
}
22 changes: 22 additions & 0 deletions l1-contracts/src/core/interfaces/messagebridge/IRegistryReader.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.18;

import {IRollup} from "@aztec/interfaces/IRollup.sol";
import {IInbox} from "@aztec/interfaces/messagebridge/IInbox.sol";
import {IOutbox} from "@aztec/interfaces/messagebridge/IOutbox.sol";

interface IRegistryReader {
struct L1L2Addresses {
address rollup;
address inbox;
address outbox;
}

function getL1L2Addresses() external view returns (L1L2Addresses memory);

function getRollupAddress() external view returns (IRollup);

function getInboxAddress() external view returns (IInbox);

function getOutboxAddress() external view returns (IOutbox);
}
139 changes: 139 additions & 0 deletions l1-contracts/src/core/messagebridge/Inbox.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2023 Aztec Labs.
pragma solidity >=0.8.18;

import {IInbox} from "@aztec/interfaces/messagebridge/IInbox.sol";
import {MessageBox} from "./MessageBox.sol";

/**
* @title Inbox
* @author Aztec Labs
* @notice Lives on L1 and is used to pass messages into the rollup, e.g., L1 -> L2 messages.
*/
contract Inbox is MessageBox, IInbox {
error Inbox__DeadlineBeforeNow();
error Inbox__NotPastDeadline();
error Inbox__PastDeadline();
error Inbox__Unauthorized();
error Inbox__FailedToWithdrawFees();

mapping(address account => uint256 balance) public feesAccrued;

constructor(address _registry) MessageBox(_registry) {}

/**
* @notice Given a message, computes an entry key for the Inbox
* @param message - The L1 to L2 message
* @return The hash of the message (used as the key of the entry in the set)
*/
function computeMessageKey(L1ToL2Msg memory message) public pure returns (bytes32) {
rahul-kothari marked this conversation as resolved.
Show resolved Hide resolved
return bytes32(
uint256(
sha256(
abi.encode(
message.sender,
message.recipient,
message.content,
message.secretHash,
message.deadline,
message.fee
)
)
) % P // TODO: Replace mod P later on when we have a better idea of how to handle Fields.
);
}

/**
* @notice Inserts an entry into the Inbox
* @dev Will emit `MessageAdded` with data for easy access by the sequencer
* @dev msg.value - The fee provided to sequencer for including the entry
* @param _recipient - The recipient of the entry
* @param _deadline - The deadline to consume a message. Only after it, can a message be cancalled.
* @param _content - The content of the entry (application specific)
* @param _secretHash - The secret hash of the entry (make it possible to hide when a specific entry is consumed on L2)
* @return The key of the entry in the set
*/
function sendL2Message(
L2Actor memory _recipient,
uint32 _deadline,
bytes32 _content,
bytes32 _secretHash
) external payable returns (bytes32) {
if (_deadline <= block.timestamp) revert Inbox__DeadlineBeforeNow();
uint64 fee = uint64(msg.value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cast is unsafe, if paying more than 2**64 wei, some will simply be lost. If this is desired approach, add a note why.

L1ToL2Msg memory message = L1ToL2Msg({
sender: L1Actor(msg.sender, block.chainid),
recipient: _recipient,
content: _content,
secretHash: _secretHash,
deadline: _deadline,
fee: fee
});

bytes32 key = computeMessageKey(message);
_insert(key, fee, _deadline);

emit MessageAdded(
key,
message.sender.actor,
message.recipient.actor,
message.sender.chainId,
message.recipient.version,
message.deadline,
message.fee,
message.content
);

return key;
}

/**
* @notice Cancel a pending L2 message
* @dev Will revert if the deadline have not been crossed - message only cancellable past the deadline
* so it cannot be yanked away while the sequencer is building a block including it
* @dev Must be called by portal that inserted the entry
* @param _message - The content of the entry (application specific)
* @param _feeCollector - The address to receive the "fee"
* @return entryKey - The key of the entry removed
*/
function cancelL2Message(L1ToL2Msg memory _message, address _feeCollector)
rahul-kothari marked this conversation as resolved.
Show resolved Hide resolved
external
returns (bytes32 entryKey)
{
if (msg.sender != _message.sender.actor) revert Inbox__Unauthorized();
if (_message.deadline <= block.timestamp) revert Inbox__NotPastDeadline();
entryKey = computeMessageKey(_message);
_consume(entryKey);
feesAccrued[_feeCollector] += _message.fee;
emit L1ToL2MessageCancelled(entryKey);
}

/**
* @notice Batch consumes entries from the Inbox
* @dev Only callable by the rollup contract
* @dev Will revert if the message is already past deadline
* @param entryKeys - Array of entry keys (hash of the messages)
* @param _feeCollector - The address to receive the "fee"
*/
function batchConsume(bytes32[] memory entryKeys, address _feeCollector) external onlyRollup {
uint256 totalFee = 0;
for (uint256 i = 0; i < entryKeys.length; i++) {
// TODO: Combine these to optimise for gas.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this todo still active? Or is this referring to the storage packing?

Entry memory entry = get(entryKeys[i]);
if (entry.deadline > block.timestamp) revert Inbox__PastDeadline();
rahul-kothari marked this conversation as resolved.
Show resolved Hide resolved
_consume(entryKeys[i]);
totalFee += entry.fee;
}
feesAccrued[_feeCollector] += totalFee;
}

/**
* @notice Withdraws fees accrued by the sequencer
*/
function withdrawFees() external {
uint256 balance = feesAccrued[msg.sender];
feesAccrued[msg.sender] = 0;
(bool success,) = msg.sender.call{value: balance}("");
if (!success) revert Inbox__FailedToWithdrawFees();
}
}
Loading