Cross layer communication

This section describes the communication mechanism used to ensure trustworthy communications between L1 and L2. It lays the foundation for high-level application protocols like token bridges.

Merkle Mountain Ranges (MMR)

Merkle Mountain Ranges (MMR) are an alternative to Merkle trees. Same as Merkle trees, their leaves are data hashes and parent nodes are the hashes of their two children. MMR is strictly append-only, and consist of a list of perfectly balanced binary trees. Comparing with Merkle trees, this kind of structure is more convenient for incremental construction, and therefore suitable for situations where not all leaf nodes are decided at the beginning.

Goshen employs MMR to store cross layer messages sent between L1 and L2, and MMR proof is used to verify the existence of sent message on the target chain.

Send cross layer messages

Cross layer messages is stored in CrossLayerWitness system contract, deployed on both L1 and L2 chain. Contracts index the messages automatically to distinguish them from application layer messages with the same content. Witness contract provide the following method to send cross layer messages:

interface ICrossLayerWitness {
    /**
     * @dev Send cross layer message
     * @param _target call target address on the receiver chain
     * @param _message EVM call data
     */
    function sendMessage(address _target, bytes calldata _message) external;
    ...
}

When called, Witness contract will assign an index (starting from 0) to this message, and use the following function to calculate the message hash and insert it into the MMR.

function crossLayerMessageHash(
    address _target,
    address _sender,
    uint64 _messageIndex,
    bytes memory _message
) internal pure returns (bytes32) {
    // @notice we encode _messageIndex as uint256 to let the total encoded data size > 64byte
    // so when appended in MMR, it can be distinguished from the inner node.
    return keccak256(abi.encodePacked(_target, _sender, uint256(_messageIndex), _message));
}

Relay cross layer messages

When cross layer messages is sent from the source chain, a relay transaction must be sent to the target chain to deliver that message. Anyone has the permission to relay cross layer message and pay the transaction fee.

Relay L1 -> L2 messages

Relaying L1 to L2 messages will be triggered automatically. When L1CrossLayerWitness.sendMessage is called, Witness contract will generate a relay transaction with gas limit set to 3000000, and append it to the pending transaction queue of RollupInputBatch contract. The relay transaction will be included in rollup batch by Sequencer. If the execution of this transaction on L2 is reverted because of out of gas or rejected by the message target contract, user can replay this message manually.

Relay L2 -> L1 messages

When L2CrossLayerWitness.sendMessage is called, the contract will append the messsage hash to the MMR, then the MMR size and root will be set in L2 block's nonce and mixHash field. The proposer will submit the block hash as L2 state to L1. When the challenge period has passed, the L2 state committed by the proposer is finalized. User can relay the message with MMR proof and L2 block header.

Receive cross layer messages

When the witness contract invoked by relay transaction receives the cross layer message, it will check the MMR proof and then invoke the target. Witness contract provide the following method to query the message sender:

Last updated