<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.internetcomputer.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=David</id>
	<title>Internet Computer Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.internetcomputer.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=David"/>
	<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/wiki/Special:Contributions/David"/>
	<updated>2026-05-01T12:22:33Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Dealing_with_cycles_limit_exceeded_errors&amp;diff=8695</id>
		<title>Dealing with cycles limit exceeded errors</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Dealing_with_cycles_limit_exceeded_errors&amp;diff=8695"/>
		<updated>2026-02-09T15:28:39Z</updated>

		<summary type="html">&lt;p&gt;David: Deprecate page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page has been deprecated.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Parallelism&amp;diff=8694</id>
		<title>Parallelism</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Parallelism&amp;diff=8694"/>
		<updated>2026-02-09T15:28:18Z</updated>

		<summary type="html">&lt;p&gt;David: Deprecate page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page has been deprecated.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Comparing_Canister_Cycles_vs_Performance_Counter&amp;diff=8693</id>
		<title>Comparing Canister Cycles vs Performance Counter</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Comparing_Canister_Cycles_vs_Performance_Counter&amp;diff=8693"/>
		<updated>2026-02-09T15:27:53Z</updated>

		<summary type="html">&lt;p&gt;David: Deprecate page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page has been deprecated.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Current_limitations_of_the_Internet_Computer&amp;diff=8692</id>
		<title>Current limitations of the Internet Computer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Current_limitations_of_the_Internet_Computer&amp;diff=8692"/>
		<updated>2026-02-09T15:27:29Z</updated>

		<summary type="html">&lt;p&gt;David: Deprecate page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page has been deprecated.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting_forum_announcement_template&amp;diff=6525</id>
		<title>Subnet splitting forum announcement template</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting_forum_announcement_template&amp;diff=6525"/>
		<updated>2023-10-30T12:12:35Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page provides a template process that can be used to announce an upcoming series of proposals to [[Subnet splitting|split a subnet]].&lt;br /&gt;
&lt;br /&gt;
===Step 1: Heads up template, before starting the process===&lt;br /&gt;
The text below gives an example of how an announcement for an upcoming series of proposals to split a subnet could look like. &lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Hello everybody,&lt;br /&gt;
&lt;br /&gt;
We are planning to submit the proposals to split subnet &amp;lt;code&amp;gt;&amp;lt;fill in subnet ID&amp;gt;&amp;lt;/code&amp;gt; because &amp;lt;code&amp;gt;&amp;lt;fill in reason&amp;gt;&amp;lt;/code&amp;gt;. Currently this subnet is assigned the canister ID ranges &amp;lt;code&amp;gt;&amp;lt;fill in ranges; in both representations&amp;gt;&amp;lt;/code&amp;gt;. Ranges are inclusive, i.e. they include the beginning and the end of the range. We are proposing to split off the canisters corresponding to ID ranges &amp;lt;code&amp;gt;&amp;lt;fill in ranges; in both representations&amp;gt;&amp;lt;/code&amp;gt; to a new subnet. The ranges were chosen so that &amp;lt;code&amp;gt;&amp;lt;fill in how ranges were chosen&amp;gt;&amp;lt;/code&amp;gt;. For more details on subnet splitting please refer to [[Subnet splitting|this]] wiki page.&lt;br /&gt;
&lt;br /&gt;
Generally the subnet splitting process is designed in a way that – apart from downtime (&amp;lt;code&amp;gt;&amp;lt;fill in expected downtime if available&amp;gt;&amp;lt;/code&amp;gt;) – it is transparent to canisters provided that they properly handle transient errors when sending canister-to-canister messages. Note that these transient errors routinely occur during normal subnet functioning – so a correct canister implementation should properly handle these errors. In case you are unsure whether your canister properly handles these transient errors you might want to consider stopping it and restarting it after the split is complete. &lt;br /&gt;
&lt;br /&gt;
It will be possible to verify whether the proposed split is authentic by verifying the splitting related artifacts as described [[Verification of Artifacts in Subnet Splitting|here]]. The required artifacts will be obtained after the proposal to halt the source subnet at a CUP boundary was accepted and the subnet successfully halted. They will be published in a follow up post in this thread.&lt;br /&gt;
&lt;br /&gt;
Subsequent updates will also be shared in this thread. &lt;br /&gt;
&lt;br /&gt;
Hint: to make sense of the ranges and whether your canister is inside or outside some range, the state tool enables the conversion of canister IDs to their hex representation which allows to compare them as numbers. For example, to convert canister ID qoctq-giaaa-aaaaa-aaaea-cai to its hex representation one can:&lt;br /&gt;
&lt;br /&gt;
*Clone the IC repo from https://github.com/dfinity/ic&lt;br /&gt;
*From within the repo, enter the dev container via &amp;lt;code&amp;gt;./gitlab-ci/container/container-run.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
*Run &amp;lt;code&amp;gt;bazel run --config local //rs/state_tool:state-tool -- canister_id_to_hex --canister_id qoctq-giaaa-aaaaa-aaaea-cai&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Step 2: Once the source subnet is halted and the artifacts were obtained ===&lt;br /&gt;
After the proposal for halting the source subnet was accepted and the subnet is halted one can obtain the artifacts needed for [[Verification of Artifacts in Subnet Splitting|end to end verification]] and share it with the community. To do so one can follow the steps below: &lt;br /&gt;
&lt;br /&gt;
# Run through the [[Verification of Artifacts in Subnet Splitting|verification process]] manually to verify whether everything works. Only proceed with subsequent steps if verification matches.&lt;br /&gt;
# Post the artifacts in the thread and link to the verification process again so that community can verify.&lt;br /&gt;
# Continue with subsequent splitting proposals.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting_forum_announcement_template&amp;diff=6524</id>
		<title>Subnet splitting forum announcement template</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting_forum_announcement_template&amp;diff=6524"/>
		<updated>2023-10-30T12:10:37Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page provides a template process that can be used to announce an upcoming series of proposals to [[Subnet splitting|split a subnet]].&lt;br /&gt;
&lt;br /&gt;
===Step 1: Heads up template, before starting the process===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Hello everybody,&lt;br /&gt;
&lt;br /&gt;
We are planning to submit the proposals to split subnet &amp;lt;code&amp;gt;&amp;lt;fill in subnet ID&amp;gt;&amp;lt;/code&amp;gt; because &amp;lt;code&amp;gt;&amp;lt;fill in reason&amp;gt;&amp;lt;/code&amp;gt;. Currently this subnet is assigned the canister ID ranges &amp;lt;code&amp;gt;&amp;lt;fill in ranges; in both representations&amp;gt;&amp;lt;/code&amp;gt;. Ranges are inclusive, i.e. they include the beginning and the end of the range. We are proposing to split off the canisters corresponding to ID ranges &amp;lt;code&amp;gt;&amp;lt;fill in ranges; in both representations&amp;gt;&amp;lt;/code&amp;gt; to a new subnet. The ranges were chosen so that &amp;lt;code&amp;gt;&amp;lt;fill in how ranges were chosen&amp;gt;&amp;lt;/code&amp;gt;. For more details on subnet splitting please refer to [[Subnet splitting|this]] wiki page.&lt;br /&gt;
&lt;br /&gt;
Generally the subnet splitting process is designed in a way that – apart from downtime (&amp;lt;code&amp;gt;&amp;lt;fill in expected downtime if available&amp;gt;&amp;lt;/code&amp;gt;) – it is transparent to canisters provided that they properly handle transient errors when sending canister-to-canister messages. Note that these transient errors routinely occur during normal subnet functioning – so a correct canister implementation should properly handle these errors. In case you are unsure whether your canister properly handles these transient errors you might want to consider stopping it and restarting it after the split is complete. &lt;br /&gt;
&lt;br /&gt;
It will be possible to verify whether the proposed split is authentic by verifying the splitting related artifacts as described [[Verification of Artifacts in Subnet Splitting|here]]. The required artifacts will be obtained after the proposal to halt the source subnet at a CUP boundary was accepted and the subnet successfully halted. They will be published in a follow up post in this thread.&lt;br /&gt;
&lt;br /&gt;
Subsequent updates will also be shared in this thread. &lt;br /&gt;
&lt;br /&gt;
Hint: to make sense of the ranges and whether your canister is inside or outside some range, the state tool enables the conversion of canister IDs to their hex representation which allows to compare them as numbers. For example, to convert canister ID qoctq-giaaa-aaaaa-aaaea-cai to its hex representation one can:&lt;br /&gt;
&lt;br /&gt;
*Clone the IC repo from https://github.com/dfinity/ic&lt;br /&gt;
*From within the repo, enter the dev container via &amp;lt;code&amp;gt;./gitlab-ci/container/container-run.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
*Run &amp;lt;code&amp;gt;bazel run --config local //rs/state_tool:state-tool -- canister_id_to_hex --canister_id qoctq-giaaa-aaaaa-aaaea-cai&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Step 2: Once the source subnet is halted and the artifacts were obtained ===&lt;br /&gt;
After the proposal for halting the source subnet was accepted and the subnet is halted one can obtain the artifacts needed for [[Verification of Artifacts in Subnet Splitting|end to end verification]] and share it with the community. To do so one can follow the steps below: &lt;br /&gt;
&lt;br /&gt;
# Run through the [[Verification of Artifacts in Subnet Splitting|verification process]] manually to verify whether everything works. Only proceed with subsequent steps if verification matches.&lt;br /&gt;
# Post the artifacts in the thread and link to the verification process again so that community can verify.&lt;br /&gt;
# Continue with subsequent splitting proposals.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting_forum_announcement_template&amp;diff=6523</id>
		<title>Subnet splitting forum announcement template</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting_forum_announcement_template&amp;diff=6523"/>
		<updated>2023-10-30T12:10:14Z</updated>

		<summary type="html">&lt;p&gt;David: Create template page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page provides a template process that can be used to announce an upcoming series of proposals to split a subnet.&lt;br /&gt;
&lt;br /&gt;
===Step 1: Heads up template, before starting the process===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Hello everybody,&lt;br /&gt;
&lt;br /&gt;
We are planning to submit the proposals to split subnet &amp;lt;code&amp;gt;&amp;lt;fill in subnet ID&amp;gt;&amp;lt;/code&amp;gt; because &amp;lt;code&amp;gt;&amp;lt;fill in reason&amp;gt;&amp;lt;/code&amp;gt;. Currently this subnet is assigned the canister ID ranges &amp;lt;code&amp;gt;&amp;lt;fill in ranges; in both representations&amp;gt;&amp;lt;/code&amp;gt;. Ranges are inclusive, i.e. they include the beginning and the end of the range. We are proposing to split off the canisters corresponding to ID ranges &amp;lt;code&amp;gt;&amp;lt;fill in ranges; in both representations&amp;gt;&amp;lt;/code&amp;gt; to a new subnet. The ranges were chosen so that &amp;lt;code&amp;gt;&amp;lt;fill in how ranges were chosen&amp;gt;&amp;lt;/code&amp;gt;. For more details on subnet splitting please refer to [[Subnet splitting|this]] wiki page.&lt;br /&gt;
&lt;br /&gt;
Generally the subnet splitting process is designed in a way that – apart from downtime (&amp;lt;code&amp;gt;&amp;lt;fill in expected downtime if available&amp;gt;&amp;lt;/code&amp;gt;) – it is transparent to canisters provided that they properly handle transient errors when sending canister-to-canister messages. Note that these transient errors routinely occur during normal subnet functioning – so a correct canister implementation should properly handle these errors. In case you are unsure whether your canister properly handles these transient errors you might want to consider stopping it and restarting it after the split is complete. &lt;br /&gt;
&lt;br /&gt;
It will be possible to verify whether the proposed split is authentic by verifying the splitting related artifacts as described [[Verification of Artifacts in Subnet Splitting|here]]. The required artifacts will be obtained after the proposal to halt the source subnet at a CUP boundary was accepted and the subnet successfully halted. They will be published in a follow up post in this thread.&lt;br /&gt;
&lt;br /&gt;
Subsequent updates will also be shared in this thread. &lt;br /&gt;
&lt;br /&gt;
Hint: to make sense of the ranges and whether your canister is inside or outside some range, the state tool enables the conversion of canister IDs to their hex representation which allows to compare them as numbers. For example, to convert canister ID qoctq-giaaa-aaaaa-aaaea-cai to its hex representation one can:&lt;br /&gt;
&lt;br /&gt;
*Clone the IC repo from https://github.com/dfinity/ic&lt;br /&gt;
*From within the repo, enter the dev container via &amp;lt;code&amp;gt;./gitlab-ci/container/container-run.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
*Run &amp;lt;code&amp;gt;bazel run --config local //rs/state_tool:state-tool -- canister_id_to_hex --canister_id qoctq-giaaa-aaaaa-aaaea-cai&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Step 2: Once the source subnet is halted and the artifacts were obtained ===&lt;br /&gt;
After the proposal for halting the source subnet was accepted and the subnet is halted one can obtain the artifacts needed for [[Verification of Artifacts in Subnet Splitting|end to end verification]] and share it with the community. To do so one can follow the steps below: &lt;br /&gt;
&lt;br /&gt;
# Run through the [[Verification of Artifacts in Subnet Splitting|verification process]] manually to verify whether everything works. Only proceed with subsequent steps if verification matches.&lt;br /&gt;
# Post the artifacts in the thread and link to the verification process again so that community can verify.&lt;br /&gt;
# Continue with subsequent splitting proposals.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting&amp;diff=6522</id>
		<title>Subnet splitting</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting&amp;diff=6522"/>
		<updated>2023-10-30T11:58:12Z</updated>

		<summary type="html">&lt;p&gt;David: Add link to template page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Subnet splitting steps.png|alt=Subnet splitting steps|thumb|High level overview of subnet splitting steps]]&lt;br /&gt;
