EIP-5164: Cross-Chain Execution
Defines an interface that supports execution across EVM networks.
| 作者 | Brendan Asselstine, Pierrick Turelier |
|---|---|
| 讨论-To | https://ethereum-magicians.org/t/eip-5164-cross-chain-execution/9658 |
| 状态 | Review |
| 类型 | Standards Track |
| 分类 | ERC |
| 创建日期 | 2022-06-14 |
| 英文版 | https://eips.ethereum.org/EIPS/eip-5164 |
目录
Abstract
This specification defines a cross-chain execution interface for EVM-based blockchains. Implementations of this specification will allow contracts on one chain to call contracts on another.
The specification defines two components: the “Cross Chain Relayer” and the “Cross Chain Executor”. The Cross Chain Relayer lives on the calling side, and the executor lives on the receiving side. Calls sent to Cross Chain Relayers will move through a transport layer to Cross Chain Executor(s), where they are executed. Implementations of this specification must implement both components.
Motivation
Many Ethereum protocols need to coordinate state changes across multiple EVM-based blockchains. These chains often have native or third-party bridges that allow Ethereum contracts to execute code. However, bridges have different APIs so bridge integrations are custom. Each one affords different properties; with varying degrees of security, speed, and control. Defining a simple, common specification will increase code re-use and allow us to use common bridge implementations.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
This specification allows contracts on one chain to send messages to contracts on another chain. There are two key interfaces that needs to be implemented:
CrossChainRelayerCrossChainExecutor
The CrossChainRelayer lives on the origin chain. Users can share a single CrossChainRelayer or deploy their own.
The CrossChainExecutor lives on the destination chain and executes relayed calls. Users can share a single CrossChainExecutor or deploy their own.
CrossChainRelayer
The CrossChainRelayer lives on the chain from which messages are sent. The Relayer’s job is to broadcast calls through a transport layer to one or more CrossChainExecutor contracts.
Methods
relayCalls
Will relay a batch of Call structs to be executed by any CrossChainExecutor(s) that execute calls from this Relayer. The gasLimit is used as a limit on the executing side.
CrossChainRelayers MUST emit the RelayedCalls event when a batch of calls is relayed.
CrossChainRelayers MUST increment a nonce so that each batch of calls can be uniquely identified.
CrossChainRelayers MUST return the nonce to allow callers to track the batch of calls.
CrossChainRelayers SHOULD pass the nonce as well as the address of the sender in the call to CrossChainExecutor to uniquely identify the message on the receiving chain.
CrossChainRelayers MAY require payment.
struct Call {
address target;
bytes data;
}
interface CrossChainRelayer {
function relayCalls(Call[] calldata calls, uint256 gasLimit) external payable returns (uint256 nonce);
}
- name: relayCalls
type: function
stateMutability: payable
inputs:
- name: calls
type: Call[]
- name: gasLimit
type: uint256
outputs:
- name: nonce
type: uint256
Events
RelayedCalls
The RelayedCalls event MUST be emitted by the CrossChainRelayer when relayCalls is called.
interface CrossChainRelayer {
event RelayedCalls(
uint256 indexed nonce,
address indexed sender,
Call[] calls,
uint256 gasLimit
);
}
- name: RelayedCalls
type: event
inputs:
- name: nonce
indexed: true
type: uint256
- name: sender
indexed: true
type: address
- name: calls
type: Call[]
- name: gasLimit
type: uint256
Error handling
GasLimitTooHigh
CrossChainRelayers MAY revert with GasLimitTooHigh if the gasLimit passed to relayCalls is higher than the maximum gas limit accepted by the bridge being used.
interface CrossChainRelayer {
error GasLimitTooHigh(
uint256 gasLimit,
uint256 maxGasLimit
);
}
CrossChainExecutor
The CrossChainExecutor executes relayed calls. Developers must implement a CrossChainExecutor in order to execute messages on the receiving chain.
The CrossChainExecutor will execute a nonce only once, but may execute nonces in any order. This specification makes no ordering guarantees, because messages may travel non-sequentially through the transport layer.
Execution
CrossChainExecutors SHOULD authenticate that the call has been performed by the bridge transport layer.
CrossChainExecutors MUST NOT execute a batch of calls more than once.
Calldata
CrossChainExecutors MUST append the ABI-packed (nonce, sender) to the calldata for each call being executed. It allows the receiver of the call to check the true sender of the transaction and use the nonce to apply any transaction ordering logic.
interface CrossChainExecutor {
bytes calldata = abi.encode(Call.data, nonce, sender); // Can also use abi.encodePacked
}
- name: calldata
type: bytes
inputs:
- name: Call.data
type: bytes
- name: nonce
type: uint256
- name: sender
type: address
Error handling
CallsAlreadyExecuted
CrossChainExecutors MUST revert if a batch of calls has already been executed and SHOULD emit CallsAlreadyExecuted custom error.
interface CrossChainExecutor {
error CallsAlreadyExecuted(
uint256 nonce
);
}
CallFailure
CrossChainExecutors SHOULD revert with a CallFailure error if a call fails.
interface CrossChainExecutor {
error CallFailure(
uint256 callIndex,
bytes errorData
);
}
Events
ExecutedCalls
ExecutedCalls MUST be emitted once calls have been executed.
interface CrossChainExecutor {
event ExecutedCalls(
CrossChainRelayer indexed relayer,
uint256 indexed nonce
);
}
- name: ExecutedCalls
type: event
inputs:
- name: relayer
indexed: true
type: CrossChainRelayer
- name: nonce
indexed: true
type: uint256
Rationale
The CrossChainRelayer can be coupled to one or more CrossChainExecutor. It is up to bridges to decide how to couple the two. Users can easily bridge a message by calling relayCalls without being aware of the CrossChainExecutor address. Messages can also be traced by a client using the data logged by the ExecutedCalls event.
Calls are relayed in batches because it is such a common action. Rather than have implementors take different approaches to encoding multiple calls into the data portion, this specification includes call batching to take away any guess work.
Some bridges may require payment in the native currency, so the relayCalls function is payable.
Bridges relay messages in various ways, applications should be aware of how the bridge they rely on operates and decide if they want to enforce transaction ordering by using the nonce.
向后兼容性
This specification is compatible with existing governance systems as it offers simple cross-chain execution.
Security Considerations
Bridge trust profiles are variable, so users must understand that bridge security depends on the implementation.
Copyright
Copyright and related rights waived via CC0.
参考文献
Please cite this document as:
Brendan Asselstine, Pierrick Turelier, "EIP-5164: Cross-Chain Execution [DRAFT]," Ethereum Improvement Proposals, no. 5164, June 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5164.