XCM Virtual Machine (XCVM) & XCM Executor
For a more practical approach to utilizing XCM, refer to the XCM Docs. Please keep in mind that XCM is under active development.
At the core of XCM lies the Cross-Consensus Virtual Machine (XCVM). A βmessageβ in XCM is an XCVM program, referred to as an "XCM" or "XCMs" for multiple messages. The XCVM is a register-based state machine. The state is tracked in domain-specific registers that hold information that is used and mutated along the execution of a particular message. Most of the XCM format comprises these registers and the instructions used to compose XCVM programs.
The XCVM is an ultra-high-level non-Turing-complete computer whose instructions are designed to be roughly at the same level as transactions in terms of definition. Messages are one or more XCM instructions executed in order by the XCVM. An XCM is executed until it either runs to the end or hits an error, at which point it finishes up and halts.
The first implementation of the XCVM is the
xcm-executor
.
It follows the XCVM specification provided by Parity. It's engineered to be extendable, providing
maximum customizability when configuring XCM. Because the xcm-executor
is just an implementation
of XCVM, it's entirely possible to create another implementation if desired.
XCMs are XCVM Programsβ
A cross consensus message (XCM) is just a program that runs on the XCVM
: in other words, one or
more XCM instructions that are executed by an XCVM implementation, such as the xcm-executor
. To
learn more about the XCVM and the XCM format, see the latest
blog post on XCM
by Dr. Gavin Wood.
XCM instructions might change a register, the state of the consensus system, or both. Depending on the program's goal, whether it is to teleport assets from one chain to another or call a smart contract on another chain, XCMs usually require changes to the registers before any changes to the consensus system can be made.
XCM Executor & Configurationβ
The XCM Executor's implementation centers around a core piece: the XCM configuration. Each instance of the Executor must have a valid configuration, which specifies a multitude of options on how a chain may treat incoming messages via Barriers, calculate weight for a message via the Weigher, how much weight to purchase via the Trader, configure fees, how to convert origins, and more.
Cross Consensus Message (XCM) Anatomy & Flowβ
An XCM is made up of a list of instructions that are executed in order. There are four different kinds of XCM instructions:
- Instruction - Results in a state change in the local consensus system or some state change.
- Trusted Indication - Tells the XCVM, or the Executor, that some action has been done before already - meaning, this action is now trusted and can be acted on, i.e., in a teleport scenario.
- Information - Provides additional information about a particular origin, usually the result
of a query, i.e., a
QueryResponse
instruction. - System Notification - Typically used in the context of when an HRMP channel is being opened, closed, or accepted.
Typically, an XCM takes the following path through the XCVM:
- Instructions within an XCM are read one-by-one by the XCVM. An XCM may contain one or more instructions.
- The instruction is executed. This means that the current values of the XCVM registers, the instruction type, and the instruction operands are all used to execute some operation, which might result in some registers changing their value, or in an error being thrown, which would halt execution.
- Each subsequent instruction within the XCM is read until the end of the message has been reached.
Example Register: The Holding Registerβ
There are many instructions that depend on the Holding register. The Holding register is an XCVM
register that provides a place for any assets that are in an intermediary state to be held until
they are taken out of the Holding register. It requires an instruction to place assets within it and
another to withdraw them. The simplest example of this occurring is the DepositAsset
instruction,
which in its Rust form looks like this:
enum Instruction {
DepositAsset {
assets: MultiAssetFilter,
beneficiary: MultiLocation,
},
/* snip */
}
This instruction specifies which assets (asset type and amount), already present in the Holding register, are going to be taken from it and deposited to the specified beneficiary (recipient). It is very common for instructions to remove and place assets into the Holding register when transacting between chains.
Example: TransferAssetβ
An example below illustrates how a chain may transfer assets locally, or locally on a remote chain
(as part of another instruction) using an XCM. In this message, the TransferAsset
instruction is
defined with two parameters: assets
, which are the assets to be transferred, and the
beneficiary
, whoever will be the sole beneficiary of these assets. More complex instructions,
especially those which perform actions that target a location other than the interpreting consensus
system may make use of XCVM registers.
enum Instruction {
TransferAsset {
assets: MultiAssets,
beneficiary: MultiLocation,
}
/* snip */
}
-
A
MultiAsset
is a general identifier for an asset. It may represent both fungible and non-fungible assets, and in the case of a fungible asset, it represents some defined amount of the asset. -
A
MultiLocation
is a relative identifier, meaning that it can only be used to define the relative path between two locations, and cannot generally be used to refer to a location universally.
TransferAsset
is one of the many instructions that can be contained within an XCM. For more
information, please read XCM Instructions in the wiki.
Locations in XCMβ
XCM's generic nature involves specifying a wide array of "locations", or any body that is governed
by consensus (parachains, solochains, smart contracts, accounts, etc). These are relatively abstract
notions that point to where but also to who a particular action may affect. The MulitLocation
type is what XCM uses to define these locations.
A MultiLocation
is a relative identifier that defines a relative path into some state-bearing
consensus system.
It is used to define the relative path between two locations, and cannot generally be used to refer to a location universally. It is very much akin to how a relative filesystem path works and is dependent on which consensus system the location expression is being evaluated.
MultiLocation
has two primary fields:
- A series of paths, called
Junctions
, which define an interior portion of state to descend into it (sometimes called a "sub-consensus" system, such as a smart contract or pallet). An interior location may also be used to refer to a Junction, used in the context of "a parachain is an interior location of the relay chain", or how a UTXO is interior to Bitcoin's consensus. - The number of parent junctions at the beginning of a
MultiLocation
's formation - in other words, the number of parent consensus systems above it.
There are a number of various Junction
variants that may be used to describe a particular
location - whether it's a 32 byte account, a Substrate pallet, or a pluralistic body.
MultiLocation Scenario Exampleβ
In this scenario, assume an XCM is to be sent from our parachain to the Asset Hub
(Parachain 1000
). This XCM references an account on the Asset Hub. As a general path, the
MultiLocation
would look like this:
../Parachain(1000)/AccountId32(<some_account_id>)
Or, as a Rust enum:
MultiLocation {
parents: 1,
interior: X2(Parachain(1000), <some_account_id>.into())
}
-
In the first field,
parents
, there is a parent of1
. This is because our parachain has the relay chain as a parent - in other words, it will go up by one consensus system to the relay chain. This is also illustrated by the../
of the "file path" representation. -
The second field,
interior
, defines where to go after the relay chain. In this case, from the relay chain this message will go to the Asset Hub (Parachain 1000
), then reference the account (some_account_id
) located within.
Keep in mind that this location is specific to this interaction. The identities may need to change if this location was defined on another consensus system, such as Kusama. On other consensus systems, such as Ethereum, it won't be able to interpret it.
UniversalLocation in XCMβ
A UniversalLocation
refers to any global consensus system. A global consensus system is an entity
that provides its top-level consensus through some non-derivative consensus algorithm that can exist
without reference to any other singleton data system. Such global consensus systems include Polkadot
(or other relay chains), Bitcoin, or Ethereum. It provides a point of reference for overarching
consensus systems.
The GlobalConsensus
junction refers to a global consensus system and takes a NetworkId
that
specifies a particular remote network. A UniversalLocation
allows overarching consensus systems to
communicate using this junction. Sub-consensus systems (i.e., a parachain on Polkadot) may refer to
other remote sub-consensus systems (i.e., a parachain on Kusama) using a relative path defined via
a MultiLocation
.
Simulating XCVM using the xcm-simulatorβ
Within the Polkadot repository exists the
xcm-simulator
,
which allows developers to experiment with building, executing, and simulating various XCM use
scenarios.