The Internet Computer Protocol (ICP) now supports a minimal viable product (MVP) version of subnet splitting. Subnet splitting is a process, where a subset of the canisters from the parent subnet A are split off onto a newly created child subnet B for load balancing purposes and the remaining canisters stay on the trimmed down subnet A’. The MVP process is orchestrated by a series of NNS proposals and, very roughly speaking, consists of the steps visualized on the right. &lt;br /&gt;
&lt;br /&gt;
=== Background ===&lt;br /&gt;
To understand all the details of subnet splitting we need to take a closer look at some parts of the ICP. &lt;br /&gt;
&lt;br /&gt;
==== Checkpoints and Manifests ====&lt;br /&gt;
Up to date nodes persist their state to disk every couple hundreds of rounds (usually 500). A state that is persisted to disk by the protocol is called a checkpoint. Each checkpoint is a directory with the following structure (note that not all of the files shown below are necessarily present in every checkpoint, e.g., writing empty files may be skipped).&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
├── canister_states&lt;br /&gt;
│   ├── &amp;lt;hex(canister_id)&amp;gt;&lt;br /&gt;
│   │  	├── canister.pbuf&lt;br /&gt;
│   │	├── queues.pbuf&lt;br /&gt;
│   │   ├── software.wasm&lt;br /&gt;
│   │   ├── stable_memory.bin&lt;br /&gt;
│   │	└── vmemory_0.bin&lt;br /&gt;
│   ...&lt;br /&gt;
├── ingress_history.pbuf&lt;br /&gt;
├── split_from.pbuf&lt;br /&gt;
├── subnet_queues.pbuf&lt;br /&gt;
└── system_metadata.pbuf&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example, the state of each canister is stored in a separate directory. In contrast, there’s a single file containing the current ingress history (request statuses) of all canisters. &lt;br /&gt;
&lt;br /&gt;
For each checkpoint the protocol will also compute a so-called manifest. Such a manifest consists of the individual hashes of every file and file chunk (the actual contents of files are chunked so that the chunks can be individually transmitted) and a root hash computed from them. The root hash has the property that it is intractable to come up with two different states that hash to the same root hash and can hence be used to verify the integrity of a certain state relative to a root hash. A similar property holds for the file and chunk hashes in the manifest. However, they are redundant for guaranteeing the integrity of the entire state, as they are also covered by the root hash. The reason why they are included in the manifest nevertheless is to allow for efficiently computing state diffs by comparing file/chunk hashes.&lt;br /&gt;
&lt;br /&gt;
==== CUPs ====&lt;br /&gt;
Every checkpoint will also be signed on behalf of the subnet by the protocol. This is done by creating and threshold signing a so-called catch up package (CUP). A CUP includes the root hash of the corresponding manifest as well as all the information that is required by a newly joining and/or behind node to resume execution from the respective checkpoint. The signature on the CUP together with the properties of the hash described above guarantees the authenticity of the state.&lt;br /&gt;
&lt;br /&gt;
==== Remarks ====&lt;br /&gt;
Note that when we point to source code within this article we use links to a specific version of the code to make sure that these links don’t break if the code changes in the future. It is advisable to locate the code that is pointed to in the most recent version and/or the version that is used to verify the artifacts and look at it in this version to avoid missing changes that happened after the publication of this article.&lt;br /&gt;
&lt;br /&gt;
=== Splitting Process ===&lt;br /&gt;
In more detail a subnet split proceeds as follows.&lt;br /&gt;
&lt;br /&gt;
# Create a new halted subnet via NNS proposal. This is the subnet to become subnet B. It should have the same size in terms of number of nodes as the subnet to be split (subnet A) to maintain the same trust assumptions. It is important that it is halted to ensure that it will remain in its genesis state. This is because we will propose to overwrite this subnet’s state later with the split off half of subnet A. &lt;br /&gt;
# Add canisters to be split off to the migration list (NNS proposal). This is to make other subnets aware that canisters are going to be split off. This will help to react appropriately  to messages that are, e.g., expected to come from subnet A according to the routing table but actually come from B or the other way round (note that not all subnets will observe a change of the routing table at the same time). &lt;br /&gt;
# Halt subnet A at the next CUP/checkpoint (NNS proposal) and add keys that grant the entity executing the split read only access to the state (NNS proposal). Generally this proposal is the same as in the conventional subnet recovery case. The only difference is that it won’t instruct the subnet to halt immediately but at the next CUP. This will ensure that we obtain a state that is signed on behalf of the subnet so that the split can be verified by the community.&lt;br /&gt;
# Update the routing table (NNS proposal). As soon as a subnet observes this change it will (among others) start routing messages to split off canisters to B. The reason for why this happens after halting subnet A is to ensure that A doesn’t route any new messages to B until it is unhalted again.&lt;br /&gt;
# Obtain the state of subnet A together with the CUP at the height where it was halted (recall that a read only SSH key was added in step 3). Also obtain a certification of the public key of subnet A issued by the NNS (via a read_state call). Once obtained, split the state into two parts. The first part contains states of canisters that are not split off, as well as the entire subnet-level state of A, such as streams, subnet queues, etc.; this part will be used as the new genesis state of A (we’ll refer to the subnet A with this genesis state as A’). The second state part consists of an empty subnet state plus the canisters split off from A, and will become the new genesis state of subnet B. Both the genesis states of A’ and B will contain the full ingress history, to be pruned in the new subnets’ first execution round. Pruning it beforehand would change the checkpoint file contents and the hashes in the manifest needed for verification of the split would no longer match.&lt;br /&gt;
# Verify whether each file ended up on the expected subnet and whether their hashes still match. The artifacts to perform the verification will be published during a split. A manifest only contains hashes but no file contents, i.e., any subnet or canister data. Comparing the hashes is sufficient because of the properties of the hash described above and the fact that split is done in a way that either (1) file contents are either not modified during splitting, or (2) the content of the files is fully determined by the split’s input parameters. If this step is successful, one knows which root hashes to expect in the recovery proposals for subnets A’ and B in the next steps.&lt;br /&gt;
# Perform a subnet recovery for subnets A’ (resp. A) and B with the states obtained in the previous step (series of NNS proposals). The NNS voters should check that the root hashes of the states match the ones obtained in the verification step (details below) to be sure that the states were only split but not otherwise tampered with. &lt;br /&gt;
# Once it is clear that there are no more messages in any stream to or from subnet A/A’ that may potentially be misrouted, remove the migration list entry (NNS proposal).&lt;br /&gt;
&lt;br /&gt;
To gain confidence that the splitting process doesn’t violate the messaging guarantees that the IC provides to canisters, the above high-level design is accompanied by a [https://github.com/dfinity/tla-models/tree/master/subnet-splitting formal model written in TLA+]. An analysis of the model using the TLC tool found that the design preserves the messaging guarantees.&lt;br /&gt;
&lt;br /&gt;
=== Verification of Artifacts in Subnet Splitting ===&lt;br /&gt;
As mentioned before, the process is orchestrated via NNS proposals and it will be end-to-end verifiable in the sense that the community will be able to verify whether the states recovered onto the new subnets are indeed the two halves of the initial state before voting on the respective proposals. A description on how to perform this verification is provided on the [[Verification of Artifacts in Subnet Splitting]] page.&lt;br /&gt;
&lt;br /&gt;
=== Additional Useful Material ===&lt;br /&gt;
&lt;br /&gt;
* [[Subnet splitting forum announcement template|Template]] for announcing upcoming subnet splitting proposals&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Verification_of_Artifacts_in_Subnet_Splitting&amp;diff=6392</id>
		<title>Verification of Artifacts in Subnet Splitting</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Verification_of_Artifacts_in_Subnet_Splitting&amp;diff=6392"/>
		<updated>2023-09-01T14:42:09Z</updated>

		<summary type="html">&lt;p&gt;David: Add git commit that was used for running the example.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to verify the artifacts during the [[subnet splitting]] process. Note that when we point to source code within this article we use links to a specific version of the code to make sure that these links don&#039;t break if the code changes in the future. It is advisable to locate the code that is pointed to in the most recent version and/or the version that is used to verify the artifacts and look at it in this version to avoid missing changes that happened after the publication of this article.&lt;br /&gt;
&lt;br /&gt;
The first step is to obtain a vanilla clone of the [https://github.com/dfinity/ic/tree/master/rs IC repository] and check out the commit corresponding to the version currently rolled out on mainnet. Once this is done one can enter the dev container via &amp;lt;code&amp;gt;./gitlab-ci/container/container-run.sh&amp;lt;/code&amp;gt;. From within the container one should be able to run the commands as provided below.&lt;br /&gt;
&lt;br /&gt;
===Splitting the State===&lt;br /&gt;
The subnet state is split in such a way that the content of most of the individual checkpoint files does not change and so the file and chunk hashes in the manifest can be directly compared to the corresponding ones in the manifest on the initial parent subnet. For example, a canister is retained without modification on exactly one of the resulting subnets. There are a handful of subnet (as opposed to canister) state files where this is not possible, e.g., subnet queues. For these files it is the case, however, that they will remain on the source subnet in their entirety and the split off subnet will get new files, initialized based on the parameters passed to the splitting logic. So the expected hashes of these new files are also fully determined.&lt;br /&gt;
&lt;br /&gt;
The ingress history is a special case: because ingress messages are essentially tied to their respective target canisters both child subnets need parts of the ingress history. To avoid breaking end to end verifiability here, the full ingress history of the parent subnet will be preserved on both child subnets, keeping the hash of the ingress history file the same on the parent and both child subnets. The unnecessary entries are then pruned in the beginning of the first execution round of each of the child subnets.&lt;br /&gt;
&lt;br /&gt;
===Subnet Splitting Artifacts===&lt;br /&gt;
The artifacts needed to verify a subnet split are as listed below. Artifacts 2-5 will be published (presumably on the forum) during a subnet split so that the community can factor them into their decision on whether to accept the related proposals.&lt;br /&gt;
&lt;br /&gt;
#The NNS public key. &#039;&#039;&#039;This key serves as the root of trust of the validation and will not be distributed as part of the artifacts.&#039;&#039;&#039; We recommend that everyone who wants to verify the artifacts obtains this key out of band. For example the agents and the rosetta node have the mainnet NNS public key baked in and one can obtain them from the respective repositories on GitHub.&lt;br /&gt;
#A certificate from the NNS that includes the public key of the subnet to be split. This will allow to verify the authenticity of the subnet public key relative to the NNS public key.&lt;br /&gt;
#The subnet ID of the subnet to be split. If the certificate from the previous step is deemed valid relative to the NNS public key, this ID can be used to extract the subnet’s public key from the certificate.&lt;br /&gt;
#The CUP of the subnet to be split at the height where it was halted. The CUP signature can be verified using the subnet public key from the previous step and, if verification succeeds, the authentic root hash of the state can be extracted.&lt;br /&gt;
#A textual representation of the manifest of the subnet to be split at the height where it was halted. One can recompute the root hash from the file and chunk hashes in the textual representation of the manifest using the state tool. If the recomputed root hash matches the one extracted from the CUP in the previous step, one knows that the file and chunk hashes in the manifest must be authentic and can hence be used as a basis of comparison, without knowing the actual file contents, i.e., just based on the hashes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The verification procedure of the artifacts can be triggered via the validate subcommand of the subnet splitting tool. We have prepared demo artifacts we obtained from a split that was carried out on a testnet. They can be downloaded [https://drive.google.com/file/d/1xFyStpVce0B6WRgxvfB68EG_KtDPm0N4/view?usp=drive_link here]. In the commands below we assume that you have the IC repository at git commit &amp;lt;code&amp;gt;02b79bcf3cefbb86b5252a2576ccb4dd7e0a9090&amp;lt;/code&amp;gt; checked out and unzipped the artifacts archive into the &amp;lt;code&amp;gt;/tmp/splitting-artifacts&amp;lt;/code&amp;gt; directory.&amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
bazel run //rs/recovery/subnet_splitting:subnet-splitting-tool \&lt;br /&gt;
  --config local \&lt;br /&gt;
  -- validate \&lt;br /&gt;
  --nns-public-key-path /tmp/splitting-artifacts/demo_nns_public_key.pem \&lt;br /&gt;
  --state-tree-path /tmp/splitting-artifacts/demo_state_tree.cbor \&lt;br /&gt;
  --source-subnet-id gmmtp-v5kpc-wdkrx-pni4q-6qwld-ntwrv-kqxva-c3rnm-o6lx3-2eg74-oae \&lt;br /&gt;
  --cup-path /tmp/splitting-artifacts/demo_CUP.pbuf \&lt;br /&gt;
  --state-manifest-path /tmp/splitting-artifacts/demo_source_manifest.txt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;This is the expected output upon a successful validation.&amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
Aug 31 08:15:05.954 INFO Validating State Tree signed by the NNS&lt;br /&gt;
Aug 31 08:15:05.954 INFO Reading the NNS public key from /tmp/splitting-artifacts/demo_nns_public_key.pem&lt;br /&gt;
Aug 31 08:15:05.957 INFO Validation succeeded: extracted authentic subnet key from the NNS state tree.&lt;br /&gt;
Aug 31 08:15:05.957 INFO &lt;br /&gt;
Aug 31 08:15:05.957 INFO Validating Source Subnet&#039;s original CUP&lt;br /&gt;
Aug 31 08:15:05.960 INFO Dealer subnet from the CUP: gmmtp-v5kpc-wdkrx-pni4q-6qwld-ntwrv-kqxva-c3rnm-o6lx3-2eg74-oae&lt;br /&gt;
Aug 31 08:15:05.960 INFO CUP height: 82600&lt;br /&gt;
Aug 31 08:15:05.960 INFO Block time from the CUP: 2023-08-22 09:23:29.206708237 UTC (nanos since unix epoch: 1692696209206708237)&lt;br /&gt;
Aug 31 08:15:05.960 INFO State hash from the CUP: 46fbb99db26d751c5b2b9f35778d5800bae74566f968388fbb0b36226a488416&lt;br /&gt;
Aug 31 08:15:05.967 INFO Validation succeeded: source subnet CUP signature is valid.&lt;br /&gt;
Aug 31 08:15:05.967 INFO &lt;br /&gt;
Aug 31 08:15:05.967 INFO Validating Source Subnet&#039;s original state manifest&lt;br /&gt;
Aug 31 08:15:05.967 INFO state hash from the CUP: 46fbb99db26d751c5b2b9f35778d5800bae74566f968388fbb0b36226a488416&lt;br /&gt;
Aug 31 08:15:05.967 INFO state hash from the State Manifest: 46fbb99db26d751c5b2b9f35778d5800bae74566f968388fbb0b36226a488416&lt;br /&gt;
Aug 31 08:15:05.967 INFO Validation succeeded: recomputed manifest root hash matches the one in the CUP.&lt;br /&gt;
Aug 31 08:15:05.967 INFO&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Computing the expected manifests and root hashes===&lt;br /&gt;
If the verification above succeeds, one can split the authentic manifest of the parent subnet to compute the expected manifests for the child subnets. Before we start with the actual procedure, let’s look at the example manifest of the source subnet in our testnet setting. &amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
MANIFEST VERSION: V3&lt;br /&gt;
FILE TABLE&lt;br /&gt;
    idx     |    size    |                               hash                               |                         path                         &lt;br /&gt;
------------+------------+------------------------------------------------------------------+------------------------------------------------------&lt;br /&gt;
          0 |        216 | 8feafcda70181ac8920dfeba5db951f931f87758ecd5dcd7c920a8468a5bacf9 | canister_states/00000000003000000101/canister.pbuf&lt;br /&gt;
          1 |        532 | cfa0f9a9f833b072aa0c8d1f6eb8bb9334a36168379eaa0925d9013b2d646bbb | canister_states/00000000003000010101/canister.pbuf&lt;br /&gt;
          2 |     459789 | 4840e8e6e379f2108cec9de7ef386ea5f927f687b121b90ae765ad144bc0222a | canister_states/00000000003000010101/software.wasm&lt;br /&gt;
          3 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000010101/stable_memory.bin&lt;br /&gt;
          4 |    1093632 | 1ce90b6ed4c455e1c51c4c2ff466d3c6d49c76a585a014d61eebae6c09b0980b | canister_states/00000000003000010101/vmemory_0.bin&lt;br /&gt;
          5 |       4721 | 346f8b36205998ef3c3c70d5ef64f27096714c83925d98f9e7daf93bf71bd66b | canister_states/00000000003000020101/canister.pbuf&lt;br /&gt;
          6 |     324196 | 73b2c88c9db040794b23535ecd57fa14528d31ada4d9a82fdb6e9cd21cc0c1e6 | canister_states/00000000003000020101/software.wasm&lt;br /&gt;
          7 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000020101/stable_memory.bin&lt;br /&gt;
          8 |    1245184 | 0779cd1b7b5afcac3a2e19070abab88bd637261965c36dd1334928980e7a3744 | canister_states/00000000003000020101/vmemory_0.bin&lt;br /&gt;
          9 |        749 | 493d2f01070bccb63bf75764bcdbc42b1a6946e191029afd74353f339939f51e | canister_states/00000000003000030101/canister.pbuf&lt;br /&gt;
         10 |     968242 | 912f20ef0b5769a55316b7463cc1d55f079a2e91d1d358a5524a28c0782e82b1 | canister_states/00000000003000030101/software.wasm&lt;br /&gt;
         11 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000030101/stable_memory.bin&lt;br /&gt;
         12 |    1458176 | 26f9c82ae827458e84befaa73c42f0cbcf39a2c9dae0c777aa26e7fd6a75db62 | canister_states/00000000003000030101/vmemory_0.bin&lt;br /&gt;
         13 |       2418 | b18a59a56442ddd68d9fcc6fb0103f12c0c0bfd0d01c473711d53b2aff18d596 | system_metadata.pbuf&lt;br /&gt;
CHUNK TABLE&lt;br /&gt;
    idx     |  file_idx  |   offset   |    size    |                               hash                               &lt;br /&gt;
------------+------------+------------+------------+------------------------------------------------------------------&lt;br /&gt;
          0 |          0 |          0 |        216 | 0c6f866e1b60969cc48b4015bb382d45c282b46a82dd24769a15e9628e4d2f62&lt;br /&gt;
          1 |          1 |          0 |        532 | 3b53a0d9cb9e0131a4677d86c237ed06a1aadaf46c480e448a8d78afe9c43635&lt;br /&gt;
          2 |          2 |          0 |     459789 | c470eb0871e137fccfb419b16e2826a63c2a1dba913f5c260ab22ee2958afd28&lt;br /&gt;
          3 |          4 |          0 |    1048576 | de5005242d69024d356dd4d03d8a6879a2b8aadfff6e0f5f80900d45d363305e&lt;br /&gt;
          4 |          4 |    1048576 |      45056 | 1ab510085a2a3090dd1d49c578fceabd56a6433bd75e7e2ecc3107c8f8f208eb&lt;br /&gt;
          5 |          5 |          0 |       4721 | 81af05e10350340c340db100e2b4c1dddc3a7f800ea573ddcef28d562fa70a10&lt;br /&gt;
          6 |          6 |          0 |     324196 | accdd1e66c56db5b5ff0ac24182a10f65559cfd17cc52d86ac3aa6cae5d567b4&lt;br /&gt;
          7 |          8 |          0 |    1048576 | a5d9f9ce12da611d7b170fc3156f2dc1255ee11fb6525ddc4dbc3cb7c5f488e5&lt;br /&gt;
          8 |          8 |    1048576 |     196608 | 9f0bd49a6523364cbc57561e45d67597ef66e29c3fb36273465efd4d210872e8&lt;br /&gt;
          9 |          9 |          0 |        749 | c0e5fae6857b04d035f8fd752505da9f3905514c4d8dcec7650a18e43af61fa5&lt;br /&gt;
         10 |         10 |          0 |     968242 | f431111e6b9a9a074daf350cba6404abc47a993f7ddca098de1819c62d99a515&lt;br /&gt;
         11 |         12 |          0 |    1048576 | de5005242d69024d356dd4d03d8a6879a2b8aadfff6e0f5f80900d45d363305e&lt;br /&gt;
         12 |         12 |    1048576 |     409600 | 93207dec95a267dab702bb1991af9dd9c5df72ba9d87188d37772282d3948632&lt;br /&gt;
         13 |         13 |          0 |       2418 | 679b9963d906d7ecbf818b3e73d8654bd4944d7bd35d6c7c4fde7223bd8d664b&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ROOT HASH: 46fbb99db26d751c5b2b9f35778d5800bae74566f968388fbb0b36226a488416&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;The manifest consists of a file table listing all files and their hashes; and a chunk table enumerating the hashes of the chunks making up the individual files. Concretely, our state contains 4 canisters with IDs &lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;fs35c-jyaaa-aaaab-qaaaa-cai&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;00000000003000000101&amp;lt;/code&amp;gt;),&lt;br /&gt;
*&amp;lt;code&amp;gt;fv23w-eaaaa-aaaab-qaaaq-cai&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;00000000003000010101&amp;lt;/code&amp;gt;),&lt;br /&gt;
*&amp;lt;code&amp;gt;f4zqk-siaaa-aaaab-qaaba-cai&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;00000000003000020101&amp;lt;/code&amp;gt;) and&lt;br /&gt;
*&amp;lt;code&amp;gt;f3yw6-7qaaa-aaaab-qaabq-cai&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;00000000003000030101&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As we can see in the manifest, the first canister doesn’t have a WASM installed and therefore only has a canister.pbuf file, while others do and also have all the other files that are specific to canisters with installed WASMs. &lt;br /&gt;
&lt;br /&gt;
Finally there is also a root hash that covers all the files and chunks (via their hashes). For a correct set of artifacts the root hash should match the root hash in the CUP printed by the verification tool above. As we can see, we have a root hash match for our sample artifacts. More details about how the state is hashed to obtain the manifest can be found [https://github.com/dfinity/ic/blob/a4191e757dbc581cbc8cef9160aea1e852218a1a/rs/types/types/src/state_sync.rs#L3 here].&lt;br /&gt;
&lt;br /&gt;
Now, recall that the hashes in the parent manifest and the subnet splitting parameters fully determine the manifests of the child subnets. This means that one can use the state tool to compute the expected manifests and root hashes for the child subnets. &lt;br /&gt;
&lt;br /&gt;
To continue our example, let us assume we want to split off the last two canisters onto a subnet with the following ID:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;ykq2b-vnsfx-dwzwl-tvwli-ubd4d-lr6br-hpnqf-mettk-jrgtc-n5ioc-mqe&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We can compute the expected manifests with the &amp;lt;code&amp;gt;split_manifest&amp;lt;/code&amp;gt; command of the state tool. While we obviously need to provide the ranges we want to split off, we also need to provide the subnet IDs of the subnets involved in the split, the subnet type and the batch time in nanoseconds. The latter is supposed to be set to the batch time in the CUP as printed in the verification step above. &amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
bazel run //rs/state_tool:state-tool \&lt;br /&gt;
  --config local \&lt;br /&gt;
  -- split_manifest \&lt;br /&gt;
  --path /tmp/splitting-artifacts/demo_source_manifest.txt \&lt;br /&gt;
  --from-subnet gmmtp-v5kpc-wdkrx-pni4q-6qwld-ntwrv-kqxva-c3rnm-o6lx3-2eg74-oae \&lt;br /&gt;
  --to-subnet ykq2b-vnsfx-dwzwl-tvwli-ubd4d-lr6br-hpnqf-mettk-jrgtc-n5ioc-mqe \&lt;br /&gt;
  --subnet-type application \&lt;br /&gt;
  --batch-time-nanos 1692696209206708237 \&lt;br /&gt;
  --migrated-ranges f4zqk-siaaa-aaaab-qaaba-cai:f3yw6-7qaaa-aaaab-qaabq-cai&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Which will output the two manifests. For better readability we present and discuss them individually. The manifest for the first subnet A’ looks as follows:&amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
Subnet gmmtp-v5kpc-wdkrx-pni4q-6qwld-ntwrv-kqxva-c3rnm-o6lx3-2eg74-oae&lt;br /&gt;
--------&lt;br /&gt;
MANIFEST VERSION: V3&lt;br /&gt;
FILE TABLE&lt;br /&gt;
    idx     |    size    |                               hash                               |                         path                         &lt;br /&gt;
------------+------------+------------------------------------------------------------------+------------------------------------------------------&lt;br /&gt;
          0 |        216 | 8feafcda70181ac8920dfeba5db951f931f87758ecd5dcd7c920a8468a5bacf9 | canister_states/00000000003000000101/canister.pbuf&lt;br /&gt;
          1 |        532 | cfa0f9a9f833b072aa0c8d1f6eb8bb9334a36168379eaa0925d9013b2d646bbb | canister_states/00000000003000010101/canister.pbuf&lt;br /&gt;
          2 |     459789 | 4840e8e6e379f2108cec9de7ef386ea5f927f687b121b90ae765ad144bc0222a | canister_states/00000000003000010101/software.wasm&lt;br /&gt;
          3 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000010101/stable_memory.bin&lt;br /&gt;
          4 |    1093632 | 1ce90b6ed4c455e1c51c4c2ff466d3c6d49c76a585a014d61eebae6c09b0980b | canister_states/00000000003000010101/vmemory_0.bin&lt;br /&gt;
          5 |         35 | f590329cc74af3afc36daf577bf29136bc81279401a37175f8a9404277cce4b0 | split_from.pbuf&lt;br /&gt;
          6 |       2418 | b18a59a56442ddd68d9fcc6fb0103f12c0c0bfd0d01c473711d53b2aff18d596 | system_metadata.pbuf&lt;br /&gt;
CHUNK TABLE&lt;br /&gt;
    idx     |  file_idx  |   offset   |    size    |                               hash                               &lt;br /&gt;
------------+------------+------------+------------+------------------------------------------------------------------&lt;br /&gt;
          0 |          0 |          0 |        216 | 0c6f866e1b60969cc48b4015bb382d45c282b46a82dd24769a15e9628e4d2f62&lt;br /&gt;
          1 |          1 |          0 |        532 | 3b53a0d9cb9e0131a4677d86c237ed06a1aadaf46c480e448a8d78afe9c43635&lt;br /&gt;
          2 |          2 |          0 |     459789 | c470eb0871e137fccfb419b16e2826a63c2a1dba913f5c260ab22ee2958afd28&lt;br /&gt;
          3 |          4 |          0 |    1048576 | de5005242d69024d356dd4d03d8a6879a2b8aadfff6e0f5f80900d45d363305e&lt;br /&gt;
          4 |          4 |    1048576 |      45056 | 1ab510085a2a3090dd1d49c578fceabd56a6433bd75e7e2ecc3107c8f8f208eb&lt;br /&gt;
          5 |          5 |          0 |         35 | 51d26533676036bda303d066119cd7499bd39acc5d2d7b420f8c6d95ff7dd79b&lt;br /&gt;
          6 |          6 |          0 |       2418 | 679b9963d906d7ecbf818b3e73d8654bd4944d7bd35d6c7c4fde7223bd8d664b&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ROOT HASH: 8cb1880663d42b8e6c32cc894e7b7bc9304fc0f72bc89db251a81fe15256c1e8&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;We can see that all the files and chunks that are also present in the parent manifest have matching hashes. In addition, we have a new &amp;lt;code&amp;gt;split_from.pbuf&amp;lt;/code&amp;gt; file that carries meta information about the split. It is introduced by the splitting logic and computed from the input parameters (see [https://github.com/dfinity/ic/blob/a4191e757dbc581cbc8cef9160aea1e852218a1a/rs/state_tool/src/commands/split_manifest.rs#L23 here]). Note that this demo state has an empty ingress history and so doesn’t contain a file corresponding to the ingress history. But if it would, the ingress history’s hash should match the one in the original manifest (the ingress history will only be pruned once the split subnets start making progress again). The manifest for the second subnet (B) looks as follows:&amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
Subnet ykq2b-vnsfx-dwzwl-tvwli-ubd4d-lr6br-hpnqf-mettk-jrgtc-n5ioc-mqe&lt;br /&gt;
--------&lt;br /&gt;
MANIFEST VERSION: V3&lt;br /&gt;
FILE TABLE&lt;br /&gt;
    idx     |    size    |                               hash                               |                         path                         &lt;br /&gt;
------------+------------+------------------------------------------------------------------+------------------------------------------------------&lt;br /&gt;
          0 |       4721 | 346f8b36205998ef3c3c70d5ef64f27096714c83925d98f9e7daf93bf71bd66b | canister_states/00000000003000020101/canister.pbuf&lt;br /&gt;
          1 |     324196 | 73b2c88c9db040794b23535ecd57fa14528d31ada4d9a82fdb6e9cd21cc0c1e6 | canister_states/00000000003000020101/software.wasm&lt;br /&gt;
          2 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000020101/stable_memory.bin&lt;br /&gt;
          3 |    1245184 | 0779cd1b7b5afcac3a2e19070abab88bd637261965c36dd1334928980e7a3744 | canister_states/00000000003000020101/vmemory_0.bin&lt;br /&gt;
          4 |        749 | 493d2f01070bccb63bf75764bcdbc42b1a6946e191029afd74353f339939f51e | canister_states/00000000003000030101/canister.pbuf&lt;br /&gt;
          5 |     968242 | 912f20ef0b5769a55316b7463cc1d55f079a2e91d1d358a5524a28c0782e82b1 | canister_states/00000000003000030101/software.wasm&lt;br /&gt;
          6 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000030101/stable_memory.bin&lt;br /&gt;
          7 |    1458176 | 26f9c82ae827458e84befaa73c42f0cbcf39a2c9dae0c777aa26e7fd6a75db62 | canister_states/00000000003000030101/vmemory_0.bin&lt;br /&gt;
          8 |         35 | f590329cc74af3afc36daf577bf29136bc81279401a37175f8a9404277cce4b0 | split_from.pbuf&lt;br /&gt;
          9 |         77 | c29f819c86ba8fe211a272961e15dbe1c87e801619c9391dda36f83fbe4192f2 | system_metadata.pbuf&lt;br /&gt;
CHUNK TABLE&lt;br /&gt;
    idx     |  file_idx  |   offset   |    size    |                               hash                               &lt;br /&gt;
------------+------------+------------+------------+------------------------------------------------------------------&lt;br /&gt;
          0 |          0 |          0 |       4721 | 81af05e10350340c340db100e2b4c1dddc3a7f800ea573ddcef28d562fa70a10&lt;br /&gt;
          1 |          1 |          0 |     324196 | accdd1e66c56db5b5ff0ac24182a10f65559cfd17cc52d86ac3aa6cae5d567b4&lt;br /&gt;
          2 |          3 |          0 |    1048576 | a5d9f9ce12da611d7b170fc3156f2dc1255ee11fb6525ddc4dbc3cb7c5f488e5&lt;br /&gt;
          3 |          3 |    1048576 |     196608 | 9f0bd49a6523364cbc57561e45d67597ef66e29c3fb36273465efd4d210872e8&lt;br /&gt;
          4 |          4 |          0 |        749 | c0e5fae6857b04d035f8fd752505da9f3905514c4d8dcec7650a18e43af61fa5&lt;br /&gt;
          5 |          5 |          0 |     968242 | f431111e6b9a9a074daf350cba6404abc47a993f7ddca098de1819c62d99a515&lt;br /&gt;
          6 |          7 |          0 |    1048576 | de5005242d69024d356dd4d03d8a6879a2b8aadfff6e0f5f80900d45d363305e&lt;br /&gt;
          7 |          7 |    1048576 |     409600 | 93207dec95a267dab702bb1991af9dd9c5df72ba9d87188d37772282d3948632&lt;br /&gt;
          8 |          8 |          0 |         35 | 51d26533676036bda303d066119cd7499bd39acc5d2d7b420f8c6d95ff7dd79b&lt;br /&gt;
          9 |          9 |          0 |         77 | 4c7c38987b8ef245c68643cdc0ae519b8640f4bd260245e2c5b2f3a070abe789&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ROOT HASH: 00bcb78b825ce4146ce42e117d5d7256d2f1e351d974753f8e08b588ed11bcd1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Again, the canister-related file and chunk hashes match the ones of the parent manifest. It again contains a split_from.pbuf file with the same hash as the one in the manifest of the sibling subnet. Finally, it also contains a newly created system metadata file, initialized based on the parameters passed to the splitting tool but otherwise empty (see here for the code).&lt;br /&gt;
&lt;br /&gt;
If all the above properties hold, and the root hashes of these manifests appear as the root hashes of the states in the respective subnet recovery proposals for the child subnets, then one can conclude that the split is authentic and it is safe to vote in favor of the respective proposals from an authenticity point of view.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Verification_of_Artifacts_in_Subnet_Splitting&amp;diff=6390</id>
		<title>Verification of Artifacts in Subnet Splitting</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Verification_of_Artifacts_in_Subnet_Splitting&amp;diff=6390"/>
		<updated>2023-09-01T07:36:33Z</updated>

		<summary type="html">&lt;p&gt;David: Fix link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes how to verify the artifacts during the [[subnet splitting]] process. Note that when we point to source code within this article we use links to a specific version of the code to make sure that these links don&#039;t break if the code changes in the future. It is advisable to locate the code that is pointed to in the most recent version and/or the version that is used to verify the artifacts and look at it in this version to avoid missing changes that happened after the publication of this article.&lt;br /&gt;
&lt;br /&gt;
The first step is to obtain a vanilla clone of the [https://github.com/dfinity/ic/tree/master/rs IC repository] and check out the commit corresponding to the version currently rolled out on mainnet. Once this is done one can enter the dev container via &amp;lt;code&amp;gt;./gitlab-ci/container/container-run.sh&amp;lt;/code&amp;gt;. From within the container one should be able to run the commands as provided below.&lt;br /&gt;
&lt;br /&gt;
===Splitting the State===&lt;br /&gt;
The subnet state is split in such a way that the content of most of the individual checkpoint files does not change and so the file and chunk hashes in the manifest can be directly compared to the corresponding ones in the manifest on the initial parent subnet. For example, a canister is retained without modification on exactly one of the resulting subnets. There are a handful of subnet (as opposed to canister) state files where this is not possible, e.g., subnet queues. For these files it is the case, however, that they will remain on the source subnet in their entirety and the split off subnet will get new files, initialized based on the parameters passed to the splitting logic. So the expected hashes of these new files are also fully determined.&lt;br /&gt;
&lt;br /&gt;
The ingress history is a special case: because ingress messages are essentially tied to their respective target canisters both child subnets need parts of the ingress history. To avoid breaking end to end verifiability here, the full ingress history of the parent subnet will be preserved on both child subnets, keeping the hash of the ingress history file the same on the parent and both child subnets. The unnecessary entries are then pruned in the beginning of the first execution round of each of the child subnets.&lt;br /&gt;
&lt;br /&gt;
===Subnet Splitting Artifacts===&lt;br /&gt;
The artifacts needed to verify a subnet split are as listed below. Artifacts 2-5 will be published (presumably on the forum) during a subnet split so that the community can factor them into their decision on whether to accept the related proposals.&lt;br /&gt;
&lt;br /&gt;
#The NNS public key. &#039;&#039;&#039;This key serves as the root of trust of the validation and will not be distributed as part of the artifacts.&#039;&#039;&#039; We recommend that everyone who wants to verify the artifacts obtains this key out of band. For example the agents and the rosetta node have the mainnet NNS public key baked in and one can obtain them from the respective repositories on GitHub.&lt;br /&gt;
#A certificate from the NNS that includes the public key of the subnet to be split. This will allow to verify the authenticity of the subnet public key relative to the NNS public key.&lt;br /&gt;
#The subnet ID of the subnet to be split. If the certificate from the previous step is deemed valid relative to the NNS public key, this ID can be used to extract the subnet’s public key from the certificate.&lt;br /&gt;
#The CUP of the subnet to be split at the height where it was halted. The CUP signature can be verified using the subnet public key from the previous step and, if verification succeeds, the authentic root hash of the state can be extracted.&lt;br /&gt;
#A textual representation of the manifest of the subnet to be split at the height where it was halted. One can recompute the root hash from the file and chunk hashes in the textual representation of the manifest using the state tool. If the recomputed root hash matches the one extracted from the CUP in the previous step, one knows that the file and chunk hashes in the manifest must be authentic and can hence be used as a basis of comparison, without knowing the actual file contents, i.e., just based on the hashes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The verification procedure of the artifacts can be triggered via the validate subcommand of the subnet splitting tool. We have prepared demo artifacts we obtained from a split that was carried out on a testnet. They can be downloaded here. In the commands below we assume that you download the artifacts into the &amp;lt;code&amp;gt;/tmp/splitting-artifacts&amp;lt;/code&amp;gt; directory.&amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
bazel run //rs/recovery/subnet_splitting:subnet-splitting-tool \&lt;br /&gt;
  --config local \&lt;br /&gt;
  -- validate \&lt;br /&gt;
  --nns-public-key-path /tmp/splitting-artifacts/demo_nns_public_key.pem \&lt;br /&gt;
  --state-tree-path /tmp/splitting-artifacts/demo_state_tree.cbor \&lt;br /&gt;
  --source-subnet-id gmmtp-v5kpc-wdkrx-pni4q-6qwld-ntwrv-kqxva-c3rnm-o6lx3-2eg74-oae \&lt;br /&gt;
  --cup-path /tmp/splitting-artifacts/demo_CUP.pbuf \&lt;br /&gt;
  --state-manifest-path /tmp/splitting-artifacts/demo_source_manifest.txt&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;This is the expected output upon a successful validation.&amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
Aug 31 08:15:05.954 INFO Validating State Tree signed by the NNS&lt;br /&gt;
Aug 31 08:15:05.954 INFO Reading the NNS public key from /tmp/splitting-artifacts/demo_nns_public_key.pem&lt;br /&gt;
Aug 31 08:15:05.957 INFO Validation succeeded: extracted authentic subnet key from the NNS state tree.&lt;br /&gt;
Aug 31 08:15:05.957 INFO &lt;br /&gt;
Aug 31 08:15:05.957 INFO Validating Source Subnet&#039;s original CUP&lt;br /&gt;
Aug 31 08:15:05.960 INFO Dealer subnet from the CUP: gmmtp-v5kpc-wdkrx-pni4q-6qwld-ntwrv-kqxva-c3rnm-o6lx3-2eg74-oae&lt;br /&gt;
Aug 31 08:15:05.960 INFO CUP height: 82600&lt;br /&gt;
Aug 31 08:15:05.960 INFO Block time from the CUP: 2023-08-22 09:23:29.206708237 UTC (nanos since unix epoch: 1692696209206708237)&lt;br /&gt;
Aug 31 08:15:05.960 INFO State hash from the CUP: 46fbb99db26d751c5b2b9f35778d5800bae74566f968388fbb0b36226a488416&lt;br /&gt;
Aug 31 08:15:05.967 INFO Validation succeeded: source subnet CUP signature is valid.&lt;br /&gt;
Aug 31 08:15:05.967 INFO &lt;br /&gt;
Aug 31 08:15:05.967 INFO Validating Source Subnet&#039;s original state manifest&lt;br /&gt;
Aug 31 08:15:05.967 INFO state hash from the CUP: 46fbb99db26d751c5b2b9f35778d5800bae74566f968388fbb0b36226a488416&lt;br /&gt;
Aug 31 08:15:05.967 INFO state hash from the State Manifest: 46fbb99db26d751c5b2b9f35778d5800bae74566f968388fbb0b36226a488416&lt;br /&gt;
Aug 31 08:15:05.967 INFO Validation succeeded: recomputed manifest root hash matches the one in the CUP.&lt;br /&gt;
Aug 31 08:15:05.967 INFO&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Computing the expected manifests and root hashes===&lt;br /&gt;
If the verification above succeeds, one can split the authentic manifest of the parent subnet to compute the expected manifests for the child subnets. Before we start with the actual procedure, let’s look at the example manifest of the source subnet in our testnet setting. &amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
MANIFEST VERSION: V3&lt;br /&gt;
FILE TABLE&lt;br /&gt;
    idx     |    size    |                               hash                               |                         path                         &lt;br /&gt;
------------+------------+------------------------------------------------------------------+------------------------------------------------------&lt;br /&gt;
          0 |        216 | 8feafcda70181ac8920dfeba5db951f931f87758ecd5dcd7c920a8468a5bacf9 | canister_states/00000000003000000101/canister.pbuf&lt;br /&gt;
          1 |        532 | cfa0f9a9f833b072aa0c8d1f6eb8bb9334a36168379eaa0925d9013b2d646bbb | canister_states/00000000003000010101/canister.pbuf&lt;br /&gt;
          2 |     459789 | 4840e8e6e379f2108cec9de7ef386ea5f927f687b121b90ae765ad144bc0222a | canister_states/00000000003000010101/software.wasm&lt;br /&gt;
          3 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000010101/stable_memory.bin&lt;br /&gt;
          4 |    1093632 | 1ce90b6ed4c455e1c51c4c2ff466d3c6d49c76a585a014d61eebae6c09b0980b | canister_states/00000000003000010101/vmemory_0.bin&lt;br /&gt;
          5 |       4721 | 346f8b36205998ef3c3c70d5ef64f27096714c83925d98f9e7daf93bf71bd66b | canister_states/00000000003000020101/canister.pbuf&lt;br /&gt;
          6 |     324196 | 73b2c88c9db040794b23535ecd57fa14528d31ada4d9a82fdb6e9cd21cc0c1e6 | canister_states/00000000003000020101/software.wasm&lt;br /&gt;
          7 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000020101/stable_memory.bin&lt;br /&gt;
          8 |    1245184 | 0779cd1b7b5afcac3a2e19070abab88bd637261965c36dd1334928980e7a3744 | canister_states/00000000003000020101/vmemory_0.bin&lt;br /&gt;
          9 |        749 | 493d2f01070bccb63bf75764bcdbc42b1a6946e191029afd74353f339939f51e | canister_states/00000000003000030101/canister.pbuf&lt;br /&gt;
         10 |     968242 | 912f20ef0b5769a55316b7463cc1d55f079a2e91d1d358a5524a28c0782e82b1 | canister_states/00000000003000030101/software.wasm&lt;br /&gt;
         11 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000030101/stable_memory.bin&lt;br /&gt;
         12 |    1458176 | 26f9c82ae827458e84befaa73c42f0cbcf39a2c9dae0c777aa26e7fd6a75db62 | canister_states/00000000003000030101/vmemory_0.bin&lt;br /&gt;
         13 |       2418 | b18a59a56442ddd68d9fcc6fb0103f12c0c0bfd0d01c473711d53b2aff18d596 | system_metadata.pbuf&lt;br /&gt;
CHUNK TABLE&lt;br /&gt;
    idx     |  file_idx  |   offset   |    size    |                               hash                               &lt;br /&gt;
------------+------------+------------+------------+------------------------------------------------------------------&lt;br /&gt;
          0 |          0 |          0 |        216 | 0c6f866e1b60969cc48b4015bb382d45c282b46a82dd24769a15e9628e4d2f62&lt;br /&gt;
          1 |          1 |          0 |        532 | 3b53a0d9cb9e0131a4677d86c237ed06a1aadaf46c480e448a8d78afe9c43635&lt;br /&gt;
          2 |          2 |          0 |     459789 | c470eb0871e137fccfb419b16e2826a63c2a1dba913f5c260ab22ee2958afd28&lt;br /&gt;
          3 |          4 |          0 |    1048576 | de5005242d69024d356dd4d03d8a6879a2b8aadfff6e0f5f80900d45d363305e&lt;br /&gt;
          4 |          4 |    1048576 |      45056 | 1ab510085a2a3090dd1d49c578fceabd56a6433bd75e7e2ecc3107c8f8f208eb&lt;br /&gt;
          5 |          5 |          0 |       4721 | 81af05e10350340c340db100e2b4c1dddc3a7f800ea573ddcef28d562fa70a10&lt;br /&gt;
          6 |          6 |          0 |     324196 | accdd1e66c56db5b5ff0ac24182a10f65559cfd17cc52d86ac3aa6cae5d567b4&lt;br /&gt;
          7 |          8 |          0 |    1048576 | a5d9f9ce12da611d7b170fc3156f2dc1255ee11fb6525ddc4dbc3cb7c5f488e5&lt;br /&gt;
          8 |          8 |    1048576 |     196608 | 9f0bd49a6523364cbc57561e45d67597ef66e29c3fb36273465efd4d210872e8&lt;br /&gt;
          9 |          9 |          0 |        749 | c0e5fae6857b04d035f8fd752505da9f3905514c4d8dcec7650a18e43af61fa5&lt;br /&gt;
         10 |         10 |          0 |     968242 | f431111e6b9a9a074daf350cba6404abc47a993f7ddca098de1819c62d99a515&lt;br /&gt;
         11 |         12 |          0 |    1048576 | de5005242d69024d356dd4d03d8a6879a2b8aadfff6e0f5f80900d45d363305e&lt;br /&gt;
         12 |         12 |    1048576 |     409600 | 93207dec95a267dab702bb1991af9dd9c5df72ba9d87188d37772282d3948632&lt;br /&gt;
         13 |         13 |          0 |       2418 | 679b9963d906d7ecbf818b3e73d8654bd4944d7bd35d6c7c4fde7223bd8d664b&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ROOT HASH: 46fbb99db26d751c5b2b9f35778d5800bae74566f968388fbb0b36226a488416&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;The manifest consists of a file table listing all files and their hashes; and a chunk table enumerating the hashes of the chunks making up the individual files. Concretely, our state contains 4 canisters with IDs &lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;fs35c-jyaaa-aaaab-qaaaa-cai&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;00000000003000000101&amp;lt;/code&amp;gt;),&lt;br /&gt;
*&amp;lt;code&amp;gt;fv23w-eaaaa-aaaab-qaaaq-cai&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;00000000003000010101&amp;lt;/code&amp;gt;),&lt;br /&gt;
*&amp;lt;code&amp;gt;f4zqk-siaaa-aaaab-qaaba-cai&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;00000000003000020101&amp;lt;/code&amp;gt;) and&lt;br /&gt;
*&amp;lt;code&amp;gt;f3yw6-7qaaa-aaaab-qaabq-cai&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;00000000003000030101&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As we can see in the manifest, the first canister doesn’t have a WASM installed and therefore only has a canister.pbuf file, while others do and also have all the other files that are specific to canisters with installed WASMs. &lt;br /&gt;
&lt;br /&gt;
Finally there is also a root hash that covers all the files and chunks (via their hashes). For a correct set of artifacts the root hash should match the root hash in the CUP printed by the verification tool above. As we can see, we have a root hash match for our sample artifacts. More details about how the state is hashed to obtain the manifest can be found [https://github.com/dfinity/ic/blob/a4191e757dbc581cbc8cef9160aea1e852218a1a/rs/types/types/src/state_sync.rs#L3 here].&lt;br /&gt;
&lt;br /&gt;
Now, recall that the hashes in the parent manifest and the subnet splitting parameters fully determine the manifests of the child subnets. This means that one can use the state tool to compute the expected manifests and root hashes for the child subnets. &lt;br /&gt;
&lt;br /&gt;
To continue our example, let us assume we want to split off the last two canisters onto a subnet with the following ID:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;ykq2b-vnsfx-dwzwl-tvwli-ubd4d-lr6br-hpnqf-mettk-jrgtc-n5ioc-mqe&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We can compute the expected manifests with the &amp;lt;code&amp;gt;split_manifest&amp;lt;/code&amp;gt; command of the state tool. While we obviously need to provide the ranges we want to split off, we also need to provide the subnet IDs of the subnets involved in the split, the subnet type and the batch time in nanoseconds. The latter is supposed to be set to the batch time in the CUP as printed in the verification step above. &amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
bazel run //rs/state_tool:state-tool \&lt;br /&gt;
  --config local \&lt;br /&gt;
  -- split_manifest \&lt;br /&gt;
  --path /tmp/splitting-artifacts/demo_source_manifest.txt \&lt;br /&gt;
  --from-subnet gmmtp-v5kpc-wdkrx-pni4q-6qwld-ntwrv-kqxva-c3rnm-o6lx3-2eg74-oae \&lt;br /&gt;
  --to-subnet ykq2b-vnsfx-dwzwl-tvwli-ubd4d-lr6br-hpnqf-mettk-jrgtc-n5ioc-mqe \&lt;br /&gt;
  --subnet-type application \&lt;br /&gt;
  --batch-time-nanos 1692696209206708237 \&lt;br /&gt;
  --migrated-ranges f4zqk-siaaa-aaaab-qaaba-cai:f3yw6-7qaaa-aaaab-qaabq-cai&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Which will output the two manifests. For better readability we present and discuss them individually. The manifest for the first subnet A’ looks as follows:&amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
Subnet gmmtp-v5kpc-wdkrx-pni4q-6qwld-ntwrv-kqxva-c3rnm-o6lx3-2eg74-oae&lt;br /&gt;
--------&lt;br /&gt;
MANIFEST VERSION: V3&lt;br /&gt;
FILE TABLE&lt;br /&gt;
    idx     |    size    |                               hash                               |                         path                         &lt;br /&gt;
------------+------------+------------------------------------------------------------------+------------------------------------------------------&lt;br /&gt;
          0 |        216 | 8feafcda70181ac8920dfeba5db951f931f87758ecd5dcd7c920a8468a5bacf9 | canister_states/00000000003000000101/canister.pbuf&lt;br /&gt;
          1 |        532 | cfa0f9a9f833b072aa0c8d1f6eb8bb9334a36168379eaa0925d9013b2d646bbb | canister_states/00000000003000010101/canister.pbuf&lt;br /&gt;
          2 |     459789 | 4840e8e6e379f2108cec9de7ef386ea5f927f687b121b90ae765ad144bc0222a | canister_states/00000000003000010101/software.wasm&lt;br /&gt;
          3 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000010101/stable_memory.bin&lt;br /&gt;
          4 |    1093632 | 1ce90b6ed4c455e1c51c4c2ff466d3c6d49c76a585a014d61eebae6c09b0980b | canister_states/00000000003000010101/vmemory_0.bin&lt;br /&gt;
          5 |         35 | f590329cc74af3afc36daf577bf29136bc81279401a37175f8a9404277cce4b0 | split_from.pbuf&lt;br /&gt;
          6 |       2418 | b18a59a56442ddd68d9fcc6fb0103f12c0c0bfd0d01c473711d53b2aff18d596 | system_metadata.pbuf&lt;br /&gt;
CHUNK TABLE&lt;br /&gt;
    idx     |  file_idx  |   offset   |    size    |                               hash                               &lt;br /&gt;
------------+------------+------------+------------+------------------------------------------------------------------&lt;br /&gt;
          0 |          0 |          0 |        216 | 0c6f866e1b60969cc48b4015bb382d45c282b46a82dd24769a15e9628e4d2f62&lt;br /&gt;
          1 |          1 |          0 |        532 | 3b53a0d9cb9e0131a4677d86c237ed06a1aadaf46c480e448a8d78afe9c43635&lt;br /&gt;
          2 |          2 |          0 |     459789 | c470eb0871e137fccfb419b16e2826a63c2a1dba913f5c260ab22ee2958afd28&lt;br /&gt;
          3 |          4 |          0 |    1048576 | de5005242d69024d356dd4d03d8a6879a2b8aadfff6e0f5f80900d45d363305e&lt;br /&gt;
          4 |          4 |    1048576 |      45056 | 1ab510085a2a3090dd1d49c578fceabd56a6433bd75e7e2ecc3107c8f8f208eb&lt;br /&gt;
          5 |          5 |          0 |         35 | 51d26533676036bda303d066119cd7499bd39acc5d2d7b420f8c6d95ff7dd79b&lt;br /&gt;
          6 |          6 |          0 |       2418 | 679b9963d906d7ecbf818b3e73d8654bd4944d7bd35d6c7c4fde7223bd8d664b&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ROOT HASH: 8cb1880663d42b8e6c32cc894e7b7bc9304fc0f72bc89db251a81fe15256c1e8&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;We can see that all the files and chunks that are also present in the parent manifest have matching hashes. In addition, we have a new &amp;lt;code&amp;gt;split_from.pbuf&amp;lt;/code&amp;gt; file that carries meta information about the split. It is introduced by the splitting logic and computed from the input parameters (see [https://github.com/dfinity/ic/blob/a4191e757dbc581cbc8cef9160aea1e852218a1a/rs/state_tool/src/commands/split_manifest.rs#L23 here]). Note that this demo state has an empty ingress history and so doesn’t contain a file corresponding to the ingress history. But if it would, the ingress history’s hash should match the one in the original manifest (the ingress history will only be pruned once the split subnets start making progress again). The manifest for the second subnet (B) looks as follows:&amp;lt;syntaxhighlight lang=&amp;quot;shell-session&amp;quot;&amp;gt;&lt;br /&gt;
Subnet ykq2b-vnsfx-dwzwl-tvwli-ubd4d-lr6br-hpnqf-mettk-jrgtc-n5ioc-mqe&lt;br /&gt;
--------&lt;br /&gt;
MANIFEST VERSION: V3&lt;br /&gt;
FILE TABLE&lt;br /&gt;
    idx     |    size    |                               hash                               |                         path                         &lt;br /&gt;
------------+------------+------------------------------------------------------------------+------------------------------------------------------&lt;br /&gt;
          0 |       4721 | 346f8b36205998ef3c3c70d5ef64f27096714c83925d98f9e7daf93bf71bd66b | canister_states/00000000003000020101/canister.pbuf&lt;br /&gt;
          1 |     324196 | 73b2c88c9db040794b23535ecd57fa14528d31ada4d9a82fdb6e9cd21cc0c1e6 | canister_states/00000000003000020101/software.wasm&lt;br /&gt;
          2 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000020101/stable_memory.bin&lt;br /&gt;
          3 |    1245184 | 0779cd1b7b5afcac3a2e19070abab88bd637261965c36dd1334928980e7a3744 | canister_states/00000000003000020101/vmemory_0.bin&lt;br /&gt;
          4 |        749 | 493d2f01070bccb63bf75764bcdbc42b1a6946e191029afd74353f339939f51e | canister_states/00000000003000030101/canister.pbuf&lt;br /&gt;
          5 |     968242 | 912f20ef0b5769a55316b7463cc1d55f079a2e91d1d358a5524a28c0782e82b1 | canister_states/00000000003000030101/software.wasm&lt;br /&gt;
          6 |          0 | 981305d7c0b2ace0f53fe822f4075278fa28511e8c34e70f37fd8425af659b36 | canister_states/00000000003000030101/stable_memory.bin&lt;br /&gt;
          7 |    1458176 | 26f9c82ae827458e84befaa73c42f0cbcf39a2c9dae0c777aa26e7fd6a75db62 | canister_states/00000000003000030101/vmemory_0.bin&lt;br /&gt;
          8 |         35 | f590329cc74af3afc36daf577bf29136bc81279401a37175f8a9404277cce4b0 | split_from.pbuf&lt;br /&gt;
          9 |         77 | c29f819c86ba8fe211a272961e15dbe1c87e801619c9391dda36f83fbe4192f2 | system_metadata.pbuf&lt;br /&gt;
CHUNK TABLE&lt;br /&gt;
    idx     |  file_idx  |   offset   |    size    |                               hash                               &lt;br /&gt;
------------+------------+------------+------------+------------------------------------------------------------------&lt;br /&gt;
          0 |          0 |          0 |       4721 | 81af05e10350340c340db100e2b4c1dddc3a7f800ea573ddcef28d562fa70a10&lt;br /&gt;
          1 |          1 |          0 |     324196 | accdd1e66c56db5b5ff0ac24182a10f65559cfd17cc52d86ac3aa6cae5d567b4&lt;br /&gt;
          2 |          3 |          0 |    1048576 | a5d9f9ce12da611d7b170fc3156f2dc1255ee11fb6525ddc4dbc3cb7c5f488e5&lt;br /&gt;
          3 |          3 |    1048576 |     196608 | 9f0bd49a6523364cbc57561e45d67597ef66e29c3fb36273465efd4d210872e8&lt;br /&gt;
          4 |          4 |          0 |        749 | c0e5fae6857b04d035f8fd752505da9f3905514c4d8dcec7650a18e43af61fa5&lt;br /&gt;
          5 |          5 |          0 |     968242 | f431111e6b9a9a074daf350cba6404abc47a993f7ddca098de1819c62d99a515&lt;br /&gt;
          6 |          7 |          0 |    1048576 | de5005242d69024d356dd4d03d8a6879a2b8aadfff6e0f5f80900d45d363305e&lt;br /&gt;
          7 |          7 |    1048576 |     409600 | 93207dec95a267dab702bb1991af9dd9c5df72ba9d87188d37772282d3948632&lt;br /&gt;
          8 |          8 |          0 |         35 | 51d26533676036bda303d066119cd7499bd39acc5d2d7b420f8c6d95ff7dd79b&lt;br /&gt;
          9 |          9 |          0 |         77 | 4c7c38987b8ef245c68643cdc0ae519b8640f4bd260245e2c5b2f3a070abe789&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ROOT HASH: 00bcb78b825ce4146ce42e117d5d7256d2f1e351d974753f8e08b588ed11bcd1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Again, the canister-related file and chunk hashes match the ones of the parent manifest. It again contains a split_from.pbuf file with the same hash as the one in the manifest of the sibling subnet. Finally, it also contains a newly created system metadata file, initialized based on the parameters passed to the splitting tool but otherwise empty (see here for the code).&lt;br /&gt;
&lt;br /&gt;
If all the above properties hold, and the root hashes of these manifests appear as the root hashes of the states in the respective subnet recovery proposals for the child subnets, then one can conclude that the split is authentic and it is safe to vote in favor of the respective proposals from an authenticity point of view.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting&amp;diff=6387</id>
		<title>Subnet splitting</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting&amp;diff=6387"/>
		<updated>2023-08-31T13:21:26Z</updated>

		<summary type="html">&lt;p&gt;David: Subnet splitting page add text&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Subnet splitting steps.png|alt=Subnet splitting steps|thumb|High level overview of subnet splitting steps]]&lt;br /&gt;
The Internet Computer Protocol (ICP) now supports a minimal viable product (MVP) version of subnet splitting. Subnet splitting is a process, where a subset of the canisters from the parent subnet A are split off onto a newly created child subnet B for load balancing purposes and the remaining canisters stay on the trimmed down subnet A’. The MVP process is orchestrated by a series of NNS proposals and, very roughly speaking, consists of the steps visualized on the right.&lt;br /&gt;
&lt;br /&gt;
=== Background ===&lt;br /&gt;
To understand all the details of subnet splitting we need to take a closer look at some parts of the ICP. &lt;br /&gt;
&lt;br /&gt;
==== Checkpoints and Manifests ====&lt;br /&gt;
Up to date nodes persist their state to disk every couple hundreds of rounds (usually 500). A state that is persisted to disk by the protocol is called a checkpoint. Each checkpoint is a directory with the following structure (note that not all of the files shown below are necessarily present in every checkpoint, e.g., writing empty files may be skipped).&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
├── canister_states&lt;br /&gt;
│   ├── &amp;lt;hex(canister_id)&amp;gt;&lt;br /&gt;
│   │  	├── canister.pbuf&lt;br /&gt;
│   │	├── queues.pbuf&lt;br /&gt;
│   │   ├── software.wasm&lt;br /&gt;
│   │   ├── stable_memory.bin&lt;br /&gt;
│   │	└── vmemory_0.bin&lt;br /&gt;
│   ...&lt;br /&gt;
├── ingress_history.pbuf&lt;br /&gt;
├── split_from.pbuf&lt;br /&gt;
├── subnet_queues.pbuf&lt;br /&gt;
└── system_metadata.pbuf&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example, the state of each canister is stored in a separate directory. In contrast, there’s a single file containing the current ingress history (request statuses) of all canisters. &lt;br /&gt;
&lt;br /&gt;
For each checkpoint the protocol will also compute a so-called manifest. Such a manifest consists of the individual hashes of every file and file chunk (the actual contents of files are chunked so that the chunks can be individually transmitted) and a root hash computed from them. The root hash has the property that it is intractable to come up with two different states that hash to the same root hash and can hence be used to verify the integrity of a certain state relative to a root hash. A similar property holds for the file and chunk hashes in the manifest. However, they are redundant for guaranteeing the integrity of the entire state, as they are also covered by the root hash. The reason why they are included in the manifest nevertheless is to allow for efficiently computing state diffs by comparing file/chunk hashes.&lt;br /&gt;
&lt;br /&gt;
==== CUPs ====&lt;br /&gt;
Every checkpoint will also be signed on behalf of the subnet by the protocol. This is done by creating and threshold signing a so-called catch up package (CUP). A CUP includes the root hash of the corresponding manifest as well as all the information that is required by a newly joining and/or behind node to resume execution from the respective checkpoint. The signature on the CUP together with the properties of the hash described above guarantees the authenticity of the state.&lt;br /&gt;
&lt;br /&gt;
==== Remarks ====&lt;br /&gt;
Note that when we point to source code within this article we use links to a specific version of the code to make sure that these links don’t break if the code changes in the future. It is advisable to locate the code that is pointed to in the most recent version and/or the version that is used to verify the artifacts and look at it in this version to avoid missing changes that happened after the publication of this article.&lt;br /&gt;
&lt;br /&gt;
=== Splitting Process ===&lt;br /&gt;
In more detail a subnet split proceeds as follows.&lt;br /&gt;
&lt;br /&gt;
# Create a new halted subnet via NNS proposal. This is the subnet to become subnet B. It should have the same size in terms of number of nodes as the subnet to be split (subnet A) to maintain the same trust assumptions. It is important that it is halted to ensure that it will remain in its genesis state. This is because we will propose to overwrite this subnet’s state later with the split off half of subnet A. &lt;br /&gt;
# Add canisters to be split off to the migration list (NNS proposal). This is to make other subnets aware that canisters are going to be split off. This will help to react appropriately  to messages that are, e.g., expected to come from subnet A according to the routing table but actually come from B or the other way round (note that not all subnets will observe a change of the routing table at the same time). &lt;br /&gt;
# Halt subnet A at the next CUP/checkpoint (NNS proposal) and add keys that grant the entity executing the split read only access to the state (NNS proposal). Generally this proposal is the same as in the conventional subnet recovery case. The only difference is that it won’t instruct the subnet to halt immediately but at the next CUP. This will ensure that we obtain a state that is signed on behalf of the subnet so that the split can be verified by the community.&lt;br /&gt;
# Update the routing table (NNS proposal). As soon as a subnet observes this change it will (among others) start routing messages to split off canisters to B. The reason for why this happens after halting subnet A is to ensure that A doesn’t route any new messages to B until it is unhalted again.&lt;br /&gt;
# Obtain the state of subnet A together with the CUP at the height where it was halted (recall that a read only SSH key was added in step 3). Also obtain a certification of the public key of subnet A issued by the NNS (via a read_state call). Once obtained, split the state into two parts. The first part contains states of canisters that are not split off, as well as the entire subnet-level state of A, such as streams, subnet queues, etc.; this part will be used as the new genesis state of A (we’ll refer to the subnet A with this genesis state as A’). The second state part consists of an empty subnet state plus the canisters split off from A, and will become the new genesis state of subnet B. Both the genesis states of A’ and B will contain the full ingress history, to be pruned in the new subnets’ first execution round. Pruning it beforehand would change the checkpoint file contents and the hashes in the manifest needed for verification of the split would no longer match.&lt;br /&gt;
# Verify whether each file ended up on the expected subnet and whether their hashes still match. The artifacts to perform the verification will be published during a split. A manifest only contains hashes but no file contents, i.e., any subnet or canister data. Comparing the hashes is sufficient because of the properties of the hash described above and the fact that split is done in a way that either (1) file contents are either not modified during splitting, or (2) the content of the files is fully determined by the split’s input parameters. If this step is successful, one knows which root hashes to expect in the recovery proposals for subnets A’ and B in the next steps.&lt;br /&gt;
# Perform a subnet recovery for subnets A’ (resp. A) and B with the states obtained in the previous step (series of NNS proposals). The NNS voters should check that the root hashes of the states match the ones obtained in the verification step (details below) to be sure that the states were only split but not otherwise tampered with. &lt;br /&gt;
# Once it is clear that there are no more messages in any stream to or from subnet A/A’ that may potentially be misrouted, remove the migration list entry (NNS proposal).&lt;br /&gt;
&lt;br /&gt;
To gain confidence that the splitting process doesn’t violate the messaging guarantees that the IC provides to canisters, the above high-level design is accompanied by a [https://github.com/dfinity/tla-models/tree/master/subnet-splitting formal model written in TLA+]. An analysis of the model using the TLC tool found that the design preserves the messaging guarantees.&lt;br /&gt;
&lt;br /&gt;
=== Verification of Artifacts in Subnet Splitting ===&lt;br /&gt;
As mentioned before, the process is orchestrated via NNS proposals and it will be end-to-end verifiable, in the sense that the community will be able to verify whether the states recovered onto the new subnets are indeed the two halves of the initial state before voting on the respective proposals. A description on how to perform this verification is provided on the [[Verification of Artifacts in Subnet Splitting]] page.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting&amp;diff=6386</id>
		<title>Subnet splitting</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting&amp;diff=6386"/>
		<updated>2023-08-31T13:19:03Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Subnet splitting steps.png|alt=Subnet splitting steps|thumb|High level overview of subnet splitting steps]]&lt;br /&gt;
The Internet Computer Protocol (ICP) now supports a minimal viable product (MVP) version of subnet splitting. Subnet splitting is a process, where a subset of the canisters from the parent subnet A are split off onto a newly created child subnet B for load balancing purposes and the remaining canisters stay on the trimmed down subnet A’. The MVP process is orchestrated by a series of NNS proposals and, very roughly speaking, consists of the steps visualized on the right.&lt;br /&gt;
&lt;br /&gt;
=== Background ===&lt;br /&gt;
To understand all the details of subnet splitting we need to take a closer look at some parts of the ICP. &lt;br /&gt;
&lt;br /&gt;
==== Checkpoints and Manifests ====&lt;br /&gt;
Up to date nodes persist their state to disk every couple hundreds of rounds (usually 500). A state that is persisted to disk by the protocol is called a checkpoint. Each checkpoint is a directory with the following structure (note that not all of the files shown below are necessarily present in every checkpoint, e.g., writing empty files may be skipped).&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
├── canister_states&lt;br /&gt;
│   ├── &amp;lt;hex(canister_id)&amp;gt;&lt;br /&gt;
│   │  	├── canister.pbuf&lt;br /&gt;
│   │	├── queues.pbuf&lt;br /&gt;
│   │   ├── software.wasm&lt;br /&gt;
│   │   ├── stable_memory.bin&lt;br /&gt;
│   │	└── vmemory_0.bin&lt;br /&gt;
│   ...&lt;br /&gt;
├── ingress_history.pbuf&lt;br /&gt;
├── split_from.pbuf&lt;br /&gt;
├── subnet_queues.pbuf&lt;br /&gt;
└── system_metadata.pbuf&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example, the state of each canister is stored in a separate directory. In contrast, there’s a single file containing the current ingress history (request statuses) of all canisters. &lt;br /&gt;
&lt;br /&gt;
For each checkpoint the protocol will also compute a so-called manifest. Such a manifest consists of the individual hashes of every file and file chunk (the actual contents of files are chunked so that the chunks can be individually transmitted) and a root hash computed from them. The root hash has the property that it is intractable to come up with two different states that hash to the same root hash and can hence be used to verify the integrity of a certain state relative to a root hash. A similar property holds for the file and chunk hashes in the manifest. However, they are redundant for guaranteeing the integrity of the entire state, as they are also covered by the root hash. The reason why they are included in the manifest nevertheless is to allow for efficiently computing state diffs by comparing file/chunk hashes.&lt;br /&gt;
&lt;br /&gt;
==== CUPs ====&lt;br /&gt;
Every checkpoint will also be signed on behalf of the subnet by the protocol. This is done by creating and threshold signing a so-called catch up package (CUP). A CUP includes the root hash of the corresponding manifest as well as all the information that is required by a newly joining and/or behind node to resume execution from the respective checkpoint. The signature on the CUP together with the properties of the hash described above guarantees the authenticity of the state.&lt;br /&gt;
&lt;br /&gt;
==== Remarks ====&lt;br /&gt;
Note that when we point to source code within this article we use links to a specific version of the code to make sure that these links don’t break if the code changes in the future. It is advisable to locate the code that is pointed to in the most recent version and/or the version that is used to verify the artifacts and look at it in this version to avoid missing changes that happened after the publication of this article.&lt;br /&gt;
&lt;br /&gt;
=== Verification of Artifacts in Subnet Splitting ===&lt;br /&gt;
As mentioned before, the process is orchestrated via NNS proposals and it will be end-to-end verifiable, in the sense that the community will be able to verify whether the states recovered onto the new subnets are indeed the two halves of the initial state before voting on the respective proposals. A description on how to perform this verification is provided on the [[Verification of Artifacts in Subnet Splitting]] page.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting&amp;diff=6385</id>
		<title>Subnet splitting</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=Subnet_splitting&amp;diff=6385"/>
		<updated>2023-08-31T13:17:17Z</updated>

		<summary type="html">&lt;p&gt;David: First version of page + intro&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Subnet splitting steps.png|alt=Subnet splitting steps|thumb|High level overview of subnet splitting steps]]&lt;br /&gt;
