-
Couldn't load subscription status.
- Fork 0
CDCP #2
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
base: main
Are you sure you want to change the base?
CDCP #2
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces the Cross-Domain Composability Protocol (CDCP), which enables atomic composability between native rollups in the Compose network and external rollups. The protocol ensures that cross-domain transactions either succeed on all participating rollups or fail on all of them, maintaining atomicity guarantees.
Key changes:
- Defines the CDCP protocol with message flows between Shared Publisher (SP), Native Sequencers (NSs), Wrapped Sequencer (WS), and External Rollup Client (ER)
- Introduces a StagedMailbox contract variant for external rollups with pre-populated messages
- Establishes synchronization mechanisms between WS and ER to maintain consistent state snapshots during protocol execution
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
|
||
| ## System Model | ||
|
|
||
| We system encompasses 5 main components: |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected grammar: 'We system' should be 'The system'.
| We system encompasses 5 main components: | |
| The system encompasses 5 main components: |
| Then, each NS runs **exactly** the protocol rules of the [SCP protocol](TODO). Namely: | ||
| 1. Once it receives the `StartCDCP` message from the SP, it starts a timer and selects the transactions from the `xD_transactions` list that are meant for its chain. | ||
| 2. Then, it simulates its transactions, meaning that it executes them with a tracer at the mailbox, so that it can intercept `mailbox.Read` and `mailbox.Write` operations. | ||
| 3. Once a `mailbox.Write` operation is intercepted, it sends a `Mailbox` message to the couterparty chain sequencer (either the WS or another NS). |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'couterparty' to 'counterparty' (found in line 273's context).
| 3. Once a `mailbox.Write` operation is intercepted, it sends a `Mailbox` message to the couterparty chain sequencer (either the WS or another NS). | |
| 3. Once a `mailbox.Write` operation is intercepted, it sends a `Mailbox` message to the counterparty chain sequencer (either the WS or another NS). |
| The Shared Publisher (SP) runs a slightly modified version of the SCP protocol: | ||
| 1. It sends a `StartCDCP` message to the appropriate sequencers, starts a timer and waits for NSs' `Vote` messages. | ||
| 2. If a timeout occurs or if a `Vote(0)` message is received (indicates a failure), it sends a `Decided(0)` message to the NSs and a `NativeDecided(0)` message to the WS, and terminates. | ||
| 3. If it receives a `Vote(1)` message from all NSs, it stops the timer (as it not longer will be used) and sends a `NativeDecided(1)` message to the WS, indicating that the NSs are willing to proceed. |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected grammar: 'as it not longer will be used' should be 'as it will no longer be used'.
| 3. If it receives a `Vote(1)` message from all NSs, it stops the timer (as it not longer will be used) and sends a `NativeDecided(1)` message to the WS, indicating that the NSs are willing to proceed. | |
| 3. If it receives a `Vote(1)` message from all NSs, it stops the timer (as it will no longer be used) and sends a `NativeDecided(1)` message to the WS, indicating that the NSs are willing to proceed. |
| // Message is valid to be read. | ||
|
|
||
| // Mark as used | ||
| usedKeys[key] = true; |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The read function is marked as view but attempts to modify state by setting usedKeys[key] = true (line 192). This will cause a compilation error. The function should either be changed to non-view or the state modification logic should be removed/refactored.
| bytes memory data = outbox[key]; | ||
|
|
||
| // Update the chain-specific outbox root | ||
| if (outboxRootPerChain[destChainID] == bytes32(0)) { | ||
| chainIDsOutbox.push(destChainID); | ||
| } | ||
| outboxRootPerChain[destChainID] = keccak256( | ||
| abi.encode(outboxRootPerChain[destChainID], key, data) |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable shadowing: data is declared as a function parameter (line 219) and then re-declared as a local variable (line 250). This shadows the parameter and may cause confusion. Use a different variable name for the local variable.
| bytes memory data = outbox[key]; | |
| // Update the chain-specific outbox root | |
| if (outboxRootPerChain[destChainID] == bytes32(0)) { | |
| chainIDsOutbox.push(destChainID); | |
| } | |
| outboxRootPerChain[destChainID] = keccak256( | |
| abi.encode(outboxRootPerChain[destChainID], key, data) | |
| bytes memory messageData = outbox[key]; | |
| // Update the chain-specific outbox root | |
| if (outboxRootPerChain[destChainID] == bytes32(0)) { | |
| chainIDsOutbox.push(destChainID); | |
| } | |
| outboxRootPerChain[destChainID] = keccak256( | |
| abi.encode(outboxRootPerChain[destChainID], key, messageData) |
| # Wait for mailbox message arrival from another sequencer | ||
| return | ||
|
|
||
| else if sim.failReason == OTHER: |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect Python syntax: should be elif instead of else if.
| else if sim.failReason == OTHER: | |
| elif sim.failReason == OTHER: |
| function release_snapshot_lease(store: SnapshotStore): | ||
| lock(store.mu): | ||
| store.read_lease = false | ||
| if store.read_lease == false and store.swap_pending: |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant condition check: store.read_lease is already set to false on line 681, so checking store.read_lease == false on line 682 is redundant. This condition will always be true at this point.
| if store.read_lease == false and store.swap_pending: | |
| if store.swap_pending: |
|
|
||
| Following the SBCP (v2), at the end of the superblock period, sequencers submit an `AggregationProof` to the SP, | ||
| commiting to their final state and to the associated mailbox roots. | ||
| With an external rollup, the mailbox roots from natives should also be compared to the roots stores in the ER. |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'stores' to 'stored'.
| With an external rollup, the mailbox roots from natives should also be compared to the roots stores in the ER. | |
| With an external rollup, the mailbox roots from natives should also be compared to the roots stored in the ER. |
| if (outboxRootPerChain[destChainID] == bytes32(0)) { | ||
| chainIDsOutbox.push(destChainID); | ||
| } | ||
| outboxRootPerChain[destChainID] = keccak256( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MatheusFranco99 if it writes the new root it doesnt qualify as "staging" the message. Does it?
| > Space optimizations can be made to the contract by letting the `read` and `write` calls automatically remove used messages from storage. | ||
|
|
||
| ## Protocol | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still stick with the SP being a coordinator? Or can the sequencers do it independently
| The special atomic transaction to the ER, `safe_execute`, allows an atomic execution of the mailbox staging and the main transaction. | ||
| It has the following pseudo-code: | ||
| ```solidity | ||
| function safe_execute(stagedInboxMsgs, stagedOutboxMsgs, mainTx) external { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't it also receive signature from the SP that the tx can be executed?
| It has the following pseudo-code: | ||
| ```solidity | ||
| function safe_execute(stagedInboxMsgs, stagedOutboxMsgs, mainTx) external { | ||
| // 1. Pre-populate the staged inbox messages |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should better define the responsibilities and structure of the SP
Structure:
- A committee of operators
- Selected, potentially, via some dPOS protocol
- Each operator has a signing key
Responsibilities
- Validate the simulation (the messages are correct since once we write to an ER we can't un-write it)
- Validate no transitive dependencies
- Sign (each member of the SP committee) that the tx can safely execute
| } | ||
| ``` | ||
|
|
||
|  |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we discussed that the WS needs to write messages one by one during simulation because otherwise it can't guarantee the actual values during execute (say a msg returns some value from a contract)
| ```solidity | ||
| function safe_execute(stagedInboxMsgs, stagedOutboxMsgs, mainTx) external { | ||
| // 1. Pre-populate the staged inbox messages | ||
| for (msg in stagedInboxMsgs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add some execution deadline? say within the same block or following block?
Overview
Introduces the CDCP protocol for the integrated/included rollups composability (here denoted native vs. external).
It describes the protocol, the new mailbox, the syncing with the ER client, and the modifications to the settlement pipeline.