Basic Inbound Message Channel (Darwinia → Ethereum)

Ethereum RPC

An Ethereum RPC is a data structure representing asynchronous calls that a Darwinia pallet wants to make on a remote Ethereum smart contract. Such RPCs are generated by a Polkadot pallet and then sent to the corresponding smart contract via a cross-chain bridge. They are asynchronous, one-way calls that require a Darwinia pallet to apply the corresponding callback function to the return of the message execution. They are received and processed by Ethereum smart contracts.

EthereumRPC {
    sourcePallet Int
    targetContractAddress EthereumContractAddress
    nonce Int
    payload Bytes
}

The attribute payload in EthereumRPC is the ABI-encoded data for contract invocation encoded by the sending pallet. The receiving smart contract will be called directly with this ABI-encoded call.

The primary inbound channel is the one that sends Ethereum RPCs from Darwinia to Ethereum. It consists of the Commitments pallet and its corresponding smart contract and provides protection against replay attacks.

The Commitments pallet accepts requests from other pallets or parachains via XCMP and sends Ethereum RPCs to Ethereum. Upon accepting the request, it adds a nonce and appends the message to a queue. It also generates a commitment in the form of a hash of the message queue at fixed intervals, adds it to the MMR leaf, and includes it in the Darwinia Block Header.

The corresponding Darwinia light client smart contract accepts this commitment and the set of messages in it as input. It verifies that the commitment described here is contained in the MMR Leaf, then verifies that these messages are contained in the commitment via the hash value, and finally invokes the Ethereum smart contract for each Ethereum RPC to process these messages in turn.

Cross Chain Filter

/**
* The Message is the structure of DarwiniaRPC which should be delivery to Ethereum-like chain
* @param sourceAccount The derived DVM address of pallet ID which send the message
* @param targetContract The targe contract address which receive the message
* @param laneContract The inbound channel contract address which the message commuting to
* @param nonce The ID used to uniquely identify the message
* @param payload The calldata which encoded by ABI Encoding
*/
struct Message {
	address sourceAccount;
	address targetContract;
	address laneContract;
	uint256 nonce;
	bytes payload; /*abi.encodePacked(SELECTOR, PARAMS)*/
}

Note: The source pallet will pass the filter checks at the message layer. The target contract at the application layer needs to implement the corresponding interface to control which source Pallet can call the contract. The interface is defined as follows:

interface ICrossChainFilter {
    function crossChainFilter(address sourceAccount, bytes calldata payload) external view returns (bool); 
}

Message Commitment

Darwinia facilitates any parachain that wants to send messages to Ethereum, so it requires representing them in a trustless and verifiable way. It is done by creating custom message commits on Darwinia, which can be quickly and economically verified.

Basic Outbound Message Channel (Ethereum → Darwinia)

Darwinia RPC

Darwinia RPC is a data structure representing asynchronous calls that Ethereum smart contracts want to make on remote Darwinia pallets. They are generated by the Ethereum smart contract and then sent to the corresponding pallet via a cross-chain bridge. They are asynchronous, one-way calls that do not require any response (based on the integrity of the protocol, it is theoretically necessary to perform message acknowledgement. But here, we believe that Darwinia pallets are easy to ensure successful message execution and that execution on the Ethereum consumes more gas, so no further acknowledgement of the message is needed). They are received and processed by Darwinia pallets.

DarwiniaRPC {
    sourceContractAddress EthereumContractAddress
    targetPallet Int
    nonce Int
    payload Bytes
}

The attribute payload in DarwiniaRPC can be anything in theory, but in practice, they should be understood by the corresponding pallet, which processes and decodes payload into the Rust type. We use ABI-encoded payload because they are easy and economic to generate and send from Ethereum.