The Internet Computer Protocol (ICP) now supports a minimal viable product (MVP) version of subnet splitting. Subnet splitting is a process, where a subset of the canisters from the parent subnet A are split off onto a newly created child subnet B for load balancing purposes and the remaining canisters stay on the trimmed down subnet A’. The MVP process is orchestrated by a series of NNS proposals and, very roughly speaking, consists of the steps visualized on the right.&lt;br /&gt;
&lt;br /&gt;
=== Background ===&lt;br /&gt;
To understand all the details of subnet splitting we need to take a closer look at some parts of the ICP. &lt;br /&gt;
&lt;br /&gt;
==== Checkpoints and Manifests ====&lt;br /&gt;
Up to date nodes persist their state to disk every couple hundreds of rounds (usually 500). A state that is persisted to disk by the protocol is called a checkpoint. Each checkpoint is a directory with the following structure (note that not all of the files shown below are necessarily present in every checkpoint, e.g., writing empty files may be skipped).&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
├── canister_states&lt;br /&gt;
│   ├── &amp;lt;hex(canister_id)&amp;gt;&lt;br /&gt;
│   │  	├── canister.pbuf&lt;br /&gt;
│   │	├── queues.pbuf&lt;br /&gt;
│   │   ├── software.wasm&lt;br /&gt;
│   │   ├── stable_memory.bin&lt;br /&gt;
│   │	└── vmemory_0.bin&lt;br /&gt;
│   ...&lt;br /&gt;
├── ingress_history.pbuf&lt;br /&gt;
├── split_from.pbuf&lt;br /&gt;
├── subnet_queues.pbuf&lt;br /&gt;
└── system_metadata.pbuf&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;For example, the state of each canister is stored in a separate directory. In contrast, there’s a single file containing the current ingress history (request statuses) of all canisters. &lt;br /&gt;
&lt;br /&gt;
For each checkpoint the protocol will also compute a so-called manifest. Such a manifest consists of the individual hashes of every file and file chunk (the actual contents of files are chunked so that the chunks can be individually transmitted) and a root hash computed from them. The root hash has the property that it is intractable to come up with two different states that hash to the same root hash and can hence be used to verify the integrity of a certain state relative to a root hash. A similar property holds for the file and chunk hashes in the manifest. However, they are redundant for guaranteeing the integrity of the entire state, as they are also covered by the root hash. The reason why they are included in the manifest nevertheless is to allow for efficiently computing state diffs by comparing file/chunk hashes.&lt;br /&gt;
&lt;br /&gt;
==== CUPs ====&lt;br /&gt;
Every checkpoint will also be signed on behalf of the subnet by the protocol. This is done by creating and threshold signing a so-called catch up package (CUP). A CUP includes the root hash of the corresponding manifest as well as all the information that is required by a newly joining and/or behind node to resume execution from the respective checkpoint. The signature on the CUP together with the properties of the hash described above guarantees the authenticity of the state.&lt;br /&gt;
&lt;br /&gt;
==== Remarks ====&lt;br /&gt;
Note that when we point to source code within this article we use links to a specific version of the code to make sure that these links don’t break if the code changes in the future. It is advisable to locate the code that is pointed to in the most recent version and/or the version that is used to verify the artifacts and look at it in this version to avoid missing changes that happened after the publication of this article.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=File:Subnet_splitting_steps.png&amp;diff=6384</id>
		<title>File:Subnet splitting steps.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=File:Subnet_splitting_steps.png&amp;diff=6384"/>
		<updated>2023-08-31T13:11:56Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;High level overview of subnet splitting steps&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_architecture_overview&amp;diff=6383</id>
		<title>IC architecture overview</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_architecture_overview&amp;diff=6383"/>
		<updated>2023-08-31T13:09:26Z</updated>

		<summary type="html">&lt;p&gt;David: Add link to subnet splitting page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[File:IC-protocol-stack.png|500px]]&lt;br /&gt;
