Skip to content

Commit

Permalink
update MCR to include an acceptor role (#713)
Browse files Browse the repository at this point in the history
  • Loading branch information
apenzk authored Feb 21, 2025
1 parent 0ab2b6f commit 13f8eb6
Show file tree
Hide file tree
Showing 15 changed files with 935 additions and 443 deletions.
2 changes: 1 addition & 1 deletion protocol-units/settlement/mcr/client/abis/MCR.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions protocol-units/settlement/mcr/client/src/eth_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ pub enum McrEthConnectorError {
SendTransactionError(#[from] alloy_contract::Error),
#[error("MCR Settlement Transaction send failed during its execution :{0}")]
RpcTransactionExecution(String),
#[error("MCR Settlement BlockAccepted event notification error :{0}")]
#[error("MCR Settlement SuperBlockPostconfirmed event notification error :{0}")]
EventNotificationError(#[from] alloy_sol_types::Error),
#[error("MCR Settlement BlockAccepted event notification stream close")]
#[error("MCR Settlement SuperBlockPostconfirmed event notification stream close")]
EventNotificationStreamClosed,
}

Expand Down Expand Up @@ -284,7 +284,7 @@ where
// Register to contract BlockCommitmentSubmitted event

let contract = MCR::new(self.contract_address, &self.ws_provider);
let event_filter = contract.BlockAccepted_filter().watch().await?;
let event_filter = contract.SuperBlockPostconfirmed_filter().watch().await?;

let stream = event_filter.into_stream().map(|event| {
event
Expand All @@ -310,8 +310,8 @@ where
height: u64,
) -> Result<Option<SuperBlockCommitment>, anyhow::Error> {
let contract = MCR::new(self.contract_address, &self.ws_provider);
let MCR::getAcceptedCommitmentAtSuperBlockHeightReturn { _0: commitment } =
contract.getAcceptedCommitmentAtSuperBlockHeight(U256::from(height)).call().await?;
let MCR::getPostconfirmedCommitmentReturn { _0: commitment } =
contract.getPostconfirmedCommitment(U256::from(height)).call().await?;

let return_height: u64 = commitment
.height
Expand Down
6 changes: 2 additions & 4 deletions protocol-units/settlement/mcr/contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@ For a given block height, MCR selects the earliest block commitment that matches

## Proof of Correctness

> To proof: For a given block height, MCR selects the earliest block commitment that matches the supermajority of stake-
The stake is fixed for an epoch, so only commitments for a specific block height are considered, allowing for a straightforward proof.

**Commitment**. Let $v: C \to V$ map a commitment to its validator, where $C$ represent all possible commitments and $V$ is the set of validators. Since commitments are ordered by L1 in the L1-blocks, let $C'$ be an ordered subset of $C$ with $k$ elements (i.e. up to the $k$-th commitment).
**Commitment**. Let $v: C \to V$ map a commitment to its validator, where $C$ represent all possible commitments and $V$ is the set of validators. Since commitments are ordered by L1 in the L1-blocks, let $C'$ be an ordered subset of $C$ with $k$ elements (i.e. up to the $k$-th commitment).

**Stake**. Let $s: V \to \mathbb{N}$ map a validator to their stake and $S(C',i) = \sum_{j = 1}^{i} s(v(c_j))$ the cumulative stake up to the $i$-th commitment. $S$ is non-decreasing as $S(C',i) = S(C',i - 1) + s(v(c_i))$.

We require that
We require that

$$
S(C',i) > \frac{2}{3} TotalStake = \frac{2}{3} \times \sum_{u \in V} s(u),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ contract DeployMCRDev is Script {
address[] memory custodians = new address[](1);
custodians[0] = address(moveTokenProxy);
bytes memory mcrData = abi.encodeCall(
MCR.initialize, (IMovementStaking(address(movementStakingProxy)), 0, 10, 4 seconds, custodians)
MCR.initialize, (IMovementStaking(address(movementStakingProxy)), 0, 10, 4 seconds, custodians, 1 days)
);
address mcrProxy = address(new ERC1967Proxy(address(mcrImplementation), mcrData));
MCR mcr = MCR(mcrProxy);
Expand Down
349 changes: 236 additions & 113 deletions protocol-units/settlement/mcr/contracts/src/settlement/MCR.sol

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,38 @@ contract MCRStorage {

IMovementStaking public stakingContract;

// the number of superBlocks that can be submitted ahead of the lastAcceptedSuperBlockHeight
// the number of superBlocks that can be submitted ahead of the lastPostconfirmedSuperBlockHeight
// this allows for things like batching to take place without some attesters locking down the attester set by pushing too far ahead
// ? this could be replaced by a 2/3 stake vote on the superBlock height to epoch assignment
// ? however, this protocol becomes more complex as you to take steps to ensure that...
// ? 1. superBlock heights have a non-decreasing mapping to epochs
// ? 2. Votes get accumulated reasonable near the end of the epoch (i.e., your vote is cast for the epoch you vote fore and the next)
// ? if howevever, you simply allow a race with the tolerance below, both of these are satisfied without the added complexity
// TODO the above explanation is not clear and needs to be rephrased or further explained
// TODO unless this is clarified or becomes relevant in the future, this comment should be removed
uint256 public leadingSuperBlockTolerance;

// track the last accepted superBlock height, so that we can require superBlocks are submitted in order and handle staking effectively
uint256 public lastAcceptedSuperBlockHeight;
// track the last postconfirmed superBlock height, so that we can require superBlocks are submitted in order and handle staking effectively
uint256 public lastPostconfirmedSuperBlockHeight;

/// Acceptor term time in seconds (determined by L1 blocks). The confimer remains the same for acceptorTerm period.
// This means we accept that if the acceptor is not active the postconfirmations will be delayed.
// TODO permit that anyone can confirm but only the Acceptor gets rewarded.
// TODO The Acceptor should also get rewarded even if another attestor confirmed the postconfirmation.
// The Acceptor term can be minimal, but it should not be O(1) as the acceptor should have some time
// to prepare and post L1-transactions that will start the validation of attestations.
uint256 public acceptorTerm;

// the acceptor for the accepting epoch
address public currentAcceptor;

// TODO i added these param descriptions. are these correct?
/// Struct to store block commitment details
/// @param height The height of the block
/// @param commitment The hash of the committment
/// @param blockId The unique identifier of the block (hash of the block)
struct SuperBlockCommitment {
// currently, to simplify the api, we'll say 0 is uncommitted all other numbers are legitimate heights

uint256 height;
bytes32 commitment;
bytes32 blockId;
Expand All @@ -37,15 +54,32 @@ contract MCRStorage {
// track the total stake accumulate for each commitment for each superBlock height
mapping(uint256 superBlockHeight => mapping(bytes32 commitement => uint256 stake)) public commitmentStakes;

// map superBlock height to accepted superBlock hash
mapping(uint256 superBlockHeight => SuperBlockCommitment) public acceptedSuperBlocks;
// Track which attester postconfirmed a given superBlock height
mapping(uint256 superBlockHeight => address attester) public postconfirmedBy;

// Track if acceptor postconfirmed a given superBlock height
// TODO this may be redundant due to one of the mappings below
mapping(uint256 superBlockHeight => bool) public postconfirmedByAcceptor;

// Track the L1Block height when a superBlock height was postconfirmed
mapping(uint256 superBlockHeight => uint256 L1BlockHeight) public postconfirmedAtL1BlockHeight;

// TODO: either the L1Block timestamp or L1Block height should be tracked, both are not needed, but keep both until we know which one is not needed
// Track the L1Block timestamp when a superBlock height was postconfirmed
mapping(uint256 superBlockHeight => uint256 L1BlockTimestamp) public postconfirmedAtL1BlockTimestamp;

// Track the L1Block height when a superBlock height was postconfirmed by the acceptor
mapping(uint256 superBlockHeight => uint256 L1BlockHeight) public postconfirmedAtL1BlockHeightByAcceptor;

// map superBlock height to postconfirmed superBlock hash
mapping(uint256 superBlockHeight => SuperBlockCommitment) public postconfirmedSuperBlocks;

// whether we allow open attestation
bool public openAttestationEnabled;

// versioned scheme for accepted superBlocks
mapping(uint256 => mapping(uint256 superBlockHeight => SuperBlockCommitment)) public versionedAcceptedSuperBlocks;
uint256 public acceptedSuperBlocksVersion;
// versioned scheme for postconfirmed superBlocks
mapping(uint256 => mapping(uint256 superBlockHeight => SuperBlockCommitment)) public versionedPostconfirmedSuperBlocks;
uint256 public postconfirmedSuperBlocksVersion;

uint256[47] internal __gap;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.13;

interface IMCR {
event BlockAccepted(
event SuperBlockPostconfirmed(
bytes32 indexed blockHash,
bytes32 stateCommitment,
uint256 height
Expand Down
Loading

0 comments on commit 13f8eb6

Please sign in to comment.