8

When registering a parachain on a relay-chain you need to provide something called head data (or also referred as genesis state) and wasm.

What is this head data and how do I get that?

3 Answers 3

8

Parachains can be seen as a function h' = f(h), where:

  • f is the wasm blob referred to as PVF (parachain validation function).
  • h is the current head data.
  • h' is the new head data.

"Head data" is just a small byte buffer. It is stored on the relay chain for each parachain. Cumulus uses head data to store a Substrate block header.

Upon the registration of a parachain, h0 needs to be provided. This is a very first head data and in case of Cumulus that will be the block header of the genesis block, the block 0.

In cumulus one can obtain head data using the export-genesis-state subcommand of cumulus-based collator. Similarly, genesis wasm can be obtain using export-genesis-wasm.

More information can be found in this tutorial.

3

For the curious, parachain heads are maintained in the relay chain storage using a map, defined as

// The head-data of every registered para.
    #[pallet::storage]
    #[pallet::getter(fn para_head)]
    pub(super) type Heads<T: Config> = StorageMap<_, Twox64Concat, ParaId, HeadData>; 

Source from polkadot code base: https://github.com/paritytech/polkadot/blob/aa4b5fc5df538fe281af8379fba45bc1937a2dd9/runtime/parachains/src/paras/mod.rs#L550-L553

2

The head data that is provided to the relay chain consists of three concatenated elements (in the given order):

  1. The parent block hash (32 bytes)
  2. The extrinsic root (32 bytes)
  3. The state root (32 bytes)

The parent block hash is what the name says, it's the hash of the parent block. When deploying a new parachain (from genesis), the parent hash contains 32 zero bytes, since there is no parent at genesis.

The extrinsic root summarizes the extrinsics and their order within the block. The documentation at docs.substrate.io (Feb. 22, 2023, 10:15 am UTC) describes it in the following way:

All of the transactions are bundled together as a series to be executed as defined in the runtime. [...] The transaction root is a cryptographic digest of this series. This cryptographic digest serves two purposes:

  1. It prevents any alterations to the series of transactions after the header has been built and distributed.
  2. It enables light clients to succinctly verify that any given transaction exists in a block given only knowledge of the header.

The state root summarizes the complete state of the storage at the given block within those 32 bytes. Should the underlying storage be available, a merkle proof can be executed in O(log N) time, where N is the number of storage elements. The documentation at docs.substrate.io (Feb. 22, 2023, 10:20 am UTC) describes the state root as follows:

The trie root is a representation of the data within the trie; that is, two tries with different data will always have different roots. Thus, two blockchain nodes can easily verify that they have the same state by simply comparing their trie roots.

Having these three hashes (the head) available allows anybody to verify the correctness of the local data available. By having the parent block hash, the history is referenced. By having the extrinsics root, the state-transition logic that was applied on the state of the previous block (referenced by the parent block hash) in a given order can be verified. By having the state root, the current state that resulted from applying the extrinsics on the previous state can be verified. The underlying data to verify all of that still has to be obtained by other means, ideally by completely syncing the chain and verifying each parent hash, extrinsic root and state root by applying all the changes in the given order.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.