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:
CrossChainRelayer
CrossChainExecutor
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.
CrossChainRelayer
s MUST emit the RelayedCalls
event when a batch of calls is relayed.
CrossChainRelayer
s MUST increment a nonce
so that each batch of calls can be uniquely identified.
CrossChainRelayer
s MUST return the nonce
to allow callers to track the batch of calls.
CrossChainRelayer
s 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.
CrossChainRelayer
s 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
CrossChainRelayer
s 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
CrossChainExecutor
s SHOULD authenticate that the call has been performed by the bridge transport layer.
CrossChainExecutor
s MUST NOT execute a batch of calls more than once.
Calldata
CrossChainExecutor
s 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
CrossChainExecutor
s MUST revert if a batch of calls has already been executed and SHOULD emit CallsAlreadyExecuted
custom error.
interface CrossChainExecutor {
error CallsAlreadyExecuted(
uint256 nonce
);
}
CallFailure
CrossChainExecutor
s 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.