Remote EVM execution for Moonriver and Moonbeam
My name is Gorka (girazoki) from the Purestake dev team, focusing most of the time on XCM.
Summary
This is a proposal to enable EVM remote execution (i.e., EVM execution triggered by a remote chain) in Moonriver and Moonbeam. The main idea is that we install the EthereumXcm pallet in Moonriver and Moonbeam, which acts as a proxy between the XCM execution and the EVM world.
Abstract
Moonbeam is focused on bringing the best of both the Polkadot ecosystem and the EVM worlds to its users. This implies being able to leverage cross-chain capabilities to offer EVM support to other parachains that are seeking interactions with projects already deploted in Moonbeam.
While XCM is alreay able to trigger remote execution, calling the EVM implies several assumptions that we cannot guarantee through XCM. These include, among others, the fact that we cannot provide a signature and a nonce as we need to dispatch transactions through keyless accounts like the sovereign account.
The solution proposed implies calling a special pallet, called EthereumXCM, with a subset of the arguments that are necessary to call the EVM directly. With this new pallet, other chains from the Polkadot ecosystem will be able to trigger remote EVM execution in Moonbeam and leverage interactions with any of the projects already deployed.
Where are we now?
I will describe the current remote execution status from two different perspectives:
-
Pallets callable remotely: The current status is that the pallets/extrinsics that are callable remotely are those that imply a signed origin. Any other pallet requiring a special origin requires specific conversions that are not in place yet in Moonriver and Moonbeam. This is the case of
pallet-ethereum
, which requires an EthereumOrigin. - Accounts that are able to dispatch remotely: Only the parachains sovereign account is able to dispatch transactions in Moonriver. In order to dispatch transactions through XCM, a specific MultiLocation to dispatchOrigin is required and as of today, its only implemented for the main sovereign account.
What do we need to be able to call the EVM remotely?
In the following I describe the main requirements that are needed to be able to enable remote-EVM calls:
- Signature check bypass: Keyless accounts like the sovereign account will not ever be able to provide a signature as there is no private key backing it. This means we need to be able to call the EVM bypassing preliminary signature checks.
- Avoid Ethereum Tx hash collision: The signature is part of the transaction hash, and since we no longer have a signature, just trusting the body of the transaction could lead to hash collisions.
- Enable multilocation-derived keyless accounts: Having only the possibility of using the main sovereign account limits quite a lot the usecases that can be performed, as it would only allow parachain origins to issue EVM transactions. Thus, we need to be able to derive keyless accounts from locations that are not the parachain locations.
- Fee payment: XCM or EVM: Currently the XCM executor and the EVM executor have their own independent ways of charging for fee. In order to prevent double-charging, we need to decide which satisfy our needs better.
- Be able to dispatch from a keyed account instead of a keyless account: While for security we cannot dispatch directly XCM transactions from a keyed account, we can allow a user to decide whether it wants to create a proxy between its keyless account and its keyed account.
EthereumXcm pallet
The ethereumXcm pallet provides solution to requirements 1,2 4 and 5. Similar to how pallet-ethereum works, it provides an interface between the XCM-executor and the EVM. This pallet works with a special origin called XcmEthereumTransaction
. This origin is only appended when calling the EthereumXcm pallet from the xcm-executor. Thus, we guarantee that this pallet is xcm-callable only.
The pallet also works with the concept of EthereumXcmTransaction
. This is a similar type to the one requested by pallet-ethereum:
pub struct EthereumXcmTransactionV2 {
/// Gas limit to be consumed by EVM execution.
pub gas_limit: U256,
/// Either a Call (the callee, account or contract address) or Create (currently unsupported).
pub action: TransactionAction,
/// Value to be transfered.
pub value: U256,
/// Input data for a contract call. Max. size 65_536 bytes.
pub input: BoundedVec<u8, ConstU32<MAX_ETHEREUM_XCM_INPUT_SIZE>>,
/// Map of addresses to be pre-paid to warm storage.
pub access_list: Option<Vec<(H160, Vec<H256>)>>,
}
However it does not ask for a nonce, gasPrice or signature. This is because:
- We will use a global nonce as a nonce, that gets incremented everytime we receive an EthereumXcm transaction. This allows to generate different transaction hashes for different EthereumXcm transactions. The global nonce to be used is fetched from the storage Nonce of the EthereumXcm pallet.
- gasPrice is set to 0 by the pallet because fees will be charged in the xcm-executor, not on the evm executor.
- signature is not needed as this is an xcm execution. Xcm works with the premise of granting origins permisions to use certain accounts, like the sovereign account.
The pallet contains two main dispatchables:
-
transact(tx: EthereumXcmTransaction)
: This dispatchable allows to issue a transaction to the evm-executor with the current origin. -
transact_through_proxy(tx: EthereumXcmTransaction, transact_as: H160)
: This dispatchable allows to issue a transaction to the evm-executor usingtransact_as
as origin. It requires an ‘Any’ proxy to exist between thetransact_as
and the current origin.
MultiLocation-derived accounts
As we already said, in order to perform remote calls in the xcm-executor we need to somehow be able to convert a MultiLocation origin to a dispatch Origin, typically defined by a 20-byte account in Moonbeam.
The only conversion that exists today is the Sovereign account conversion. This conversion is performed only for parachain origins, and the associated 20 byte account is constructed by appending together the 'sibl'
word, the para_id
, and sufficient trailing zeroes.
MultiLocation {parents: 1, interior: X1(Parachain(2000))} -> b'sibl' + b'2000' + trailing zeros.
However, what happens if the origin trying to dispatch is an account on a remote parachain, and not the parachain itself?
MultiLocation {parents: 1, interior: X2(Parachain(2000), AccountKey32(Alice))}
In this case we dont have any conversion do a dispatchOrigin
. For this reason we enable the Account20Hash
conversion, which basically performs a blake2_256 hash and takes the lowest 20 bytes:
MultiLocation {parents: 1, interior: X2(Parachain(2000), AccountKey32(Alice))} -> blake2_256(MultiLocation {parents: 1, interior: X2(Parachain(2000), AccountKey32(Alice))})[0..20]
This allows Alice in parachain 2000 to have a unique keyless account from which she can dispatch remote transactions in Moonbeam. Note that if a Alice uses the same private key from another chain, her keyless account will be different
Why cannot we directly use Alice?
This is a question that we often get when explaining remote EVM execution. The reason why we cannot use Alice directly to dispatch is because that allows the remote chain to use any account that exists in the Moonbeam ecosystem.
Suppose a malicious chain sends a message claiming it was sent by “Bob” from its chain. “Bob” never sent that message, but still, the malicious chain would be able to act on his behalf on the Moonbeam chain.
With hash-based multilocation derived accounts, a malicious chain can only control those accounts that can be hashed with its para_id
. Thus, it cannot target a specific account in Moonbeam, neither can mess with the derived accounts from other chains
Overall picture after this change
After this change, there will be two fundamental ways of entering the EVM executor:
- Through the regular frontier RPC interface, in which users send signed transactions and all ethereum validations(nonce, gasPrice, signature) are checked.
- Through the xcm-executor and EthereumXcm pallet.
Security considerations
It is critical to understand the security implications of this schema. Here are the main points to take into account:
- The multilocation derived address is an address controlled by the remote chain. This means that access to such account can be prevented by the remote chain. It also means that a compromised chain can act on your behalf using this account. For such reason, we recommend not to treat this account as a private-key backed account. This account should only hold sufficient balance to perform remote interactions, but ideally nothing that would put large amounts of funds at risk.
- The proxy made from a private key backed account to the multilocation derived address (e.g., Alice->ml_derived_account) is totally up to the user, but it means that if the remote chain gets compromised, such chain would have access the private key backed account on Moonbeam. If such proxy is created, the user is fully trusting the remote chain not to tamper with its account.
- A full audit on this proposal will be conducted before the code reaches Moonriver and Moonbeam
Key learnings from the Moonbase alpha testnet deployment
There are a couple of important points we have understood from the deployment already made to the Moonbase chain:
- Remote EVM interactions are capped itself by the remote execution limits. This means that remote EVM interaction is probably not well-suited for high-demanding EVM executions, as the block space reserved for XCM is limited.
- It is critical that other chains have a notion of the fee costs, weight and address derivation mechanics. To help with this, we provided a xcm-utils precompile at address
0x000000000000000000000000000000000000080C
. Such precompile will also be available in Moonriver and Moonbeam if this proposal gets accepted
Next steps
A snapshot voting session has been opened for 7 days here : Snapshot Voting
If the snapshot vote passes, this idea will be implemented and proposed to be included in one of the following Runtime Upgrade.
If you have any questions or comments, feel free to reply in the comment section below.