&lt;br /&gt;
As illustrated in the above diagram, the Internet Computer Protocol consists of four layers:&lt;br /&gt;
* [[IC execution layer]]&lt;br /&gt;
* [[IC message routing layer]]&lt;br /&gt;
* [[IC consensus layer]] &lt;br /&gt;
* [[IC P2P (peer to peer) layer]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Description of specific features:&lt;br /&gt;
*[[IC Smart Contract Memory]]&lt;br /&gt;
*[[Bitcoin integration]]&lt;br /&gt;
*[[HTTPS outcalls]]&lt;br /&gt;
* [[Subnet splitting]]&lt;br /&gt;
&lt;br /&gt;
Canisters serving the web:&lt;br /&gt;
* [[HTTP asset certification]]&lt;br /&gt;
* [[Boundary Nodes]]&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* &#039;&#039;&#039;The Internet Computer project website (hosted on the IC): [https://internetcomputer.org/ internetcomputer.org]&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3417</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3417"/>
		<updated>2022-11-04T06:49:36Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The VSR for cross-net messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_xnet : CanonicalState × Batch → Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function that determines the indices of the messages in the individual substreams contained in &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt; to be inducted.&lt;br /&gt;
&lt;br /&gt;
We require that the implementation of the VSR (or the layer above) makes sure that all reply messages are accepted by the VSR. Formally this means that for any valid State-Batch combination &amp;lt;code&amp;gt;(s, b)&amp;lt;/code&amp;gt; it holds that for all &amp;lt;code&amp;gt;(subnet, index)&amp;lt;/code&amp;gt; so that &amp;lt;code&amp;gt;b.xnet_payload[subnet].msgs[index]&amp;lt;/code&amp;gt; is a reply message that &amp;lt;code&amp;gt;(subnet, index) ∈ vsr_check_xnet(s, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Based on this rule one can straight-forwardly define the interface behavior of the VSR.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).xnet :=&lt;br /&gt;
  { (index ↦ msg) |&lt;br /&gt;
      (index ↦ msg) ∈ batch.xnet_payload.msgs ∧&lt;br /&gt;
      index ∈ vsr_check_xnet(state, batch)&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
VSR(state, batch).signals :=&lt;br /&gt;
    { (concatenate(subnet, index) ↦ ACCEPT) |&lt;br /&gt;
      (subnet ↦ stream) ∈ batch.xnet_payload ∧&lt;br /&gt;
      (index ↦ msg) ∈ stream.msgs ∧&lt;br /&gt;
      (subnet, index) ∈ vsr_check_xnet(state, batch)&lt;br /&gt;
    }&lt;br /&gt;
  ∪ { (concatenate(subnet, index) ↦ REJECT) |&lt;br /&gt;
      (subnet ↦ stream) ∈ batch.xnet_payload ∧&lt;br /&gt;
      (index ↦ msg) ∈ stream.msgs ∧&lt;br /&gt;
      (subnet, index) ∉ vsr_check_xnet(state, batch)&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;br /&gt;
&lt;br /&gt;
== XNet Transfer ==&lt;br /&gt;
After calling &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt; at the end of a deterministic processing cycle, the state manager will take care of getting the committed state certified. Once certification is complete, the certified stream slices can be made available to block makers on other subnets. The &amp;lt;code&amp;gt;XNetTransfer&amp;lt;/code&amp;gt; subcomponent is responsible to enable this transfer. It consists of&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet.png|thumb|XNet transfer component diagram]]&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which is responsible for serving certified stream slices and making them available to &amp;lt;code&amp;gt;XNetPayloadBuilders&amp;lt;/code&amp;gt; on other subnetworks.&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;, which allows the block makers to obtain an &amp;lt;code&amp;gt;XNetPayload&amp;lt;/code&amp;gt; containing the currently available certified streams originating from other subnetworks. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; obtains those streams by interacting with &amp;lt;code&amp;gt;XNetEndpoints&amp;lt;/code&amp;gt; exposed by other subnets. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; also provides functionality for notaries to verify &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; contained in block proposals.&lt;br /&gt;
&lt;br /&gt;
We do not specify anything about the protocol run between the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; to transfer the streams between two subnetworks. The only requirement we have is that certified streams made available by an &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; of an honest replica on some source subnetwork, they can be obtained by an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; of an honest replica on the destination subnetwork and that the information regarding which endpoints to contact is available in the Registry.&lt;br /&gt;
&lt;br /&gt;
=== Properties and Functionality ===&lt;br /&gt;
Assume an XNet transfer component on a replica part of subnet &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt;. The interface behavior of the XNet transfer component will guarantee that for any payload payload produced via&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;get_xnet_payload(registry_version, reference_height, past_payloads, size_limit)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we have that for any &amp;lt;code&amp;gt;(remote_subnet ↦ css) ∈ payload&amp;lt;/code&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;StateManager.decode_certified_stream(registry_version, own_subnet, remote_subnet, css)&amp;lt;/code&amp;gt; succeeds, i.e., returns a valid slice slice that is guaranteed to come from remote_subnet.&lt;br /&gt;
&lt;br /&gt;
* Furthermore, for each slice it will hold that a soon as the state corresponding to height &amp;lt;code&amp;gt;h = reference_height + |past_payloads|&amp;lt;/code&amp;gt; is available that &amp;lt;code&amp;gt;concatenate(remote_subnet, min(dom(slice.msgs.elements))) ∈ StateManager.get_state_at(h).expected_indexes&amp;lt;/code&amp;gt;. This means that the streams will start with the expected indexes stored in the previous state, i.e., they gap freely extend the previously seen streams.&lt;br /&gt;
&lt;br /&gt;
Payloads verified using &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; are accepted if they adhere to those requirements, and are rejected otherwise.&lt;br /&gt;
&lt;br /&gt;
=== XNet Endpoint ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; serves the streams available on some subnet to other subnets. For an implementation this will typically mean that there is some client which will handle querying the API of the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; on the remote subnet in question. We use the following abstraction to avoid explicitly talking about this client: We assume that there is a function &amp;lt;code&amp;gt;get : SubnetId → XNetEndpoint&amp;lt;/code&amp;gt; which will return an appropriate instance of &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which we can directly query using the API described below.&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet-sequence.png|thumb|XNet transfer sequence diagram]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get_stream(subnet_id : SubnetId, begin : StreamIndex, msg_limit : ℕ, size_limit : ℕ) → CertifiedStreamSlice&amp;lt;/code&amp;gt;: Returns the requested certified stream slice in its transport format.&lt;br /&gt;
&lt;br /&gt;
We require that an honest &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; pair is able to successfully obtain slices over this API.&lt;br /&gt;
&lt;br /&gt;
Looking at the bigger picture, the intuition for why this will yield a secure system is that in each round a new pair of block maker and endpoint will try to pull over a stream, which, in turn, means that eventually an honest pair will be able to obtain the stream and include it into a block.&lt;br /&gt;
&lt;br /&gt;
=== XNet Payload Builder ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; builds and verifies payloads whenever requested to do so by the block maker. The rules for whether a payload is considered valid or not must be so that every notary is guaranteed to make the same decision on the same input and that a payload built by an honest payload builder will be accepted by honest validators. Essentially the rules resemble what is described in the section on properties and functionality. However, given that the execution may be behind we can not directly look up the expected indexes in the appropriate state but need to compute it based on the referenced state and the payloads since then. Below, we provide a figure illustrating the high-level functionality: generally speaking blocks are considered valid if they adhere to the rules described in the figure and are considered invalid otherwise.&lt;br /&gt;
&lt;br /&gt;
[[File:Payload-building.png|thumb|Rules for payload building]]&lt;br /&gt;
&lt;br /&gt;
Below we formally define the operation of the component. We first define the following helper functions. We assume that &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; has an associated field &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt; which is passed whenever constructing an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;new : SubnetId → Self&lt;br /&gt;
new(own_subnet) :=&lt;br /&gt;
  XNetPayloadBuilder {&lt;br /&gt;
      with&lt;br /&gt;
         └─ own_subnet := own_subnet&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The API defines the past_payloads as a vector where the past payloads are ordered with respect to the corresponding height in the chain. While this ordering allows for a more efficient implementation of the functions below it does not matter on a conceptual level. Hence we resort to looking at it as a set for the sake of simplicity.&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;slice_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, solely based on a set of Slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Take the maximum index for each individual (sub-)stream in the given set of slices and add&lt;br /&gt;
% 1 to obtain the next indexes one would expect when solely looking at the past payloads but&lt;br /&gt;
% ignoring the state.&lt;br /&gt;
slice_indexes : (SubnetId ↦ StreamSlice) → Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
slice_indexes(slices) := { i + 1 | i ∈ max(dom(slices.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;state_and_payload_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, taking into account both the expected indices in the given replicated state and the more recent messages in the given slices from the past payloads.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Take the expected indexes from the state, remove whatever index appears in the given&lt;br /&gt;
% slices and add the expected indexes according to the streams in the slices.&lt;br /&gt;
%&lt;br /&gt;
% FAIL IF: ∃ i, j ∈ state_and_payload_indexes(state, slices) :&lt;br /&gt;
%              prefix(i) = prefix(j) ∧ postfix(i) ≠ postfix(j)&lt;br /&gt;
%&lt;br /&gt;
state_and_payload_indexes : ReplicatedState ×&lt;br /&gt;
                            (SubnetId ↦ StreamSlice) →&lt;br /&gt;
                            Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
state_and_payload_indexes(state, slices) := state.expected_xnet_indices&lt;br /&gt;
                                            \ dom(slices.msgs.elements)&lt;br /&gt;
                                            ∪ slice_indexes(slices)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;expected_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, taking into account both the expected indices in the given replicated state and the more recent messages in the given past payloads.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Decode the slices in the given payload and compute the expected indexes using the&lt;br /&gt;
% expected_indexes function above&lt;br /&gt;
expected_indexes : SubnetId ×&lt;br /&gt;
                   ReplicatedState ×&lt;br /&gt;
                   (SubnetId ↦ StreamSlice) →&lt;br /&gt;
                   Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
expected_indexes(own_subnet, state, slices) :=&lt;br /&gt;
    state_and_payload_indexes(&lt;br /&gt;
        state,&lt;br /&gt;
        { (src ↦ slice) | payload ∈ slices ∧&lt;br /&gt;
                          (src ↦ cert_slice) ∈ payload ∧&lt;br /&gt;
                          slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                             cert_slice)&lt;br /&gt;
        }&lt;br /&gt;
    )&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creation of XNet Payloads ====&lt;br /&gt;
Based on the functions above, we are now ready to define the function &amp;lt;code&amp;gt;get_xnet_payload : Height × Height × Set&amp;lt;XNetPayload&amp;gt; → XNetPayload&amp;lt;/code&amp;gt;. Note that the gap-freeness of streams is an invariant of the datatype, which is why we do not explicitly include the rule for gap-freeness here.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Build an xnet payload containing the currently available streams. The begin is either given&lt;br /&gt;
% by the expected index, and, if there is no expected index for a given prefix, the index&lt;br /&gt;
% ONE is expected.&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: size_of(get_xnet_payload(self, ·, ·, ·, size_limit)) ≤ size_limit ∧&lt;br /&gt;
%          each payload output by get_xnet_payload will be accepted by validate_xnet_payload&lt;br /&gt;
%&lt;br /&gt;
get_xnet_payload : Self × RegistryVersion × Height × Vec&amp;lt;XNetPayload&amp;gt; × ℕ → XNetPayload&lt;br /&gt;
get_xnet_payload(self, registry_version, reference_height, past_payloads, size_limit) :=&lt;br /&gt;
    { (remote_subnet ↦ slice) |&lt;br /&gt;
            S = StateManager.get_state_at(reference_height)&lt;br /&gt;
          ∧ subnets = Registry::get_registry_at(registry_version).subnets \ { self.own_subnet }&lt;br /&gt;
          ∧ (remote_subnet, begin_index) ∈&lt;br /&gt;
                  expected_indexes(self.own_subnet, S, past_payloads)&lt;br /&gt;
                ∪ { (subnet_id, StreamIndex::ONE) |&lt;br /&gt;
                        subnet_id ∈ subnets&lt;br /&gt;
                                    \ { s | (s, ·) ∈ expected_indexes(self.own_subnet,&lt;br /&gt;
                                                                      S,&lt;br /&gt;
                                                                      past_payloads)&lt;br /&gt;
                                      }&lt;br /&gt;
                  }&lt;br /&gt;
            % msg_limit and size limit need to be set by the implementation as appropriate&lt;br /&gt;
            % to satisfy the post condition&lt;br /&gt;
          ∧ slice = XNetEndpoint::get(subnet).get_stream(remote_subnet, begin_index, ·, ·)&lt;br /&gt;
          ∧ ERR ≠ StateManager.decode_certified_stream(registry_version,&lt;br /&gt;
                                                       self.own_subnet,&lt;br /&gt;
                                                       remote_subnet,&lt;br /&gt;
                                                       slice)&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Validation of XNet Payloads ====&lt;br /&gt;
Validation of XNetPayloads works analogously to the creation. The function &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; is defined as follows, where we assume that it evaluates to false in case an error occurs. Again, note that the gap-freeness of streams is an invariant of the datatype, which is why we do not explicitly include the rule for gap-freeness here.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Check whether a given xnet payload was built according to the rules given above.&lt;br /&gt;
%&lt;br /&gt;
% FAIL IF: size_of(payload) &amp;gt; size_limit&lt;br /&gt;
%&lt;br /&gt;
validate_xnet_payload : Self × RegistryVersion × Height × Vec&amp;lt;XNetPayload&amp;gt; × XNetPayload × ℕ → Bool&lt;br /&gt;
validate_xnet_payload(self, registry_version, reference_height, past_payloads, payload, size_limit) :=&lt;br /&gt;
    S = StateManager.get_state_at(reference_height) ∧&lt;br /&gt;
    ∀ (remote_subnet ↦ css) ∈ payload :&lt;br /&gt;
    {&lt;br /&gt;
      slice = StateManager.decode_certified_stream(registry_version,&lt;br /&gt;
                                                   self.own_subnet,&lt;br /&gt;
                                                   remote_subnet,&lt;br /&gt;
                                                   css) ∧&lt;br /&gt;
      ∀ index ∈ min(dom(slice.msgs.elements)) :&lt;br /&gt;
      {&lt;br /&gt;
        (remote_subnet, index) ∈ expected_indexes(S, past_payloads) ∨&lt;br /&gt;
        index = (remote_subnet, StreamIndex::ONE)&lt;br /&gt;
      }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3416</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3416"/>
		<updated>2022-11-04T06:43:11Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The VSR for cross-net messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_xnet : CanonicalState × Batch → Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function that determines the indices of the messages in the individual substreams contained in &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt; to be inducted.&lt;br /&gt;
&lt;br /&gt;
We require that the implementation of the VSR (or the layer above) makes sure that all reply messages are accepted by the VSR. Formally this means that for any valid State-Batch combination &amp;lt;code&amp;gt;(s, b)&amp;lt;/code&amp;gt; it holds that for all &amp;lt;code&amp;gt;(subnet, index)&amp;lt;/code&amp;gt; so that &amp;lt;code&amp;gt;b.xnet_payload[subnet].msgs[index]&amp;lt;/code&amp;gt; is a reply message that &amp;lt;code&amp;gt;(subnet, index) ∈ vsr_check_xnet(s, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Based on this rule one can straight-forwardly define the interface behavior of the VSR.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).xnet :=&lt;br /&gt;
  { (index ↦ msg) |&lt;br /&gt;
      (index ↦ msg) ∈ batch.xnet_payload.msgs ∧&lt;br /&gt;
      index ∈ vsr_check_xnet(state, batch)&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
VSR(state, batch).signals :=&lt;br /&gt;
    { (concatenate(subnet, index) ↦ ACCEPT) |&lt;br /&gt;
      (subnet ↦ stream) ∈ batch.xnet_payload ∧&lt;br /&gt;
      (index ↦ msg) ∈ stream.msgs ∧&lt;br /&gt;
      (subnet, index) ∈ vsr_check_xnet(state, batch)&lt;br /&gt;
    }&lt;br /&gt;
  ∪ { (concatenate(subnet, index) ↦ REJECT) |&lt;br /&gt;
      (subnet ↦ stream) ∈ batch.xnet_payload ∧&lt;br /&gt;
      (index ↦ msg) ∈ stream.msgs ∧&lt;br /&gt;
      (subnet, index) ∉ vsr_check_xnet(state, batch)&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;br /&gt;
&lt;br /&gt;
== XNet Transfer ==&lt;br /&gt;
After calling &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt; at the end of a deterministic processing cycle, the state manager will take care of getting the committed state certified. Once certification is complete, the certified stream slices can be made available to block makers on other subnets. The &amp;lt;code&amp;gt;XNetTransfer&amp;lt;/code&amp;gt; subcomponent is responsible to enable this transfer. It consists of&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet.png|thumb|XNet transfer component diagram]]&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which is responsible for serving certified stream slices and making them available to &amp;lt;code&amp;gt;XNetPayloadBuilders&amp;lt;/code&amp;gt; on other subnetworks.&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;, which allows the block makers to obtain an &amp;lt;code&amp;gt;XNetPayload&amp;lt;/code&amp;gt; containing the currently available certified streams originating from other subnetworks. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; obtains those streams by interacting with &amp;lt;code&amp;gt;XNetEndpoints&amp;lt;/code&amp;gt; exposed by other subnets. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; also provides functionality for notaries to verify &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; contained in block proposals.&lt;br /&gt;
&lt;br /&gt;
We do not specify anything about the protocol run between the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; to transfer the streams between two subnetworks. The only requirement we have is that certified streams made available by an &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; of an honest replica on some source subnetwork, they can be obtained by an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; of an honest replica on the destination subnetwork and that the information regarding which endpoints to contact is available in the Registry.&lt;br /&gt;
&lt;br /&gt;
=== Properties and Functionality ===&lt;br /&gt;
Assume an XNet transfer component on a replica part of subnet &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt;. The interface behavior of the XNet transfer component will guarantee that for any payload payload produced via&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;get_xnet_payload(registry_version, reference_height, past_payloads, size_limit)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we have that for any &amp;lt;code&amp;gt;(remote_subnet ↦ css) ∈ payload&amp;lt;/code&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;StateManager.decode_certified_stream(registry_version, own_subnet, remote_subnet, css)&amp;lt;/code&amp;gt; succeeds, i.e., returns a valid slice slice that is guaranteed to come from remote_subnet.&lt;br /&gt;
&lt;br /&gt;
* Furthermore, for each slice it will hold that a soon as the state corresponding to height &amp;lt;code&amp;gt;h = reference_height + |past_payloads|&amp;lt;/code&amp;gt; is available that &amp;lt;code&amp;gt;concatenate(remote_subnet, min(dom(slice.msgs.elements))) ∈ StateManager.get_state_at(h).expected_indexes&amp;lt;/code&amp;gt;. This means that the streams will start with the expected indexes stored in the previous state, i.e., they gap freely extend the previously seen streams.&lt;br /&gt;
&lt;br /&gt;
Payloads verified using &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; are accepted if they adhere to those requirements, and are rejected otherwise.&lt;br /&gt;
&lt;br /&gt;
=== XNet Endpoint ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; serves the streams available on some subnet to other subnets. For an implementation this will typically mean that there is some client which will handle querying the API of the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; on the remote subnet in question. We use the following abstraction to avoid explicitly talking about this client: We assume that there is a function &amp;lt;code&amp;gt;get : SubnetId → XNetEndpoint&amp;lt;/code&amp;gt; which will return an appropriate instance of &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which we can directly query using the API described below.&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet-sequence.png|thumb|XNet transfer sequence diagram]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get_stream(subnet_id : SubnetId, begin : StreamIndex, msg_limit : ℕ, size_limit : ℕ) → CertifiedStreamSlice&amp;lt;/code&amp;gt;: Returns the requested certified stream slice in its transport format.&lt;br /&gt;
&lt;br /&gt;
We require that an honest &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; pair is able to successfully obtain slices over this API.&lt;br /&gt;
&lt;br /&gt;
Looking at the bigger picture, the intuition for why this will yield a secure system is that in each round a new pair of block maker and endpoint will try to pull over a stream, which, in turn, means that eventually an honest pair will be able to obtain the stream and include it into a block.&lt;br /&gt;
&lt;br /&gt;
=== XNet Payload Builder ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; builds and verifies payloads whenever requested to do so by the block maker. The rules for whether a payload is considered valid or not must be so that every notary is guaranteed to make the same decision on the same input and that a payload built by an honest payload builder will be accepted by honest validators. Essentially the rules resemble what is described in the section on properties and functionality. However, given that the execution may be behind we can not directly look up the expected indexes in the appropriate state but need to compute it based on the referenced state and the payloads since then. Below, we provide a figure illustrating the high-level functionality: generally speaking blocks are considered valid if they adhere to the rules described in the figure and are considered invalid otherwise.&lt;br /&gt;
&lt;br /&gt;
[[File:Payload-building.png|thumb|Rules for payload building]]&lt;br /&gt;
&lt;br /&gt;
Below we formally define the operation of the component. We first define the following helper functions. We assume that &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; has an associated field &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt; which is passed whenever constructing an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;new : SubnetId → Self&lt;br /&gt;
new(own_subnet) :=&lt;br /&gt;
  XNetPayloadBuilder {&lt;br /&gt;
      with&lt;br /&gt;
         └─ own_subnet := own_subnet&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The API defines the past_payloads as a vector where the past payloads are ordered with respect to the corresponding height in the chain. While this ordering allows for a more efficient implementation of the functions below it does not matter on a conceptual level. Hence we resort to looking at it as a set for the sake of simplicity.&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;slice_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, solely based on a set of Slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Take the maximum index for each individual (sub-)stream in the given set of slices and add&lt;br /&gt;
% 1 to obtain the next indexes one would expect when solely looking at the past payloads but&lt;br /&gt;
% ignoring the state.&lt;br /&gt;
slice_indexes : (SubnetId ↦ StreamSlice) → Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
slice_indexes(slices) := { i + 1 | i ∈ max(dom(slices.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;state_and_payload_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, taking into account both the expected indices in the given replicated state and the more recent messages in the given slices from the past payloads.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Take the expected indexes from the state, remove whatever index appears in the given&lt;br /&gt;
% slices and add the expected indexes according to the streams in the slices.&lt;br /&gt;
%&lt;br /&gt;
% FAIL IF: ∃ i, j ∈ state_and_payload_indexes(state, slices) :&lt;br /&gt;
%              prefix(i) = prefix(j) ∧ postfix(i) ≠ postfix(j)&lt;br /&gt;
%&lt;br /&gt;
state_and_payload_indexes : ReplicatedState ×&lt;br /&gt;
                            (SubnetId ↦ StreamSlice) →&lt;br /&gt;
                            Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
state_and_payload_indexes(state, slices) := state.expected_xnet_indices&lt;br /&gt;
                                            \ dom(slices.msgs.elements)&lt;br /&gt;
                                            ∪ slice_indexes(slices)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;expected_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, taking into account both the expected indices in the given replicated state and the more recent messages in the given past payloads.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Decode the slices in the given payload and compute the expected indexes using the&lt;br /&gt;
% expected_indexes function above&lt;br /&gt;
expected_indexes : SubnetId ×&lt;br /&gt;
                   ReplicatedState ×&lt;br /&gt;
                   (SubnetId ↦ StreamSlice) →&lt;br /&gt;
                   Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
expected_indexes(own_subnet, state, slices) :=&lt;br /&gt;
    state_and_payload_indexes(&lt;br /&gt;
        state,&lt;br /&gt;
        { (src ↦ slice) | payload ∈ slices ∧&lt;br /&gt;
                          (src ↦ cert_slice) ∈ payload ∧&lt;br /&gt;
                          slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                             cert_slice)&lt;br /&gt;
        }&lt;br /&gt;
    )&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creation of XNet Payloads ====&lt;br /&gt;
Based on the functions above, we are now ready to define the function &amp;lt;code&amp;gt;get_xnet_payload : Height × Height × Set&amp;lt;XNetPayload&amp;gt; → XNetPayload&amp;lt;/code&amp;gt;. Note that the gap-freeness of streams is an invariant of the datatype, which is why we do not explicitly include the rule for gap-freeness here.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Build an xnet payload containing the currently available streams. The begin is either given&lt;br /&gt;
% by the expected index, and, if there is no expected index for a given prefix, the index&lt;br /&gt;
% ONE is expected.&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: size_of(get_xnet_payload(self, ·, ·, ·, size_limit)) ≤ size_limit ∧&lt;br /&gt;
%          each payload output by get_xnet_payload will be accepted by validate_xnet_payload&lt;br /&gt;
%&lt;br /&gt;
get_xnet_payload : Self × RegistryVersion × Height × Vec&amp;lt;XNetPayload&amp;gt; × ℕ → XNetPayload&lt;br /&gt;
get_xnet_payload(self, registry_version, reference_height, past_payloads, size_limit) :=&lt;br /&gt;
    { (remote_subnet ↦ slice) |&lt;br /&gt;
            S = StateManager.get_state_at(reference_height)&lt;br /&gt;
          ∧ subnets = Registry::get_registry_at(registry_version).subnets \ { self.own_subnet }&lt;br /&gt;
          ∧ (remote_subnet, begin_index) ∈&lt;br /&gt;
                  expected_indexes(self.own_subnet, S, past_payloads)&lt;br /&gt;
                ∪ { (subnet_id, StreamIndex::ONE) |&lt;br /&gt;
                        subnet_id ∈ subnets&lt;br /&gt;
                                    \ { s | (s, ·) ∈ expected_indexes(self.own_subnet,&lt;br /&gt;
                                                                      S,&lt;br /&gt;
                                                                      past_payloads)&lt;br /&gt;
                                      }&lt;br /&gt;
                  }&lt;br /&gt;
            % msg_limit and size limit need to be set by the implementation as appropriate&lt;br /&gt;
            % to satisfy the post condition&lt;br /&gt;
          ∧ slice = XNetEndpoint::get(subnet).get_stream(remote_subnet, begin_index, ·, ·)&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Validation of XNet Payloads ====&lt;br /&gt;
Validation of XNetPayloads works analogously to the creation. The function &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; is defined as follows, where we assume that it evaluates to false in case an error occurs. Again, note that the gap-freeness of streams is an invariant of the datatype, which is why we do not explicitly include the rule for gap-freeness here.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Check whether a given xnet payload was built according to the rules given above.&lt;br /&gt;
%&lt;br /&gt;
% FAIL IF: size_of(payload) &amp;gt; size_limit&lt;br /&gt;
%&lt;br /&gt;
validate_xnet_payload : Self × RegistryVersion × Height × Vec&amp;lt;XNetPayload&amp;gt; × XNetPayload × ℕ → Bool&lt;br /&gt;
validate_xnet_payload(self, registry_version, reference_height, past_payloads, payload, size_limit) :=&lt;br /&gt;
    S = StateManager.get_state_at(reference_height) ∧&lt;br /&gt;
    ∀ (remote_subnet ↦ css) ∈ payload :&lt;br /&gt;
    {&lt;br /&gt;
      slice = StateManager.decode_certified_stream(registry_version,&lt;br /&gt;
                                                   self.own_subnet,&lt;br /&gt;
                                                   remote_subnet,&lt;br /&gt;
                                                   css) ∧&lt;br /&gt;
      ∀ index ∈ min(dom(slice.msgs.elements)) :&lt;br /&gt;
      {&lt;br /&gt;
        (remote_subnet, index) ∈ expected_indexes(S, past_payloads) ∨&lt;br /&gt;
        index = (remote_subnet, StreamIndex::ONE)&lt;br /&gt;
      }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3415</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3415"/>
		<updated>2022-11-04T06:40:49Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The VSR for cross-net messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_xnet : CanonicalState × Batch → Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function that determines the indices of the messages in the individual substreams contained in &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt; to be inducted.&lt;br /&gt;
&lt;br /&gt;
We require that the implementation of the VSR (or the layer above) makes sure that all reply messages are accepted by the VSR. Formally this means that for any valid State-Batch combination &amp;lt;code&amp;gt;(s, b)&amp;lt;/code&amp;gt; it holds that for all &amp;lt;code&amp;gt;(subnet, index)&amp;lt;/code&amp;gt; so that &amp;lt;code&amp;gt;b.xnet_payload[subnet].msgs[index]&amp;lt;/code&amp;gt; is a reply message that &amp;lt;code&amp;gt;(subnet, index) ∈ vsr_check_xnet(s, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Based on this rule one can straight-forwardly define the interface behavior of the VSR.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).xnet :=&lt;br /&gt;
  { (index ↦ msg) |&lt;br /&gt;
      (index ↦ msg) ∈ batch.xnet_payload.msgs ∧&lt;br /&gt;
      index ∈ vsr_check_xnet(state, batch)&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
VSR(state, batch).signals :=&lt;br /&gt;
    { (concatenate(subnet, index) ↦ ACCEPT) |&lt;br /&gt;
      (subnet ↦ stream) ∈ batch.xnet_payload ∧&lt;br /&gt;
      (index ↦ msg) ∈ stream.msgs ∧&lt;br /&gt;
      (subnet, index) ∈ vsr_check_xnet(state, batch)&lt;br /&gt;
    }&lt;br /&gt;
  ∪ { (concatenate(subnet, index) ↦ REJECT) |&lt;br /&gt;
      (subnet ↦ stream) ∈ batch.xnet_payload ∧&lt;br /&gt;
      (index ↦ msg) ∈ stream.msgs ∧&lt;br /&gt;
      (subnet, index) ∉ vsr_check_xnet(state, batch)&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;br /&gt;
&lt;br /&gt;
== XNet Transfer ==&lt;br /&gt;
After calling &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt; at the end of a deterministic processing cycle, the state manager will take care of getting the committed state certified. Once certification is complete, the certified stream slices can be made available to block makers on other subnets. The &amp;lt;code&amp;gt;XNetTransfer&amp;lt;/code&amp;gt; subcomponent is responsible to enable this transfer. It consists of&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet.png|thumb|XNet transfer component diagram]]&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which is responsible for serving certified stream slices and making them available to &amp;lt;code&amp;gt;XNetPayloadBuilders&amp;lt;/code&amp;gt; on other subnetworks.&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;, which allows the block makers to obtain an &amp;lt;code&amp;gt;XNetPayload&amp;lt;/code&amp;gt; containing the currently available certified streams originating from other subnetworks. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; obtains those streams by interacting with &amp;lt;code&amp;gt;XNetEndpoints&amp;lt;/code&amp;gt; exposed by other subnets. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; also provides functionality for notaries to verify &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; contained in block proposals.&lt;br /&gt;
&lt;br /&gt;
We do not specify anything about the protocol run between the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; to transfer the streams between two subnetworks. The only requirement we have is that certified streams made available by an &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; of an honest replica on some source subnetwork, they can be obtained by an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; of an honest replica on the destination subnetwork and that the information regarding which endpoints to contact is available in the Registry.&lt;br /&gt;
&lt;br /&gt;
=== Properties and Functionality ===&lt;br /&gt;
Assume an XNet transfer component on a replica part of subnet &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt;. The interface behavior of the XNet transfer component will guarantee that for any payload payload produced via&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;get_xnet_payload(registry_version, reference_height, past_payloads, size_limit)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we have that for any &amp;lt;code&amp;gt;(remote_subnet ↦ css) ∈ payload&amp;lt;/code&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;StateManager.decode_certified_stream(registry_version, own_subnet, remote_subnet, css)&amp;lt;/code&amp;gt; succeeds, i.e., returns a valid slice slice that is guaranteed to come from remote_subnet.&lt;br /&gt;
&lt;br /&gt;
* Furthermore, for each slice it will hold that a soon as the state corresponding to height &amp;lt;code&amp;gt;h = reference_height + |past_payloads|&amp;lt;/code&amp;gt; is available that &amp;lt;code&amp;gt;concatenate(remote_subnet, min(dom(slice.msgs.elements))) ∈ StateManager.get_state_at(h).expected_indexes&amp;lt;/code&amp;gt;. This means that the streams will start with the expected indexes stored in the previous state, i.e., they gap freely extend the previously seen streams.&lt;br /&gt;
&lt;br /&gt;
Payloads verified using &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; are accepted if they adhere to those requirements, and are rejected otherwise.&lt;br /&gt;
&lt;br /&gt;
=== XNet Endpoint ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; serves the streams available on some subnet to other subnets. For an implementation this will typically mean that there is some client which will handle querying the API of the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; on the remote subnet in question. We use the following abstraction to avoid explicitly talking about this client: We assume that there is a function &amp;lt;code&amp;gt;get : SubnetId → XNetEndpoint&amp;lt;/code&amp;gt; which will return an appropriate instance of &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which we can directly query using the API described below.&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet-sequence.png|thumb|XNet transfer sequence diagram]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get_stream(subnet_id : SubnetId, begin : StreamIndex, msg_limit : ℕ, size_limit : ℕ) → CertifiedStreamSlice&amp;lt;/code&amp;gt;: Returns the requested certified stream slice in its transport format.&lt;br /&gt;
&lt;br /&gt;
We require that an honest &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; pair is able to successfully obtain slices over this API.&lt;br /&gt;
&lt;br /&gt;
Looking at the bigger picture, the intuition for why this will yield a secure system is that in each round a new pair of block maker and endpoint will try to pull over a stream, which, in turn, means that eventually an honest pair will be able to obtain the stream and include it into a block.&lt;br /&gt;
&lt;br /&gt;
=== XNet Payload Builder ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; builds and verifies payloads whenever requested to do so by the block maker. The rules for whether a payload is considered valid or not must be so that every notary is guaranteed to make the same decision on the same input and that a payload built by an honest payload builder will be accepted by honest validators. Essentially the rules resemble what is described in the section on properties and functionality. However, given that the execution may be behind we can not directly look up the expected indexes in the appropriate state but need to compute it based on the referenced state and the payloads since then. Below, we provide a figure illustrating the high-level functionality: generally speaking blocks are considered valid if they adhere to the rules described in the figure and are considered invalid otherwise.&lt;br /&gt;
&lt;br /&gt;
[[File:Payload-building.png|thumb|Rules for payload building]]&lt;br /&gt;
&lt;br /&gt;
Below we formally define the operation of the component. We first define the following helper functions. We assume that &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; has an associated field &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt; which is passed whenever constructing an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;new : SubnetId → Self&lt;br /&gt;
new(own_subnet) :=&lt;br /&gt;
  XNetPayloadBuilder {&lt;br /&gt;
      with&lt;br /&gt;
         └─ own_subnet := own_subnet&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The API defines the past_payloads as a vector where the past payloads are ordered with respect to the corresponding height in the chain. While this ordering allows for a more efficient implementation of the functions below it does not matter on a conceptual level. Hence we resort to looking at it as a set for the sake of simplicity.&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;slice_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, solely based on a set of Slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Take the maximum index for each individual (sub-)stream in the given set of slices and add&lt;br /&gt;
% 1 to obtain the next indexes one would expect when solely looking at the past payloads but&lt;br /&gt;
% ignoring the state.&lt;br /&gt;
slice_indexes : (SubnetId ↦ StreamSlice) → Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
slice_indexes(slices) := { i + 1 | i ∈ max(dom(slices.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;state_and_payload_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, taking into account both the expected indices in the given replicated state and the more recent messages in the given slices from the past payloads.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Take the expected indexes from the state, remove whatever index appears in the given&lt;br /&gt;
% slices and add the expected indexes according to the streams in the slices.&lt;br /&gt;
%&lt;br /&gt;
% FAIL IF: ∃ i, j ∈ state_and_payload_indexes(state, slices) :&lt;br /&gt;
%              prefix(i) = prefix(j) ∧ postfix(i) ≠ postfix(j)&lt;br /&gt;
%&lt;br /&gt;
state_and_payload_indexes : ReplicatedState ×&lt;br /&gt;
                            (SubnetId ↦ StreamSlice) →&lt;br /&gt;
                            Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
state_and_payload_indexes(state, slices) := state.expected_xnet_indices&lt;br /&gt;
                                            \ dom(slices.msgs.elements)&lt;br /&gt;
                                            ∪ slice_indexes(slices)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;expected_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, taking into account both the expected indices in the given replicated state and the more recent messages in the given past payloads.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Decode the slices in the given payload and compute the expected indexes using the&lt;br /&gt;
% expected_indexes function above&lt;br /&gt;
expected_indexes : SubnetId ×&lt;br /&gt;
                   ReplicatedState ×&lt;br /&gt;
                   (SubnetId ↦ StreamSlice) →&lt;br /&gt;
                   Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
expected_indexes(own_subnet, state, slices) :=&lt;br /&gt;
    state_and_payload_indexes(&lt;br /&gt;
        state,&lt;br /&gt;
        { (src ↦ slice) | payload ∈ slices ∧&lt;br /&gt;
                          (src ↦ cert_slice) ∈ payload ∧&lt;br /&gt;
                          slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                             cert_slice)&lt;br /&gt;
        }&lt;br /&gt;
    )&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creation of XNet Payloads ====&lt;br /&gt;
Based on the functions above, we are now ready to define the function &amp;lt;code&amp;gt;get_xnet_payload : Height × Height × Set&amp;lt;XNetPayload&amp;gt; → XNetPayload&amp;lt;/code&amp;gt;. Note that the gap-freeness of streams is an invariant of the datatype, which is why we do not explicitly include the rule for gap-freeness here.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Build an xnet payload containing the currently available streams. The begin is either given&lt;br /&gt;
% by the expected index, and, if there is no expected index for a given prefix, the index&lt;br /&gt;
% ONE is expected.&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: size_of(get_xnet_payload(self, ·, ·, ·, size_limit)) ≤ size_limit&lt;br /&gt;
%&lt;br /&gt;
get_xnet_payload : Self × RegistryVersion × Height × Vec&amp;lt;XNetPayload&amp;gt; × ℕ → XNetPayload&lt;br /&gt;
get_xnet_payload(self, registry_version, reference_height, past_payloads, size_limit) :=&lt;br /&gt;
    { (remote_subnet ↦ slice) |&lt;br /&gt;
            S = StateManager.get_state_at(reference_height)&lt;br /&gt;
          ∧ subnets = Registry::get_registry_at(registry_version).subnets \ { self.own_subnet }&lt;br /&gt;
          ∧ (remote_subnet, begin_index) ∈&lt;br /&gt;
                  expected_indexes(self.own_subnet, S, past_payloads)&lt;br /&gt;
                ∪ { (subnet_id, StreamIndex::ONE) |&lt;br /&gt;
                        subnet_id ∈ subnets&lt;br /&gt;
                                    \ { s | (s, ·) ∈ expected_indexes(self.own_subnet,&lt;br /&gt;
                                                                      S,&lt;br /&gt;
                                                                      past_payloads)&lt;br /&gt;
                                      }&lt;br /&gt;
                  }&lt;br /&gt;
            % msg_limit and size limit need to be set by the implementation as appropriate&lt;br /&gt;
            % to satisfy the post condition&lt;br /&gt;
          ∧ slice = XNetEndpoint::get(subnet).get_stream(remote_subnet, begin_index, ·, ·)&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Validation of XNet Payloads ====&lt;br /&gt;
Validation of XNetPayloads works analogously to the creation. The function &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; is defined as follows, where we assume that it evaluates to false in case an error occurs. Again, note that the gap-freeness of streams is an invariant of the datatype, which is why we do not explicitly include the rule for gap-freeness here.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Check whether a given xnet payload was built according to the rules given above.&lt;br /&gt;
%&lt;br /&gt;
% FAIL IF: size_of(payload) &amp;gt; size_limit&lt;br /&gt;
%&lt;br /&gt;
validate_xnet_payload : Self × RegistryVersion × Height × Vec&amp;lt;XNetPayload&amp;gt; × XNetPayload × ℕ → Bool&lt;br /&gt;
validate_xnet_payload(self, registry_version, reference_height, past_payloads, payload, size_limit) :=&lt;br /&gt;
    S = StateManager.get_state_at(reference_height) ∧&lt;br /&gt;
    ∀ (remote_subnet ↦ css) ∈ payload :&lt;br /&gt;
    {&lt;br /&gt;
      slice = StateManager.decode_certified_stream(registry_version,&lt;br /&gt;
                                                   self.own_subnet,&lt;br /&gt;
                                                   remote_subnet,&lt;br /&gt;
                                                   css) ∧&lt;br /&gt;
      ∀ index ∈ min(dom(slice.msgs.elements)) :&lt;br /&gt;
      {&lt;br /&gt;
        (remote_subnet, index) ∈ expected_indexes(S, past_payloads) ∨&lt;br /&gt;
        index = (remote_subnet, StreamIndex::ONE)&lt;br /&gt;
      }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3414</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3414"/>
		<updated>2022-11-04T06:40:27Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The VSR for cross-net messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_xnet : CanonicalState × Batch → Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function that determines the indices of the messages in the individual substreams contained in &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt; to be inducted.&lt;br /&gt;
&lt;br /&gt;
We require that the implementation of the VSR (or the layer above) makes sure that all reply messages are accepted by the VSR. Formally this means that for any valid State-Batch combination &amp;lt;code&amp;gt;(s, b)&amp;lt;/code&amp;gt; it holds that for all &amp;lt;code&amp;gt;(subnet, index)&amp;lt;/code&amp;gt; so that &amp;lt;code&amp;gt;b.xnet_payload[subnet].msgs[index]&amp;lt;/code&amp;gt; is a reply message that &amp;lt;code&amp;gt;(subnet, index) ∈ vsr_check_xnet(s, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Based on this rule one can straight-forwardly define the interface behavior of the VSR.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).xnet :=&lt;br /&gt;
  { (index ↦ msg) |&lt;br /&gt;
      (index ↦ msg) ∈ batch.xnet_payload.msgs ∧&lt;br /&gt;
      index ∈ vsr_check_xnet(state, batch)&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
VSR(state, batch).signals :=&lt;br /&gt;
    { (concatenate(subnet, index) ↦ ACCEPT) |&lt;br /&gt;
      (subnet ↦ stream) ∈ batch.xnet_payload ∧&lt;br /&gt;
      (index ↦ msg) ∈ stream.msgs ∧&lt;br /&gt;
      (subnet, index) ∈ vsr_check_xnet(state, batch)&lt;br /&gt;
    }&lt;br /&gt;
  ∪ { (concatenate(subnet, index) ↦ REJECT) |&lt;br /&gt;
      (subnet ↦ stream) ∈ batch.xnet_payload ∧&lt;br /&gt;
      (index ↦ msg) ∈ stream.msgs ∧&lt;br /&gt;
      (subnet, index) ∉ vsr_check_xnet(state, batch)&lt;br /&gt;
    }&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;br /&gt;
&lt;br /&gt;
== XNet Transfer ==&lt;br /&gt;
After calling &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt; at the end of a deterministic processing cycle, the state manager will take care of getting the committed state certified. Once certification is complete, the certified stream slices can be made available to block makers on other subnets. The &amp;lt;code&amp;gt;XNetTransfer&amp;lt;/code&amp;gt; subcomponent is responsible to enable this transfer. It consists of&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet.png|thumb|XNet transfer component diagram]]&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which is responsible for serving certified stream slices and making them available to &amp;lt;code&amp;gt;XNetPayloadBuilders&amp;lt;/code&amp;gt; on other subnetworks.&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;, which allows the block makers to obtain an &amp;lt;code&amp;gt;XNetPayload&amp;lt;/code&amp;gt; containing the currently available certified streams originating from other subnetworks. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; obtains those streams by interacting with &amp;lt;code&amp;gt;XNetEndpoints&amp;lt;/code&amp;gt; exposed by other subnets. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; also provides functionality for notaries to verify &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; contained in block proposals.&lt;br /&gt;
&lt;br /&gt;
We do not specify anything about the protocol run between the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; to transfer the streams between two subnetworks. The only requirement we have is that certified streams made available by an &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; of an honest replica on some source subnetwork, they can be obtained by an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; of an honest replica on the destination subnetwork and that the information regarding which endpoints to contact is available in the Registry.&lt;br /&gt;
&lt;br /&gt;
=== Properties and Functionality ===&lt;br /&gt;
Assume an XNet transfer component on a replica part of subnet &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt;. The interface behavior of the XNet transfer component will guarantee that for any payload payload produced via&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;get_xnet_payload(registry_version, reference_height, past_payloads, size_limit)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we have that for any &amp;lt;code&amp;gt;(remote_subnet ↦ css) ∈ payload&amp;lt;/code&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;StateManager.decode_certified_stream(registry_version, own_subnet, remote_subnet, css)&amp;lt;/code&amp;gt; succeeds, i.e., returns a valid slice slice that is guaranteed to come from remote_subnet.&lt;br /&gt;
&lt;br /&gt;
* Furthermore, for each slice it will hold that a soon as the state corresponding to height &amp;lt;code&amp;gt;h = reference_height + |past_payloads|&amp;lt;/code&amp;gt; is available that &amp;lt;code&amp;gt;concatenate(remote_subnet, min(dom(slice.msgs.elements))) ∈ StateManager.get_state_at(h).expected_indexes&amp;lt;/code&amp;gt;. This means that the streams will start with the expected indexes stored in the previous state, i.e., they gap freely extend the previously seen streams.&lt;br /&gt;
&lt;br /&gt;
Payloads verified using &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; are accepted if they adhere to those requirements, and are rejected otherwise.&lt;br /&gt;
&lt;br /&gt;
=== XNet Endpoint ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; serves the streams available on some subnet to other subnets. For an implementation this will typically mean that there is some client which will handle querying the API of the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; on the remote subnet in question. We use the following abstraction to avoid explicitly talking about this client: We assume that there is a function &amp;lt;code&amp;gt;get : SubnetId → XNetEndpoint&amp;lt;/code&amp;gt; which will return an appropriate instance of &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which we can directly query using the API described below.&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet-sequence.png|thumb|XNet transfer sequence diagram]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get_stream(subnet_id : SubnetId, begin : StreamIndex, msg_limit : ℕ, size_limit : ℕ) → CertifiedStreamSlice&amp;lt;/code&amp;gt;: Returns the requested certified stream slice in its transport format.&lt;br /&gt;
&lt;br /&gt;
We require that an honest &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; pair is able to successfully obtain slices over this API.&lt;br /&gt;
&lt;br /&gt;
Looking at the bigger picture, the intuition for why this will yield a secure system is that in each round a new pair of block maker and endpoint will try to pull over a stream, which, in turn, means that eventually an honest pair will be able to obtain the stream and include it into a block.&lt;br /&gt;
&lt;br /&gt;
=== XNet Payload Builder ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; builds and verifies payloads whenever requested to do so by the block maker. The rules for whether a payload is considered valid or not must be so that every notary is guaranteed to make the same decision on the same input and that a payload built by an honest payload builder will be accepted by honest validators. Essentially the rules resemble what is described in the section on properties and functionality. However, given that the execution may be behind we can not directly look up the expected indexes in the appropriate state but need to compute it based on the referenced state and the payloads since then. Below, we provide a figure illustrating the high-level functionality: generally speaking blocks are considered valid if they adhere to the rules described in the figure and are considered invalid otherwise.&lt;br /&gt;
&lt;br /&gt;
[[File:Payload-building.png|thumb|Rules for payload building]]&lt;br /&gt;
&lt;br /&gt;
Below we formally define the operation of the component. We first define the following helper functions. We assume that &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; has an associated field &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt; which is passed whenever constructing an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;new : SubnetId → Self&lt;br /&gt;
new(own_subnet) :=&lt;br /&gt;
  XNetPayloadBuilder {&lt;br /&gt;
      with&lt;br /&gt;
         └─ own_subnet := own_subnet&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The API defines the past_payloads as a vector where the past payloads are ordered with respect to the corresponding height in the chain. While this ordering allows for a more efficient implementation of the functions below it does not matter on a conceptual level. Hence we resort to looking at it as a set for the sake of simplicity.&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;slice_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, solely based on a set of Slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Take the maximum index for each individual (sub-)stream in the given set of slices and add&lt;br /&gt;
% 1 to obtain the next indexes one would expect when solely looking at the past payloads but&lt;br /&gt;
% ignoring the state.&lt;br /&gt;
slice_indexes : (SubnetId ↦ StreamSlice) → Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
slice_indexes(slices) := { i + 1 | i ∈ max(dom(slices.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;state_and_payload_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, taking into account both the expected indices in the given replicated state and the more recent messages in the given slices from the past payloads.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Take the expected indexes from the state, remove whatever index appears in the given&lt;br /&gt;
% slices and add the expected indexes according to the streams in the slices.&lt;br /&gt;
%&lt;br /&gt;
% FAIL IF: ∃ i, j ∈ state_and_payload_indexes(state, slices) :&lt;br /&gt;
%              prefix(i) = prefix(j) ∧ postfix(i) ≠ postfix(j)&lt;br /&gt;
%&lt;br /&gt;
state_and_payload_indexes : ReplicatedState ×&lt;br /&gt;
                            (SubnetId ↦ StreamSlice) →&lt;br /&gt;
                            Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
state_and_payload_indexes(state, slices) := state.expected_xnet_indices&lt;br /&gt;
                                            \ dom(slices.msgs.elements)&lt;br /&gt;
                                            ∪ slice_indexes(slices)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;expected_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, taking into account both the expected indices in the given replicated state and the more recent messages in the given past payloads.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Decode the slices in the given payload and compute the expected indexes using the&lt;br /&gt;
% expected_indexes function above&lt;br /&gt;
expected_indexes : SubnetId ×&lt;br /&gt;
                   ReplicatedState ×&lt;br /&gt;
                   (SubnetId ↦ StreamSlice) →&lt;br /&gt;
                   Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
expected_indexes(own_subnet, state, slices) :=&lt;br /&gt;
    state_and_payload_indexes(&lt;br /&gt;
        state,&lt;br /&gt;
        { (src ↦ slice) | payload ∈ slices ∧&lt;br /&gt;
                          (src ↦ cert_slice) ∈ payload ∧&lt;br /&gt;
                          slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                             cert_slice)&lt;br /&gt;
        }&lt;br /&gt;
    )&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creation of XNet Payloads ====&lt;br /&gt;
Based on the functions above, we are now ready to define the function &amp;lt;code&amp;gt;get_xnet_payload : Height × Height × Set&amp;lt;XNetPayload&amp;gt; → XNetPayload&amp;lt;/code&amp;gt;. Note that the gap-freeness of streams is an invariant of the datatype, which is why we do not explicitly include the rule for gap-freeness here.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Build an xnet payload containing the currently available streams. The begin is either given&lt;br /&gt;
% by the expected index, and, if there is no expected index for a given prefix, the index&lt;br /&gt;
% ONE is expected.&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: size_of(get_xnet_payload(self, ·, ·, ·, size_limit)) ≤ size_limit&lt;br /&gt;
%&lt;br /&gt;
get_xnet_payload : Self × RegistryVersion × Height × Vec&amp;lt;XNetPayload&amp;gt; × ℕ → XNetPayload&lt;br /&gt;
get_xnet_payload(self, registry_version, reference_height, past_payloads, size_limit) :=&lt;br /&gt;
    { (remote_subnet ↦ slice) |&lt;br /&gt;
            S = StateManager.get_state_at(reference_height)&lt;br /&gt;
          ∧ subnets = Registry::get_registry_at(registry_version).subnets \ { self.own_subnet }&lt;br /&gt;
          ∧ (remote_subnet, begin_index) ∈&lt;br /&gt;
                  expected_indexes(self.own_subnet, S, past_payloads)&lt;br /&gt;
                ∪ { (subnet_id, StreamIndex::ONE) |&lt;br /&gt;
                        subnet_id ∈ subnets&lt;br /&gt;
                                    \ { s | (s, ·) ∈ expected_indexes(self.own_subnet,&lt;br /&gt;
                                                                      S,&lt;br /&gt;
                                                                      past_payloads)&lt;br /&gt;
                                      }&lt;br /&gt;
                  }&lt;br /&gt;
            % msg_limit and size limit need to be set by the implementation as appropriate&lt;br /&gt;
            % to satisfy the post condition&lt;br /&gt;
          ∧ slice = XNetEndpoint::get(subnet).get_stream(remote_subnet, begin_index, ·, ·)&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Validation of XNet Payloads ====&lt;br /&gt;
Validation of XNetPayloads works analogously to the creation. The function &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; is defined as follows, where we assume that it evaluates to false in case an error occurs. Again, note that the gap-freeness of streams is an invariant of the datatype, which is why we do not explicitly include the rule for gap-freeness here.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Check whether a given xnet payload was built according to the rules given above.&lt;br /&gt;
%&lt;br /&gt;
% FAIL IF: size_of(payload) &amp;gt; size_limit&lt;br /&gt;
%&lt;br /&gt;
validate_xnet_payload : Self × RegistryVersion × Height × Vec&amp;lt;XNetPayload&amp;gt; × XNetPayload × ℕ → Bool&lt;br /&gt;
validate_xnet_payload(self, registry_version, reference_height, past_payloads, payload, size_limit) :=&lt;br /&gt;
    S = StateManager.get_state_at(reference_height) ∧&lt;br /&gt;
    ∀ (remote_subnet ↦ css) ∈ payload :&lt;br /&gt;
    {&lt;br /&gt;
      slice = StateManager.decode_certified_stream(registry_version,&lt;br /&gt;
                                                   self.own_subnet,&lt;br /&gt;
                                                   remote_subnet,&lt;br /&gt;
                                                   css) ∧&lt;br /&gt;
      ∀ index ∈ min(dom(slice.msgs.elements)) :&lt;br /&gt;
      {&lt;br /&gt;
        (remote_subnet, index) ∈ expected_indexes(S, past_payloads) ∨&lt;br /&gt;
        index = (remote_subnet, StreamIndex::ONE)&lt;br /&gt;
      }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3412</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3412"/>
		<updated>2022-11-03T13:14:34Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;br /&gt;
&lt;br /&gt;
== XNet Transfer ==&lt;br /&gt;
After calling &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt; at the end of a deterministic processing cycle, the state manager will take care of getting the committed state certified. Once certification is complete, the certified stream slices can be made available to block makers on other subnets. The &amp;lt;code&amp;gt;XNetTransfer&amp;lt;/code&amp;gt; subcomponent is responsible to enable this transfer. It consists of&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet.png|thumb|XNet transfer component diagram]]&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which is responsible for serving certified stream slices and making them available to &amp;lt;code&amp;gt;XNetPayloadBuilders&amp;lt;/code&amp;gt; on other subnetworks.&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;, which allows the block makers to obtain an &amp;lt;code&amp;gt;XNetPayload&amp;lt;/code&amp;gt; containing the currently available certified streams originating from other subnetworks. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; obtains those streams by interacting with &amp;lt;code&amp;gt;XNetEndpoints&amp;lt;/code&amp;gt; exposed by other subnets. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; also provides functionality for notaries to verify &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; contained in block proposals.&lt;br /&gt;
&lt;br /&gt;
We do not specify anything about the protocol run between the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; to transfer the streams between two subnetworks. The only requirement we have is that certified streams made available by an &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; of an honest replica on some source subnetwork, they can be obtained by an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; of an honest replica on the destination subnetwork and that the information regarding which endpoints to contact is available in the Registry.&lt;br /&gt;
&lt;br /&gt;
=== Properties and Functionality ===&lt;br /&gt;
Assume an XNet transfer component on a replica part of subnet &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt;. The interface behavior of the XNet transfer component will guarantee that for any payload payload produced via&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;get_xnet_payload(registry_version, reference_height, past_payloads, size_limit)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we have that for any &amp;lt;code&amp;gt;(remote_subnet ↦ css) ∈ payload&amp;lt;/code&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;StateManager.decode_certified_stream(registry_version, own_subnet, remote_subnet, css)&amp;lt;/code&amp;gt; succeeds, i.e., returns a valid slice slice that is guaranteed to come from remote_subnet.&lt;br /&gt;
&lt;br /&gt;
* Furthermore, for each slice it will hold that a soon as the state corresponding to height &amp;lt;code&amp;gt;h = reference_height + |past_payloads|&amp;lt;/code&amp;gt; is available that &amp;lt;code&amp;gt;concatenate(remote_subnet, min(dom(slice.msgs.elements))) ∈ StateManager.get_state_at(h).expected_indexes&amp;lt;/code&amp;gt;. This means that the streams will start with the expected indexes stored in the previous state, i.e., they gap freely extend the previously seen streams.&lt;br /&gt;
&lt;br /&gt;
Payloads verified using &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; are accepted if they adhere to those requirements, and are rejected otherwise.&lt;br /&gt;
&lt;br /&gt;
=== XNet Endpoint ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; serves the streams available on some subnet to other subnets. For an implementation this will typically mean that there is some client which will handle querying the API of the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; on the remote subnet in question. We use the following abstraction to avoid explicitly talking about this client: We assume that there is a function &amp;lt;code&amp;gt;get : SubnetId → XNetEndpoint&amp;lt;/code&amp;gt; which will return an appropriate instance of &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which we can directly query using the API described below.&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet-sequence.png|thumb|XNet transfer sequence diagram]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get_stream(subnet_id : SubnetId, begin : StreamIndex, msg_limit : ℕ, size_limit : ℕ) → CertifiedStreamSlice&amp;lt;/code&amp;gt;: Returns the requested certified stream slice in its transport format.&lt;br /&gt;
&lt;br /&gt;
We require that an honest &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; pair is able to successfully obtain slices over this API.&lt;br /&gt;
&lt;br /&gt;
Looking at the bigger picture, the intuition for why this will yield a secure system is that in each round a new pair of block maker and endpoint will try to pull over a stream, which, in turn, means that eventually an honest pair will be able to obtain the stream and include it into a block.&lt;br /&gt;
&lt;br /&gt;
=== XNet Payload Builder ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; builds and verifies payloads whenever requested to do so by the block maker. The rules for whether a payload is considered valid or not must be so that every notary is guaranteed to make the same decision on the same input and that a payload built by an honest payload builder will be accepted by honest validators. Essentially the rules resemble what is described in the section on properties and functionality. However, given that the execution may be behind we can not directly look up the expected indexes in the appropriate state but need to compute it based on the referenced state and the payloads since then. Below, we provide a figure illustrating the high-level functionality: generally speaking blocks are considered valid if they adhere to the rules described in the figure and are considered invalid otherwise.&lt;br /&gt;
&lt;br /&gt;
[[File:Payload-building.png|thumb|Rules for payload building]]&lt;br /&gt;
&lt;br /&gt;
Below we formally define the operation of the component. We first define the following helper functions. We assume that &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; has an associated field &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt; which is passed whenever constructing an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;new : SubnetId → Self&lt;br /&gt;
new(own_subnet) :=&lt;br /&gt;
  XNetPayloadBuilder {&lt;br /&gt;
      with&lt;br /&gt;
         └─ own_subnet := own_subnet&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The API defines the past_payloads as a vector where the past payloads are ordered with respect to the corresponding height in the chain. While this ordering allows for a more efficient implementation of the functions below it does not matter on a conceptual level. Hence we resort to looking at it as a set for the sake of simplicity.&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;slice_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, solely based on a set of Slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Take the maximum index for each individual (sub-)stream in the given set of slices and add&lt;br /&gt;
% 1 to obtain the next indexes one would expect when solely looking at the past payloads but&lt;br /&gt;
% ignoring the state.&lt;br /&gt;
slice_indexes : (SubnetId ↦ StreamSlice) → Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
slice_indexes(slices) := { i + 1 | i ∈ max(dom(slices.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;state_and_payload_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, taking into account both the expected indices in the given replicated state and the more recent messages in the given slices from the past payloads.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Take the expected indexes from the state, remove whatever index appears in the given&lt;br /&gt;
% slices and add the expected indexes according to the streams in the slices.&lt;br /&gt;
%&lt;br /&gt;
% FAIL IF: ∃ i, j ∈ state_and_payload_indexes(state, slices) :&lt;br /&gt;
%              prefix(i) = prefix(j) ∧ postfix(i) ≠ postfix(j)&lt;br /&gt;
%&lt;br /&gt;
state_and_payload_indexes : ReplicatedState ×&lt;br /&gt;
                            (SubnetId ↦ StreamSlice) →&lt;br /&gt;
                            Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
state_and_payload_indexes(state, slices) := state.expected_xnet_indices&lt;br /&gt;
                                            \ dom(slices.msgs.elements)&lt;br /&gt;
                                            ∪ slice_indexes(slices)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The function &amp;lt;code&amp;gt;expected_indexes&amp;lt;/code&amp;gt; returns the set of expected indices for the block to be proposed, taking into account both the expected indices in the given replicated state and the more recent messages in the given past payloads.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Decode the slices in the given payload and compute the expected indexes using the&lt;br /&gt;
% expected_indexes function above&lt;br /&gt;
expected_indexes : SubnetId ×&lt;br /&gt;
                   ReplicatedState ×&lt;br /&gt;
                   (SubnetId ↦ StreamSlice) →&lt;br /&gt;
                   Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
expected_indexes(own_subnet, state, slices) :=&lt;br /&gt;
    state_and_payload_indexes(&lt;br /&gt;
        state,&lt;br /&gt;
        { (src ↦ slice) | payload ∈ slices ∧&lt;br /&gt;
                          (src ↦ cert_slice) ∈ payload ∧&lt;br /&gt;
                          slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                             cert_slice)&lt;br /&gt;
        }&lt;br /&gt;
    )&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creation of XNet Payloads ====&lt;br /&gt;
Based on the functions above, we are now ready to define the function &amp;lt;code&amp;gt;get_xnet_payload : Height × Height × Set&amp;lt;XNetPayload&amp;gt; → XNetPayload&amp;lt;/code&amp;gt;. Note that the gap-freeness of streams is an invariant of the datatype, which is why we do not explicitly include the rule for gap-freeness here.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Build an xnet payload containing the currently available streams. The begin is either given&lt;br /&gt;
% by the expected index, and, if there is no expected index for a given prefix, the index&lt;br /&gt;
% ONE is expected.&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: size_of(get_xnet_payload(self, ·, ·, ·, size_limit)) ≤ size_limit&lt;br /&gt;
%&lt;br /&gt;
get_xnet_payload : Self × RegistryVersion × Height × Vec&amp;lt;XNetPayload&amp;gt; × ℕ → XNetPayload&lt;br /&gt;
get_xnet_payload(self, registry_version, reference_height, past_payloads, size_limit) :=&lt;br /&gt;
    { (remote_subnet ↦ slice) |&lt;br /&gt;
            S = StateManager.get_state_at(reference_height)&lt;br /&gt;
          ∧ subnets = Registry::get_registry_at(registry_version).subnets \ { self.own_subnet }&lt;br /&gt;
          ∧ (remote_subnet, begin_index) ∈&lt;br /&gt;
                  expected_indexes(self.own_subnet, S, past_payloads)&lt;br /&gt;
                ∪ { (subnet_id, StreamIndex::ONE) |&lt;br /&gt;
                        subnet_id ∈ subnets&lt;br /&gt;
                                    \ { s | (s, ·) ∈ expected_indexes(self.own_subnet,&lt;br /&gt;
                                                                      S,&lt;br /&gt;
                                                                      past_payloads)&lt;br /&gt;
                                      }&lt;br /&gt;
                  }&lt;br /&gt;
            % msg_limit and size limit need to be set by the implementation as appropriate&lt;br /&gt;
            % to satisfy the post condition&lt;br /&gt;
          ∧ slice = XNetEndpoint::get(subnet).get_stream(remote_subnet, begin_index, ·, ·)&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Validation of XNet Payloads ====&lt;br /&gt;
Validation of XNetPayloads works analogously to the creation. The function &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; is defined as follows, where we assume that it evaluates to false in case an error occurs. Again, note that the gap-freeness of streams is an invariant of the datatype, which is why we do not explicitly include the rule for gap-freeness here.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Check whether a given xnet payload was built according to the rules given above.&lt;br /&gt;
%&lt;br /&gt;
% FAIL IF: size_of(payload) &amp;gt; size_limit&lt;br /&gt;
%&lt;br /&gt;
validate_xnet_payload : Self × RegistryVersion × Height × Vec&amp;lt;XNetPayload&amp;gt; × XNetPayload × ℕ → Bool&lt;br /&gt;
validate_xnet_payload(self, registry_version, reference_height, past_payloads, payload, size_limit) :=&lt;br /&gt;
    S = StateManager.get_state_at(reference_height) ∧&lt;br /&gt;
    ∀ (remote_subnet ↦ css) ∈ payload :&lt;br /&gt;
    {&lt;br /&gt;
      slice = StateManager.decode_certified_stream(registry_version,&lt;br /&gt;
                                                   self.own_subnet,&lt;br /&gt;
                                                   remote_subnet,&lt;br /&gt;
                                                   css) ∧&lt;br /&gt;
      ∀ index ∈ min(dom(slice.msgs.elements)) :&lt;br /&gt;
      {&lt;br /&gt;
        (remote_subnet, index) ∈ expected_indexes(S, past_payloads) ∨&lt;br /&gt;
        index = (remote_subnet, StreamIndex::ONE)&lt;br /&gt;
      }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3411</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3411"/>
		<updated>2022-11-03T13:08:24Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;br /&gt;
&lt;br /&gt;
== XNet Transfer ==&lt;br /&gt;
After calling &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt; at the end of a deterministic processing cycle, the state manager will take care of getting the committed state certified. Once certification is complete, the certified stream slices can be made available to block makers on other subnets. The &amp;lt;code&amp;gt;XNetTransfer&amp;lt;/code&amp;gt; subcomponent is responsible to enable this transfer. It consists of&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet.png|thumb|XNet transfer component diagram]]&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which is responsible for serving certified stream slices and making them available to &amp;lt;code&amp;gt;XNetPayloadBuilders&amp;lt;/code&amp;gt; on other subnetworks.&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;, which allows the block makers to obtain an &amp;lt;code&amp;gt;XNetPayload&amp;lt;/code&amp;gt; containing the currently available certified streams originating from other subnetworks. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; obtains those streams by interacting with &amp;lt;code&amp;gt;XNetEndpoints&amp;lt;/code&amp;gt; exposed by other subnets. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; also provides functionality for notaries to verify &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; contained in block proposals.&lt;br /&gt;
&lt;br /&gt;
We do not specify anything about the protocol run between the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; to transfer the streams between two subnetworks. The only requirement we have is that certified streams made available by an &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; of an honest replica on some source subnetwork, they can be obtained by an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; of an honest replica on the destination subnetwork and that the information regarding which endpoints to contact is available in the Registry.&lt;br /&gt;
&lt;br /&gt;
=== Properties and Functionality ===&lt;br /&gt;
Assume an XNet transfer component on a replica part of subnet &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt;. The interface behavior of the XNet transfer component will guarantee that for any payload payload produced via&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;get_xnet_payload(registry_version, reference_height, past_payloads, size_limit)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we have that for any &amp;lt;code&amp;gt;(remote_subnet ↦ css) ∈ payload&amp;lt;/code&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;StateManager.decode_certified_stream(registry_version, own_subnet, remote_subnet, css)&amp;lt;/code&amp;gt; succeeds, i.e., returns a valid slice slice that is guaranteed to come from remote_subnet.&lt;br /&gt;
&lt;br /&gt;
* Furthermore, for each slice it will hold that a soon as the state corresponding to height &amp;lt;code&amp;gt;h = reference_height + |past_payloads|&amp;lt;/code&amp;gt; is available that &amp;lt;code&amp;gt;concatenate(remote_subnet, min(dom(slice.msgs.elements))) ∈ StateManager.get_state_at(h).expected_indexes&amp;lt;/code&amp;gt;. This means that the streams will start with the expected indexes stored in the previous state, i.e., they gap freely extend the previously seen streams.&lt;br /&gt;
&lt;br /&gt;
Payloads verified using &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; are accepted if they adhere to those requirements, and are rejected otherwise.&lt;br /&gt;
&lt;br /&gt;
=== XNet Endpoint ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; serves the streams available on some subnet to other subnets. For an implementation this will typically mean that there is some client which will handle querying the API of the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; on the remote subnet in question. We use the following abstraction to avoid explicitly talking about this client: We assume that there is a function &amp;lt;code&amp;gt;get : SubnetId → XNetEndpoint&amp;lt;/code&amp;gt; which will return an appropriate instance of &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which we can directly query using the API described below.&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet-sequence.png|thumb|XNet transfer sequence diagram]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get_stream(subnet_id : SubnetId, begin : StreamIndex, msg_limit : ℕ, size_limit : ℕ) → CertifiedStreamSlice&amp;lt;/code&amp;gt;: Returns the requested certified stream slice in its transport format.&lt;br /&gt;
&lt;br /&gt;
We require that an honest &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; pair is able to successfully obtain slices over this API.&lt;br /&gt;
&lt;br /&gt;
Looking at the bigger picture, the intuition for why this will yield a secure system is that in each round a new pair of block maker and endpoint will try to pull over a stream, which, in turn, means that eventually an honest pair will be able to obtain the stream and include it into a block.&lt;br /&gt;
&lt;br /&gt;
=== XNet Payload Builder ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; builds and verifies payloads whenever requested to do so by the block maker. The rules for whether a payload is considered valid or not must be so that every notary is guaranteed to make the same decision on the same input and that a payload built by an honest payload builder will be accepted by honest validators. Essentially the rules resemble what is described in the section on properties and functionality. However, given that the execution may be behind we can not directly look up the expected indexes in the appropriate state but need to compute it based on the referenced state and the payloads since then. Below, we provide a figure illustrating the high-level functionality: generally speaking blocks are considered valid if they adhere to the rules described in the figure and are considered invalid otherwise.&lt;br /&gt;
&lt;br /&gt;
[[File:Payload-building.png|thumb|Rules for payload building]]&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=File:Payload-building.png&amp;diff=3410</id>
		<title>File:Payload-building.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=File:Payload-building.png&amp;diff=3410"/>
		<updated>2022-11-03T13:08:14Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Rules for payload building&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3409</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3409"/>
		<updated>2022-11-03T13:05:40Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;br /&gt;
&lt;br /&gt;
== XNet Transfer ==&lt;br /&gt;
After calling &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt; at the end of a deterministic processing cycle, the state manager will take care of getting the committed state certified. Once certification is complete, the certified stream slices can be made available to block makers on other subnets. The &amp;lt;code&amp;gt;XNetTransfer&amp;lt;/code&amp;gt; subcomponent is responsible to enable this transfer. It consists of&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet.png|thumb|XNet transfer component diagram]]&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which is responsible for serving certified stream slices and making them available to &amp;lt;code&amp;gt;XNetPayloadBuilders&amp;lt;/code&amp;gt; on other subnetworks.&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;, which allows the block makers to obtain an &amp;lt;code&amp;gt;XNetPayload&amp;lt;/code&amp;gt; containing the currently available certified streams originating from other subnetworks. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; obtains those streams by interacting with &amp;lt;code&amp;gt;XNetEndpoints&amp;lt;/code&amp;gt; exposed by other subnets. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; also provides functionality for notaries to verify &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; contained in block proposals.&lt;br /&gt;
&lt;br /&gt;
We do not specify anything about the protocol run between the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; to transfer the streams between two subnetworks. The only requirement we have is that certified streams made available by an &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; of an honest replica on some source subnetwork, they can be obtained by an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; of an honest replica on the destination subnetwork and that the information regarding which endpoints to contact is available in the Registry.&lt;br /&gt;
&lt;br /&gt;
=== Properties and Functionality ===&lt;br /&gt;
Assume an XNet transfer component on a replica part of subnet &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt;. The interface behavior of the XNet transfer component will guarantee that for any payload payload produced via&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;get_xnet_payload(registry_version, reference_height, past_payloads, size_limit)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we have that for any &amp;lt;code&amp;gt;(remote_subnet ↦ css) ∈ payload&amp;lt;/code&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;StateManager.decode_certified_stream(registry_version, own_subnet, remote_subnet, css)&amp;lt;/code&amp;gt; succeeds, i.e., returns a valid slice slice that is guaranteed to come from remote_subnet.&lt;br /&gt;
&lt;br /&gt;
* Furthermore, for each slice it will hold that a soon as the state corresponding to height &amp;lt;code&amp;gt;h = reference_height + |past_payloads|&amp;lt;/code&amp;gt; is available that &amp;lt;code&amp;gt;concatenate(remote_subnet, min(dom(slice.msgs.elements))) ∈ StateManager.get_state_at(h).expected_indexes&amp;lt;/code&amp;gt;. This means that the streams will start with the expected indexes stored in the previous state, i.e., they gap freely extend the previously seen streams.&lt;br /&gt;
&lt;br /&gt;
Payloads verified using &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; are accepted if they adhere to those requirements, and are rejected otherwise.&lt;br /&gt;
&lt;br /&gt;
=== XNet Endpoint ===&lt;br /&gt;
The &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; serves the streams available on some subnet to other subnets. For an implementation this will typically mean that there is some client which will handle querying the API of the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; on the remote subnet in question. We use the following abstraction to avoid explicitly talking about this client: We assume that there is a function &amp;lt;code&amp;gt;get : SubnetId → XNetEndpoint&amp;lt;/code&amp;gt; which will return an appropriate instance of &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which we can directly query using the API described below.&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet-sequence.png|thumb|XNet transfer sequence diagram]]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get_stream(subnet_id : SubnetId, begin : StreamIndex, msg_limit : ℕ, size_limit : ℕ) → CertifiedStreamSlice&amp;lt;/code&amp;gt;: Returns the requested certified stream slice in its transport format.&lt;br /&gt;
&lt;br /&gt;
We require that an honest &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;-&amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; pair is able to successfully obtain slices over this API.&lt;br /&gt;
&lt;br /&gt;
Looking at the bigger picture, the intuition for why this will yield a secure system is that in each round a new pair of block maker and endpoint will try to pull over a stream, which, in turn, means that eventually an honest pair will be able to obtain the stream and include it into a block.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3408</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3408"/>
		<updated>2022-11-03T13:00:19Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;br /&gt;
&lt;br /&gt;
== XNet Transfer ==&lt;br /&gt;
After calling &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt; at the end of a deterministic processing cycle, the state manager will take care of getting the committed state certified. Once certification is complete, the certified stream slices can be made available to block makers on other subnets. The &amp;lt;code&amp;gt;XNetTransfer&amp;lt;/code&amp;gt; subcomponent is responsible to enable this transfer. It consists of&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet.png|thumb|XNet transfer component diagram]]&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which is responsible for serving certified stream slices and making them available to &amp;lt;code&amp;gt;XNetPayloadBuilders&amp;lt;/code&amp;gt; on other subnetworks.&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;, which allows the block makers to obtain an &amp;lt;code&amp;gt;XNetPayload&amp;lt;/code&amp;gt; containing the currently available certified streams originating from other subnetworks. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; obtains those streams by interacting with &amp;lt;code&amp;gt;XNetEndpoints&amp;lt;/code&amp;gt; exposed by other subnets. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; also provides functionality for notaries to verify &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; contained in block proposals.&lt;br /&gt;
&lt;br /&gt;
We do not specify anything about the protocol run between the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; to transfer the streams between two subnetworks. The only requirement we have is that certified streams made available by an &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; of an honest replica on some source subnetwork, they can be obtained by an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; of an honest replica on the destination subnetwork and that the information regarding which endpoints to contact is available in the Registry.&lt;br /&gt;
&lt;br /&gt;
=== Properties and Functionality ===&lt;br /&gt;
Assume an XNet transfer component on a replica part of subnet &amp;lt;code&amp;gt;own_subnet&amp;lt;/code&amp;gt;. The interface behavior of the XNet transfer component will guarantee that for any payload payload produced via&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;get_xnet_payload(registry_version, reference_height, past_payloads, size_limit)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we have that for any &amp;lt;code&amp;gt;(remote_subnet ↦ css) ∈ payload&amp;lt;/code&amp;gt;: &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;StateManager.decode_certified_stream(registry_version, own_subnet, remote_subnet, css)&amp;lt;/code&amp;gt; succeeds, i.e., returns a valid slice slice that is guaranteed to come from remote_subnet.&lt;br /&gt;
&lt;br /&gt;
* Furthermore, for each slice it will hold that a soon as the state corresponding to height &amp;lt;code&amp;gt;h = reference_height + |past_payloads|&amp;lt;/code&amp;gt; is available that &amp;lt;code&amp;gt;concatenate(remote_subnet, min(dom(slice.msgs.elements))) ∈ StateManager.get_state_at(h).expected_indexes&amp;lt;/code&amp;gt;. This means that the streams will start with the expected indexes stored in the previous state, i.e., they gap freely extend the previously seen streams.&lt;br /&gt;
&lt;br /&gt;
Payloads verified using &amp;lt;code&amp;gt;validate_xnet_payload&amp;lt;/code&amp;gt; are accepted if they adhere to those requirements, and are rejected otherwise.&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet-sequence.png|thumb|XNet transfer sequence diagram]]&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3407</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3407"/>
		<updated>2022-11-03T12:57:09Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;br /&gt;
&lt;br /&gt;
== XNet Transfer ==&lt;br /&gt;
After calling &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt; at the end of a deterministic processing cycle, the state manager will take care of getting the committed state certified. Once certification is complete, the certified stream slices can be made available to block makers on other subnets. The &amp;lt;code&amp;gt;XNetTransfer&amp;lt;/code&amp;gt; subcomponent is responsible to enable this transfer. It consists of&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet.png|thumb|XNet transfer component diagram]]&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which is responsible for serving certified stream slices and making them available to &amp;lt;code&amp;gt;XNetPayloadBuilders&amp;lt;/code&amp;gt; on other subnetworks.&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;, which allows the block makers to obtain an &amp;lt;code&amp;gt;XNetPayload&amp;lt;/code&amp;gt; containing the currently available certified streams originating from other subnetworks. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; obtains those streams by interacting with &amp;lt;code&amp;gt;XNetEndpoints&amp;lt;/code&amp;gt; exposed by other subnets. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; also provides functionality for notaries to verify &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; contained in block proposals.&lt;br /&gt;
&lt;br /&gt;
We do not specify anything about the protocol run between the &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; to transfer the streams between two subnetworks. The only requirement we have is that certified streams made available by an &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; of an honest replica on some source subnetwork, they can be obtained by an &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; of an honest replica on the destination subnetwork and that the information regarding which endpoints to contact is available in the Registry.&lt;br /&gt;
&lt;br /&gt;
[[File:Xnet-sequence.png|thumb|XNet transfer sequence diagram]]&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=File:Xnet-sequence.png&amp;diff=3406</id>
		<title>File:Xnet-sequence.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=File:Xnet-sequence.png&amp;diff=3406"/>
		<updated>2022-11-03T12:56:47Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;XNet transfer sequence diagram&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=File:Xnet.png&amp;diff=3405</id>
		<title>File:Xnet.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=File:Xnet.png&amp;diff=3405"/>
		<updated>2022-11-03T12:55:54Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;XNet transfer component diagram&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3404</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3404"/>
		<updated>2022-11-03T12:53:07Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;br /&gt;
&lt;br /&gt;
== XNet Transfer ==&lt;br /&gt;
After calling &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt; at the end of a deterministic processing cycle, the state manager will take care of getting the committed state certified. Once certification is complete, the certified stream slices can be made available to block makers on other subnets. The &amp;lt;code&amp;gt;XNetTransfer&amp;lt;/code&amp;gt; subcomponent is responsible to enable this transfer. It consists of&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetEndpoint&amp;lt;/code&amp;gt; which is responsible for serving certified stream slices and making them available to &amp;lt;code&amp;gt;XNetPayloadBuilders&amp;lt;/code&amp;gt; on other subnetworks.&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt;, which allows the block makers to obtain an &amp;lt;code&amp;gt;XNetPayload&amp;lt;/code&amp;gt; containing the currently available certified streams originating from other subnetworks. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; obtains those streams by interacting with &amp;lt;code&amp;gt;XNetEndpoints&amp;lt;/code&amp;gt; exposed by other subnets. The &amp;lt;code&amp;gt;XNetPayloadBuilder&amp;lt;/code&amp;gt; also provides functionality for notaries to verify &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; contained in block proposals.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3403</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3403"/>
		<updated>2022-11-03T12:50:25Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ordering of Messages in the Stream &amp;amp; Fairness&#039;&#039;. As long as the invariant that the canister-to-canister ordering of messages is preserved when iterating over the filtered messages in the state transition described above, the implementation can take the freedom to apply alternative orderings.&lt;br /&gt;
&lt;br /&gt;
Also note that, while the state transition defined above empties the output queues completely, this is not crucial to the design and one could hold back messages as long as this does not violate the ordering requirement.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3402</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3402"/>
		<updated>2022-11-03T12:49:53Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Non flat streams.&#039;&#039; As already mentioned before, the specification leaves it open whether one flat stream is produced per destination subnet, or whether each of the streams has multiple substreams—​this can be decided by the implementation. To enable this, a &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a tuple of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; and a natural number. If we have a flat stream, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt; which effectively means that the implementation can use natural numbers as stream index as one does not need to make the &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; explicit in this case. In contrast, if we have per-destination (or per-source) substreams, &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt; is defined to be a &amp;lt;code&amp;gt;CanisterId&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Formally, this means that the implementation must fix a mapping function that—​based on a given prefix of a &amp;lt;code&amp;gt;QueueIndex&amp;lt;/code&amp;gt;, i.e., a src-dst tuple—​decides on the prefix of the &amp;lt;code&amp;gt;StreamIndex&amp;lt;/code&amp;gt;, i.e., the SubstreamId.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;substream_id: (CanisterId × CanisterId) → SubstreamId&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for flat streams&lt;br /&gt;
substream_id((src, dst)) := ()&lt;br /&gt;
&lt;br /&gt;
% Definition of substream_id for per-destination canister substreams&lt;br /&gt;
substream_id((src, dst)) := dst&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Description of the actual state transition&#039;&#039;. The state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;post_process(S, subnet_assignment)&amp;lt;/code&amp;gt; is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Clear the output queues&lt;br /&gt;
  output_queues := clear(S.output_queues)&lt;br /&gt;
&lt;br /&gt;
  % Route the messages produced in the previous execution phase to the appropriate streams&lt;br /&gt;
  % taking into account ordering and capacity management constraints enforced by stream_index.&lt;br /&gt;
  streams.msgs  := {&lt;br /&gt;
    let msgs = S.streams.msgs&lt;br /&gt;
&lt;br /&gt;
    % Iterate over filtered messages preserving order of messages in queues.&lt;br /&gt;
    for each (q_index ↦ msg) ∈ filter(S.output_queues, subnet_assignment)&lt;br /&gt;
      msgs = push(msgs, { (concatenate(substream_id(prefix(q_index)), postfix(q_index)) ↦ msg) })&lt;br /&gt;
&lt;br /&gt;
    return msgs&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  % Push NON_EXISTENT_CANISTER replies to input queues of the respective canisters&lt;br /&gt;
  input_queues := push(S.input_queues,&lt;br /&gt;
                       non_existent_canister_replies(S.output_queues, subnet_assignment))&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3401</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3401"/>
		<updated>2022-11-03T12:45:09Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Execution Phase&#039;&#039;&#039;. In the execution phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, schedules messages for execution by the hypervisor, and triggers the hypervisor to execute them, i.e., one computes &amp;lt;code&amp;gt;S&#039; = execute(S)&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the induction phase. From the perspective of message routing, the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;execute(S)&amp;lt;/code&amp;gt; looks as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Delete the consumed ingress messages from the respective ingress queues&lt;br /&gt;
  ingress_queues    := delete(S.ingress_queue, schedule_and_execute(S).consumed_ingress_messages)&lt;br /&gt;
&lt;br /&gt;
  % Delete the consumed canister to canister messages from the respective input queues&lt;br /&gt;
  input_queues      := delete(S.input_queues, schedule_and_execute(S).consumed_xnet_messages)&lt;br /&gt;
&lt;br /&gt;
  % Append the produced messages to the respective output queues&lt;br /&gt;
  output_queues     := push(S.output_queues, schedule_and_execute(S).produced_messages)&lt;br /&gt;
&lt;br /&gt;
  % Execution specific state is transformed by the execution environment; the precise transition&lt;br /&gt;
  % function is out of scope here.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;XNet Message Routing Phase&#039;&#039;&#039;. In the XNet message routing phase, one takes all the messages from the canister-to-canister output queues and, according to the subnet_assignment, puts them into a subnet-to-subnet stream, i.e., it computes &amp;lt;code&amp;gt;S&#039; = post_process(S, registry)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; is the state after the execution phase and registry represents a view of the registry.&lt;br /&gt;
&lt;br /&gt;
Before we define the state transition, we define a helper function to appropriately handle messages targeted at canisters that do not exist according to the given subnet assignment.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Remove all messages from output queues targeted at non-existent canisters according&lt;br /&gt;
% to the subnet assignment.&lt;br /&gt;
filter : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;)&lt;br /&gt;
filter(queues, subnet_assignment) :=&lt;br /&gt;
    delete(queues, { (q_index ↦ msg) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                       q_index = (·, dst, ·) ∧&lt;br /&gt;
                                       dst ∉ dom(subnet_assignment)&lt;br /&gt;
                   }&lt;br /&gt;
          )&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Produce &amp;lt;code&amp;gt;NON_EXISTENT_CANISTER&amp;lt;/code&amp;gt; replies telling the sending canister that the destination canister does not exist.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% Produce NON_EXISTENT_CANISTER messages to be pushed to input queues &lt;br /&gt;
% of the senders of messages where the destination does not exist&lt;br /&gt;
non_existent_canister_replies : ((CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;) × (CanisterId ↦ SubnetId) → (QueueIndex ↦ Message)&lt;br /&gt;
non_existent_canister_replies(queues, subnet_assignment) :=&lt;br /&gt;
  { ((dst, src, i) ↦ NON_EXISTENT_CANISTER) | (q_index ↦ msg) ∈ queues.elements ∧&lt;br /&gt;
                                              q_index = (src, dst, i) ∧&lt;br /&gt;
                                              dst ∉ dom(subnet_assignment)&lt;br /&gt;
  })&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3400</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3400"/>
		<updated>2022-11-03T12:40:35Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Finally, we can define the state &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt; resulting from computing &amp;lt;code&amp;gt;pre_process(S, b)&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;S with&lt;br /&gt;
  % Append the ingress messages accepted by the VSR to the appropriate ingress_queue&lt;br /&gt;
  ingress_queues            := push(S.ingress_queues, VSR(S, b).ingress)&lt;br /&gt;
&lt;br /&gt;
  % Append the canister to canister messages accepted by the VSR to the appropriate&lt;br /&gt;
  % input queue.&lt;br /&gt;
  input_queues              := push(S.input_queues,&lt;br /&gt;
                                    map_valid_xnet_messages(VSR(S, b).xnet, subnet_assignment)&lt;br /&gt;
                                   )&lt;br /&gt;
&lt;br /&gt;
  % Garbage collect the messages which have accepted by the target subnet.&lt;br /&gt;
  % (As soon as the VSR does no longer ACCEPT all messages, one would have&lt;br /&gt;
  %  to make sure that rejected messages are appropriately re-enqueued in&lt;br /&gt;
  %  the streams)&lt;br /&gt;
  streams.msgs              := delete(S.streams.msgs,&lt;br /&gt;
                                 { (concatenate(subnet, index) ↦ msg) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ ·) ∈ slice.signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i)&lt;br /&gt;
                                 }&lt;br /&gt;
                               )&lt;br /&gt;
&lt;br /&gt;
  % Add the signals reflecting the decisions made by the VSR in the current round and&lt;br /&gt;
  % garbage collect the signals which have already been processed on the other subnet&lt;br /&gt;
  % (one knows that a signal has been processed when the message is no longer included&lt;br /&gt;
  % in a given slice).&lt;br /&gt;
  streams.signals           := S.streams.signals&lt;br /&gt;
                               ∪ VSR(S, b).signals&lt;br /&gt;
                               \ { (index ↦ signal) |&lt;br /&gt;
                                       (subnet ↦ slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                                       (i ↦ signal) ∈ S.streams[subnet].signals ∧&lt;br /&gt;
                                       index = concatenate(subnet, i) ∧&lt;br /&gt;
                                       j ∈ slice.begin ∧&lt;br /&gt;
                                       i &amp;lt; j&lt;br /&gt;
                                 }&lt;br /&gt;
&lt;br /&gt;
  % Update the expected XNet indexes so that the block maker can compute which messages&lt;br /&gt;
  % to include in a block referencing this state.&lt;br /&gt;
  expected_xnet_indices     := { index     | index ∈ S.expected_xnet_indices ∧&lt;br /&gt;
                                             ∄ (i ↦ ·) ∈ b.xnet_payload.msgs.elements :&lt;br /&gt;
                                             └─ prefix(index) = prefix(i)&lt;br /&gt;
                               } ∪&lt;br /&gt;
                               { index + 1 | index ∈ max(dom(b.xnet_payload.msgs.elements)) }&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3399</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3399"/>
		<updated>2022-11-03T12:37:42Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Based on this we can now define a function that maps over the indexes of the valid XNet messages.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;map_valid_xnet_messages : (SubnetId ↦ Slice) ×&lt;br /&gt;
                          (CanisterId ↦ SubnetId) →&lt;br /&gt;
                          ((CanisterId × ℕ) ↦ Message)&lt;br /&gt;
map_valid_xnet_messages(slices, subnet_assignment) :=&lt;br /&gt;
    queue_index({ ((subnet, index) ↦ m) | (subnet ↦ slice) ∈ slices ∧&lt;br /&gt;
                                          (index ↦ m) ∈ slice.msgs ∧&lt;br /&gt;
                                          subnet_assignment[m.src] = subnet ∧&lt;br /&gt;
&lt;br /&gt;
               })&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3398</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3398"/>
		<updated>2022-11-03T12:37:20Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;br /&gt;
&lt;br /&gt;
==== Description of the State Transitions ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Induction Phase&#039;&#039;&#039;. In the induction phase, one starts off with a &amp;lt;code&amp;gt;CanonicalState S&amp;lt;/code&amp;gt;, some &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;DecodedBatch b&amp;lt;/code&amp;gt; and applies &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; relative to &amp;lt;code&amp;gt;subnet_assignment&amp;lt;/code&amp;gt; to obtain &amp;lt;code&amp;gt;S&#039;&amp;lt;/code&amp;gt;, i.e., one computes &amp;lt;code&amp;gt;S&#039; = pre_process(S, subnet_assignment, b)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We describe things here w.r.t. to a version of the VSR which will accept all messages, while in reality the VSR may reject some messages in case canisters migrate across subnets or subnets are split. So while the possibility that messages can be REJECTed by the VSR would require specific action of the message routing layer we omit those actions here for simplicity as they are not crucial to understand the basic functionality of message routing.&lt;br /&gt;
&lt;br /&gt;
Before we define the actual state transition we define a couple of helper functions. First we define a function that determines the order of the messages in the queues based on the order of the messages in the incoming stream slices.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRES: ∄ (s1 ↦ m1), (s2 ↦ m2) ∈ S :&lt;br /&gt;
%           └─ m1 = m2 ∧ s1 ≠ s2&lt;br /&gt;
%&lt;br /&gt;
% ENSURES: ∀ S satisfying the precondition above,&lt;br /&gt;
%          └─ ∀ (q1 ↦ m1), (q2 ↦ m2) ∈ queue_index(S) :&lt;br /&gt;
%             ├─ ∃ s1, s2 :&lt;br /&gt;
%             │  └─ (s1 ↦ m1) ∈ S ∧ (s2 ↦ m2) ∈ S ∧&lt;br /&gt;
%             └─ (m1.dst = m2.dst ∧ s1 ≤ s2) ==&amp;gt; q1 ≤ q2&lt;br /&gt;
%&lt;br /&gt;
queue_index: ((SubnetId × StreamIndex) ↦  Message) → ((CanisterId × ℕ) ↦ Message))&lt;br /&gt;
queue_index(S) := {&lt;br /&gt;
  % We do not provide a concrete implementation of this function as there are&lt;br /&gt;
  % multiple possible implementations and the choice for one also depends on&lt;br /&gt;
  % how priorities/fairness etc. are handled.&lt;br /&gt;
  %&lt;br /&gt;
  % A trivial implementation is to iterate over the given stream slices S per&lt;br /&gt;
  % subnet and for each individual slice iterate over all the messages in the&lt;br /&gt;
  % order they appear in the slice and push each message m on the right queue,&lt;br /&gt;
  % i.e., the one belonging to the destination canister. This is also the way&lt;br /&gt;
  % things are currently implemented.&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3397</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3397"/>
		<updated>2022-11-03T12:29:58Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;br /&gt;
&lt;br /&gt;
* Third, we have &amp;lt;code&amp;gt;produced_messages&amp;lt;/code&amp;gt; which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all produced messages, where the order of the messages implied by the queue index determines the order in which they need to be added to the queues.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3396</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3396"/>
		<updated>2022-11-03T12:28:54Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;br /&gt;
&lt;br /&gt;
* Second, we have &amp;lt;code&amp;gt;consumed_xnet_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;QueueIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed cross-net messages.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3395</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3395"/>
		<updated>2022-11-03T12:28:24Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;br /&gt;
&lt;br /&gt;
* First, we have &amp;lt;code&amp;gt;consumed_ingress_messages&amp;lt;/code&amp;gt;, which contains a partial map &amp;lt;code&amp;gt;IngressIndex ↦ Message&amp;lt;/code&amp;gt; containing all consumed ingress messages.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3394</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3394"/>
		<updated>2022-11-03T12:27:42Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Scheduler and Hypervisor&#039;&#039;&#039;. From the point of view of message routing, one can look at the the scheduler and the hypervisor together as one component. We model the functionality of scheduler and hypervisor as a deterministic function &amp;lt;code&amp;gt;schedule_and_execute : CanonicalState → (IngressIndex ↦ Message) × (QueueIndex ↦ Message) × (QueueIndex ↦ Message)&amp;lt;/code&amp;gt; which computes the change set introduced by the Scheduler and the Hypervisor. It takes messages from the input queues, executes them and puts new messages to the output queues.&lt;br /&gt;
&lt;br /&gt;
We will later use this function when we describe how the state transition function &amp;lt;code&amp;gt;execute(CanonicalState) → CanonicalState&amp;lt;/code&amp;gt; transforms the state. For the sake of compact notation, we use the following fields to access the individual return values of the schedule_and_execute function.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3393</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3393"/>
		<updated>2022-11-03T12:25:04Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;br /&gt;
&lt;br /&gt;
==== API ====&lt;br /&gt;
The deterministic state machine does not provide any external API functions. It only provides the following functions resembling the state transformations implemented by the individual steps of the deterministic state machine depicted above. Refer to the previous section for context regarding when the individual functions are called.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pre_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId), b : DecodedBatch) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the induction phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;execute(s : CanonicalState) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the execution phase.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;post_process(s : CanonicalState, subnet_assignment : (CanisterId ↦ SubnetId)) → CanonicalState&amp;lt;/code&amp;gt;: Triggers the XNet message routing phase.&lt;br /&gt;
&lt;br /&gt;
==== Abstractions of Other Parts of the System ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Valid Set Rule (VSR)&#039;&#039;&#039;&lt;br /&gt;
The VSR is a component that makes the decision of whether to &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; a message or to &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; a message. For message routing, &amp;lt;code&amp;gt;ACCEPT&amp;lt;/code&amp;gt; has the semantic that the execution layer takes responsibility for the message, whereas &amp;lt;code&amp;gt;REJECT&amp;lt;/code&amp;gt; has the semantic that the message is dropped and may require action from the message routing layer.&lt;br /&gt;
&lt;br /&gt;
The operation of the VSR on ingress messages is defined as follows, where &amp;lt;code&amp;gt;vsr_check_ingress : CanonicalState × Batch → Set&amp;lt;ℕ&amp;gt;&amp;lt;/code&amp;gt; is a deterministic function returning the indices of the messages in the ingress payload accepted by the VSR, which returns a possibly empty set of index-message tuples corresponding to the accepted messages in the ingress_payload of the batch. The set is determined by the concrete implementation of the VSR.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;VSR(state, batch).ingress :=&lt;br /&gt;
  { ((m_i.dst, j) ↦ m_i) | (i ↦ m_i) ∈ batch.ingress_payload&lt;br /&gt;
                           ∧ i ∈ vsr_check_ingress(state, batch)&lt;br /&gt;
                           ∧ j = Rank(i, vsr_check_ingress(state, batch))&lt;br /&gt;
  }&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3392</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3392"/>
		<updated>2022-11-03T12:16:44Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Deterministic State Machine ===&lt;br /&gt;
As shown in the sequence diagram above, the deterministic state machine implemented by message routing and execution applies batches provided by consensus to the appropriate state, additionally using some meta information provided by the registry. As discussed above, we will use state of type &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; to generally describe the operations of the message-routing-related operations of this component.&lt;br /&gt;
&lt;br /&gt;
[[File:Message-routing-data-flow.png|thumb|Data flow during batch processing]]&lt;br /&gt;
&lt;br /&gt;
The flow diagram below details the operation of the component. Its operation is logically split into three phases.&lt;br /&gt;
&lt;br /&gt;
* The induction phase, where the messages contained in the batch are preprocessed. This includes extracting them from the batch and, subject to their validity and the decision of VSR, added to the induction pool or not.&lt;br /&gt;
&lt;br /&gt;
* The execution phase, where the hypervisor is triggered to perform an execution cycle. The important thing from a message routing perspective is that it will take messages from the input queues and process them, which causes messages to be added to the output queues.&lt;br /&gt;
&lt;br /&gt;
* The XNet message routing phase, where the messages produced in the execution cycle are post-processed. This means that they are taken from the canister-to-canister output queues and routed into the appropriate subnet-to-subnet streams.&lt;br /&gt;
&lt;br /&gt;
All messages will be added to the respective destination queue/stream preserving the order they appear in the respective source stream/queue.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=File:Message-routing-data-flow.png&amp;diff=3391</id>
		<title>File:Message-routing-data-flow.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=File:Message-routing-data-flow.png&amp;diff=3391"/>
		<updated>2022-11-03T12:16:01Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Data flow during deterministic processing&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3390</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3390"/>
		<updated>2022-11-03T12:12:33Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
[[File:MR Interactions.png|thumb|Interactions of message routing with other components during a deterministic processing round]]&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3389</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3389"/>
		<updated>2022-11-03T12:10:07Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
[[File:Message Routing Components.png|thumb|Components interacting with message routing during a deterministic processing round]]&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The sequence diagram below provides further insights into a deterministic processing cycle.&lt;br /&gt;
[[File:MR Interactions.png|1024px|frameless|center|Interactions of message routing with other components during a deterministic processing round]]&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=File:MR_Interactions.png&amp;diff=3388</id>
		<title>File:MR Interactions.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=File:MR_Interactions.png&amp;diff=3388"/>
		<updated>2022-11-03T12:07:17Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Interactions of message routing with other components during a deterministic processing round&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=File:Message_Routing_Components.png&amp;diff=3387</id>
		<title>File:Message Routing Components.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=File:Message_Routing_Components.png&amp;diff=3387"/>
		<updated>2022-11-03T12:06:00Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Components message routing interacts with in a deterministic processing cycle&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3386</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3386"/>
		<updated>2022-11-03T11:31:48Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Message Routing ==&lt;br /&gt;
Message routing is triggered by incoming batches from consensus. For each &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;, message routing will perform the following steps:&lt;br /&gt;
&lt;br /&gt;
* Obtain the &amp;lt;code&amp;gt;ReplicatedState s&amp;lt;/code&amp;gt; of the right version w.r.t. &amp;lt;code&amp;gt;Batch b&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Submit &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; for processing by the deterministic state machine comprised of the message routing and execution layer. This includes&lt;br /&gt;
&lt;br /&gt;
** An induction phase (cf. &amp;lt;code&amp;gt;pre_process&amp;lt;/code&amp;gt;), where the valid messages in &amp;lt;code&amp;gt;decode(own_subnet, b)&amp;lt;/code&amp;gt; are inducted. Among others, a message m in a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; from subnet &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; is considered valid if &amp;lt;code&amp;gt;registry.get_registry_at(b.registry_version).subnet_assignment&amp;lt;/code&amp;gt; maps &amp;lt;code&amp;gt;m.src&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
** An execution phase (cf. &amp;lt;code&amp;gt;execute&amp;lt;/code&amp;gt;), which executes messages available in the induction pool.&lt;br /&gt;
&lt;br /&gt;
** An XNet message routing phase (cf. &amp;lt;code&amp;gt;post_process&amp;lt;/code&amp;gt;), which moves the messages produced in the execution phase from the per-session output queues to the subnet-to-subnet streams according to the mapping defined by the subnet assignment in the registry.&lt;br /&gt;
&lt;br /&gt;
* Commit the replicated state, incrementally updated by the previous steps, to the state manager via &amp;lt;code&amp;gt;commit_and_certify&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3385</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3385"/>
		<updated>2022-11-03T11:16:02Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;br /&gt;
&lt;br /&gt;
==== Batch ====&lt;br /&gt;
A batch consists of multiple elements including an &amp;lt;code&amp;gt;ingress_payload&amp;lt;/code&amp;gt; constituting a sequence of ingress messages, and an &amp;lt;code&amp;gt;xnet_payload&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Batch {&lt;br /&gt;
    batch_number             : Height&lt;br /&gt;
    registry_version         : RegistryVersion&lt;br /&gt;
    ingress_payload          : ℕ ↦ Message&lt;br /&gt;
    xnet_payload             : SubnetId ↦ CertifiedStreamSlice&lt;br /&gt;
    requires_full_state_hash : { TRUE, FALSE }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Decoded Batch ====&lt;br /&gt;
A decoded batch represents a batch where all transport-specific things are decoded into the format suitable for processing and some things which are not required inside the deterministic state machine are stripped off.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;DecodedBatch {&lt;br /&gt;
    ingress_payload : ℕ ↦ Message&lt;br /&gt;
    xnet_payload : SubnetId ↦ StreamSlice&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently this only means decoding the &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; into &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; because we assume that the ingress payload is suitable to be processed right away. Formally there is a function, which, based on the own subnet id and the given batch decodes the batch into a decoded batch:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;decode : SubnetId × Batch → DecodedBatch&lt;br /&gt;
decode(own_subnet, b) :=&lt;br /&gt;
    DecodedBatch {&lt;br /&gt;
        with&lt;br /&gt;
           ├─ ingress_payload := b.ingress_payload&lt;br /&gt;
           └─ xnet_payload :=&lt;br /&gt;
                  { (src_subnet ↦ slice) |&lt;br /&gt;
                      (src_subnet ↦ cert_slice) ∈ b.xnet_payload ∧&lt;br /&gt;
                      slice = StateManager.decode_valid_certified_stream(own_subnet,&lt;br /&gt;
                                                                         cert_slice&lt;br /&gt;
                                                                        )&lt;br /&gt;
                  }&lt;br /&gt;
    }&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3384</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3384"/>
		<updated>2022-11-03T11:13:35Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== (Certified) Stream Slices ====&lt;br /&gt;
&amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt;, respectively, are used to transport streams from one to an other subnet within &amp;lt;code&amp;gt;XNetPayloads&amp;lt;/code&amp;gt; that are part of consensus blocks. Essentially, a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is a slice of a stream which retains the begin and the end of the original stream. A &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; is wrapped in a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; for transport so that authenticity can be guaranteed. Neither &amp;lt;code&amp;gt;CertifiedStreamSlices&amp;lt;/code&amp;gt; nor &amp;lt;code&amp;gt;StreamSlices&amp;lt;/code&amp;gt; are ever explicitly created within message routing, but instead one relies on the encoding and decoding routines provided by the state manager: A &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; is created by calling the respective encoding routine of the state manager. Such a &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt; can then be decoded into a &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; using the corresponding decoding routine provided by the state manager.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamSlice {&lt;br /&gt;
    stream    : Stream,&lt;br /&gt;
    begin     : Set&amp;lt;StreamIndex&amp;gt;,&lt;br /&gt;
    end       : Set&amp;lt;StreamIndex&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CertifiedStreamSlice {&lt;br /&gt;
    payload   : PartialCanonicalState&lt;br /&gt;
    witness   : Witness&lt;br /&gt;
    signature : Certification&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the precise relation of &amp;lt;code&amp;gt;StreamSlice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CertifiedStreamSlice&amp;lt;/code&amp;gt;, refer to the specification of the state manager.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3383</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3383"/>
		<updated>2022-11-03T11:07:02Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Streams ====&lt;br /&gt;
Each individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is scoped to a pair of subnets—​the subnet a stream originates from and subnet the stream is targeted at. An individual stream is organized in multiple substreams identified by a &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt;. The concrete definition of &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is up to the implementation. In the current implementation &amp;lt;code&amp;gt;SubstreamId&amp;lt;/code&amp;gt; is defined to be the unit type &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;, i.e., we have flat streams. Messages in streams are indexed by a concrete instance of &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; called StreamIndex which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;StreamIndex : SubstreamId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
A &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; is comprised of a sequence of &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; messages &amp;lt;code&amp;gt;signals&amp;lt;/code&amp;gt; and a sequence of canister-to-canister messages &amp;lt;code&amp;gt;msgs&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Stream {&lt;br /&gt;
    signals : StreamIndex ↦ {ACCEPT, REJECT},&lt;br /&gt;
    msgs    : SubstreamId ↦ Queue&amp;lt;Message&amp;gt;&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;Stream.msgs.elements : StreamIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
While the subnet the stream originates from is implicitly determined, the target subnet needs to be made explicit. Hence, we define a data structure Streams holding all streams indexed by destination subnetwork:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams : SubnetId ↦ Stream&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We may sometimes abuse the notation and directly access the fields defined for an individual &amp;lt;code&amp;gt;Stream&amp;lt;/code&amp;gt; on the Streams type, in which case we obtain maps of the following type:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Streams.signals : SubnetId ↦ (StreamIndex ↦ {ACCEPT, REJECT})&lt;br /&gt;
&lt;br /&gt;
Streams.msgs    : SubnetId ↦ (SubstreamId ↦ Queue&amp;lt;Message&amp;gt;)&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
	<entry>
		<id>https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3382</id>
		<title>IC message routing layer</title>
		<link rel="alternate" type="text/html" href="https://wiki.internetcomputer.org/w/index.php?title=IC_message_routing_layer&amp;diff=3382"/>
		<updated>2022-11-03T11:03:42Z</updated>

		<summary type="html">&lt;p&gt;David: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
The Internet Computer (IC) achieves its security and fault tolerance by replicating computation across node machines located in various independent data centers across the world. For scalability reasons, the Internet Computing Protocol (ICP) composes the IC of multiple independent subnets. Each subnet can be viewed as an independent replicated state machine that replicates its state over a subset of all the available nodes.&lt;br /&gt;
&lt;br /&gt;
Roughly speaking, replication is achieved by having the two lower ICP layers (P2P &amp;amp; Consensus) agree on blocks containing batches of messages to be executed, and then having the two upper ICP layers (Message Routing &amp;amp; Execution) execute them. Blocks are organized as a chain, where each block builds on the previous block. Each block has an associated height in the chain and one can look at execution of a batch of messages corresponding to the agreed upon block at height &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; by the upper layers as taking the replicated state of version &amp;lt;math&amp;gt;x-1&amp;lt;/math&amp;gt;, and &amp;quot;applying&amp;quot; the batch to it to obtain replicated state of version &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In this document we describe the role of the Message Routing layer in deterministic batch processing. Its responsibilities are:&lt;br /&gt;
* &#039;&#039;&#039;Coordinating the deterministic processing of batches:&#039;&#039;&#039; Fetching the right versions of the replicated state and the registry view to process the batch, triggering the deterministic processing, and committing the resulting replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Deterministic processing of batches:&#039;&#039;&#039; Deterministic processing of batches relative to some replicated state and some registry view, resulting in an updated replicated state.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Transferring message streams from one subnet to another:&#039;&#039;&#039; Moving streams from one subnet to another.&lt;br /&gt;
&lt;br /&gt;
=== Remarks and Required Prior Knowledge ===&lt;br /&gt;
&lt;br /&gt;
* The goal of this document is to provide the next level of detail compared to the material in the [https://internetcomputer.org/how-it-works &amp;quot;How it works&amp;quot; section of internetcomputer.org]. So it is recommended to study the material available there first.&lt;br /&gt;
* This page builds upon definitions made in the page describing the [[IC state manager|state manager]]. Please refer to this page for missing definitions related to the replicated state etc.&lt;br /&gt;
* Also see [https://mmapped.blog/posts/08-ic-xnet.html this] and [https://mmapped.blog/posts/02-ic-state-machine-replication.html this] blog post for some relevant and easier to digest background information.&lt;br /&gt;
* The documentation provided in this page may slightly deviate from the current implementation in terms of API as well as naming of functions, variables, etc. However, it still conveys the high-level ideas required to understand how the component itself works and how it interacts with other components. The implementation also contains several optimizations which are, however, not important for the conceptual overview here and therefore skipped.&lt;br /&gt;
* The notation used in this page is described [[Notation|here]].&lt;br /&gt;
&lt;br /&gt;
=== Replicated vs. Canonical State ===&lt;br /&gt;
While the external API functions defined in this document will always take state in its implementation specific representation, i.e., as &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;, we describe the operation the message routing component performs on the state based on its canonical representation, i.e., the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt;. Given the relations between &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; as defined in the specification of the state manager, this will implicitly define how an implementation needs to act on the respective parts of the &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt;. We assume an implicit conversion from &amp;lt;code&amp;gt;ReplicatedState&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; whenever we access some state passed to this component via an API function.&lt;br /&gt;
&lt;br /&gt;
== Guarantees Provided by Message Routing ==&lt;br /&gt;
Intuitively, the goal of the message routing layer is to enable transparent communication of canisters across subnets. This means that this layer formally does not add any guarantees the system provides, but simply needs to make sure that system invariants are preserved. Those system invariants include&lt;br /&gt;
&lt;br /&gt;
* guaranteed replies (each canister-to-canister request will eventually receive a reply),&lt;br /&gt;
&lt;br /&gt;
* canister-to-canister ordering (the order of canister-to-canister requests sent from one canister to another canister is preserved), and&lt;br /&gt;
&lt;br /&gt;
* authenticity (only messages that come from canisters on the IC are processed).&lt;br /&gt;
&lt;br /&gt;
To ensure that the system invariants hold, message routing needs to provide the following guarantees:&lt;br /&gt;
&lt;br /&gt;
* Canister-to-canister messages will eventually be passed to the execution layer at the subnet the destination canister lives on exactly once.&lt;br /&gt;
&lt;br /&gt;
* If a message can not be delivered, a synthetic reject response must be produced.&lt;br /&gt;
&lt;br /&gt;
* If a canister &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; sends two messages &amp;lt;math&amp;gt;m_1&amp;lt;/math&amp;gt; and &amp;lt;math&amp;gt;m_2&amp;lt;/math&amp;gt; to a canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;, then, if none of them gets synthetically rejected, it must be guaranteed that they are put in canister &amp;lt;math&amp;gt;B&amp;lt;/math&amp;gt;&#039;s input queue from &amp;lt;math&amp;gt;A&amp;lt;/math&amp;gt; in that order.&lt;br /&gt;
&lt;br /&gt;
== Preliminaries ==&lt;br /&gt;
=== Description of the Relevant Parts of the Registry ===&lt;br /&gt;
The registry can be viewed as a central store of configuration information of the IC that is maintained by the NNS DAO. The content of the registry is held by a canister on the NNS subnet, and, roughly speaking, its authenticity is guaranteed by obtaining a certification on the content on behalf of the NNS using the certification mechanism as described in the [[IC state manager|state manager]] wiki page. Throughout this document we assume that the registry contents we work with are authentic.&lt;br /&gt;
&lt;br /&gt;
The registry entries required by this component are set of all existing subnet ids, as well as a canister-to-subnet mapping subnet_assignment. Note that the actual implementation may choose to represent the required fields differently as long as they are conceptually equivalent.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Registry {&lt;br /&gt;
    subnets : Set&amp;lt;SubnetId&amp;gt;,&lt;br /&gt;
	subnet_assignment: CanisterId ↦ SubnetId&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Description of the Relevant Canonical State ===&lt;br /&gt;
Below, we define the parts of the canonical state which are relevant for the description of this component together with some constraints we impose on the replicated state. Abstractly the &amp;lt;code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; is defined as a nested partial map. For easier readability we bundle together the entries of the outermost map in a data structure with multiple fields where the names of the fields represent the keys in the respective partial map, e.g., for some &amp;lt;code&amp;gt;s : CanonicalState&amp;lt;/code&amp;gt; we can use &amp;lt;code&amp;gt;s.ingress_queue&amp;lt;/code&amp;gt; to access &amp;lt;code&amp;gt;s[ingress_queues]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We start by defining the individual fields of the type &amp;lt;/code&amp;gt;CanonicalState&amp;lt;/code&amp;gt; which are relevant in the context of this document. After that we give more details about the datatypes of the individual fields. We distinguish between the parts which are exclusively visible to message routing, and the parts which are also visible to the execution layer.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to message routing and execution&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    ingress_queues  : IngressQueues,&lt;br /&gt;
    input_queues    : InputQueues,&lt;br /&gt;
    output_queues   : OutputQueues,&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Parts visible to Message Routing only&#039;&#039;&#039;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;CanonicalState {&lt;br /&gt;
    ...&lt;br /&gt;
    streams               : Streams,&lt;br /&gt;
    expected_xnet_indices : Set&amp;lt;(SubnetId × StreamIndex)&amp;gt;&lt;br /&gt;
    ...&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even though there are parts of the state that are accessed by both message routing and execution, one can enforce a conceptual boundary between them. In particular, for input queues we have that message routing will only ever push messages to them, whereas for output queues we have that message routing will only ever pull messages from them. The opposite holds for the execution environment.&lt;br /&gt;
&lt;br /&gt;
==== Abstract Queues ====&lt;br /&gt;
We define a generic queue type &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; which has the following fields:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Queue&amp;lt;T&amp;gt; {&lt;br /&gt;
    next_index : ℕ,     // Rolling index; the index of the next message to be inserted&lt;br /&gt;
    elements   : ℕ ↦ T  // The elements currently in the queue&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We define a new queue as &amp;lt;code&amp;gt;new_queue : Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;new_queue.elements = ∅&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;new_queue.next_index = 1&amp;lt;/code&amp;gt;. Furthermore, it has the following associated functions:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt; takes a queue and a partial map of integers mapping to T, and returns a new queue consisting of the old queue with the given values appended. It also updates the next_index field so that it points to the index after the last inserted message.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;push : Self × (ℕ ↦ T) → Self&lt;br /&gt;
push(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index + |values|&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           ∪ { (i - 1 + k ↦ t) | i = self.next_index ∧&lt;br /&gt;
                                                 (j ↦ t) ∈ values ∧&lt;br /&gt;
                                                 k = rank(j, dom(values)) }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; removes the given elements from the queues keeping the &amp;lt;code&amp;gt;next_index&amp;lt;/code&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;% REQUIRE: values ⊆ self.elements&lt;br /&gt;
delete : Self × (ℕ ↦ T) → Self&lt;br /&gt;
delete(self, values) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := self.elements&lt;br /&gt;
                           \ values&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;clear&amp;lt;/code&amp;gt; removes all elements from the queues keeping the next_index&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;clear : Self → Self&lt;br /&gt;
clear(self) :=&lt;br /&gt;
    self with&lt;br /&gt;
            ├─ next_index := self.next_index&lt;br /&gt;
            └─ elements := ∅&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are often working with partial maps of type &amp;lt;code&amp;gt;SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;, in which case we will use the following shorthand notation. With &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt; being a queue of the aforementioned type, and &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; being a partial map of type &amp;lt;code&amp;gt;(SomeIdentifier × ℕ) ↦ T&amp;lt;/code&amp;gt;, we define the following semantic for the functions &amp;lt;code&amp;gt;f ∈ { push, delete }&amp;lt;/code&amp;gt; associated to &amp;lt;code&amp;gt;Queue&amp;lt;T&amp;gt;&amp;lt;/code&amp;gt;:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) × ((SomeIdentifier × ℕ) ↦ T) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q, v) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                                (id ↦ values) ∈ v ∧&lt;br /&gt;
                                queue&#039; = f(queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue&#039;) | (id ↦ values) ∈ v ∧&lt;br /&gt;
                                ∄ (id ↦ ·) ∈ q ∧&lt;br /&gt;
                                queue&#039; = f(Queue&amp;lt;T&amp;gt;::new_queue, values)&lt;br /&gt;
              } ∪&lt;br /&gt;
              { (id ↦ queue) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                               ∄ (id ↦ ·) ∈ v&lt;br /&gt;
              }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the functions &amp;lt;code&amp;gt;f ∈ { clear }&amp;lt;/code&amp;gt; we use&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;f_map : (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;) → (SomeIdentifier ↦ Queue&amp;lt;T&amp;gt;)&lt;br /&gt;
f_map(q) = { (id ↦ queue&#039;) | (id ↦ queue) ∈ q ∧&lt;br /&gt;
                             queue&#039; = f(queue)&lt;br /&gt;
           }&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will henceforth omit the &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; postfix in &amp;lt;code&amp;gt;f_map&amp;lt;/code&amp;gt; and simply use &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; if it is clear from the input type that the map variant of &amp;lt;code&amp;gt;f&amp;lt;/code&amp;gt; should be used.&lt;br /&gt;
&lt;br /&gt;
==== Indices ====&lt;br /&gt;
We define an &amp;lt;code&amp;gt;Index&amp;lt;/code&amp;gt; to be an arbitrary length sequence, where every element in the sequence up to the last one can have an arbitrary type, and the last one is a natural number.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;Index : X × ... × Y × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition we define the following semantic:&lt;br /&gt;
&lt;br /&gt;
* We define the prefix of an index Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;prefix(i) := i[1…​|i| - 1] = (x, …​, y)&amp;lt;/code&amp;gt;, i.e., it contains all elements of i except the last one.&lt;br /&gt;
&lt;br /&gt;
* We define the postfix of an Index &amp;lt;code&amp;gt;i := (x, …​, y, seq_nr)&amp;lt;/code&amp;gt; as &amp;lt;/code&amp;gt;postfix(i) := i[|i|] = seq_nr&amp;lt;/code&amp;gt;, i.e., the last element of the index sequence. As already mentioned, we require the postfix of an index to be a natural number.&lt;br /&gt;
&lt;br /&gt;
* For an &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt;, the operation &amp;lt;math&amp;gt;i + 1&amp;lt;/math&amp;gt; is defined as &amp;lt;code&amp;gt;concatenate(prefix(i), postfix(i) + 1)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, are incomparable if &amp;lt;code&amp;gt;prefix(i) ≠ prefix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* For two indices, &amp;lt;code&amp;gt;Index i&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Index j&amp;lt;/code&amp;gt;, we have that &amp;lt;math&amp;gt;i \leq j&amp;lt;/math&amp;gt; if &amp;lt;code&amp;gt;prefix(i) = prefix(j)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;postfix(i) ≤ postfix(j)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Queues ====&lt;br /&gt;
&lt;br /&gt;
We distinguish three different types of queues in the replicated state: ingress queues, input queues, and output queues. Ingress queues contain the incoming messages from users (i.e., ingress messages). Input queues contain the incoming canister-to-canister messages. Output queues contain the outgoing canister-to-canister messages.&lt;br /&gt;
&lt;br /&gt;
Ingress queues are organized on a per destination basis. Messages in ingress queues are indexed by a concrete instance of Index called &amp;lt;code&amp;gt;IngressIndex&amp;lt;/code&amp;gt;, which is a tuple consisting of the destination canister ID and a natural number, i.e.,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressIndex : CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Input queues and output queues are organized on a per-source-and-destination basis. Messages in input- and output queues are indexed by a concrete instance of Index called QueueIndex, which is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;QueueIndex : CanisterId × CanisterId × ℕ&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The type representing all of the ingress queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;IngressQueues : CanisterId ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;IngressQueues.elements : IngressIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the input queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;InputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;InputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The type representing all of the output queues is defined as follows:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;OutputQueues : (CanisterId × CanisterId) ↦ Queue&amp;lt;Message&amp;gt;,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
which means that &amp;lt;code&amp;gt;OutputQueues.elements : QueueIndex ↦ Message&amp;lt;/code&amp;gt;.&lt;/div&gt;</summary>
		<author><name>David</name></author>
	</entry>
</feed>