Polkadot XCMP MMD — Minimal POC

Forum background: XCMP Design Discussion (Polkadot).


Problem and motivation

HRMP stores message payloads on the relay chain, which is expensive (storage + execution).

XCMP (MMD approach) replaces that with:

  • payloads kept off the relay chain
  • messages proven by nested Merkle proofs anchored to relay commitments

How MMD XCMP replaces HRMP (conceptually)

HRMP:

  • relay is a payload mailbox (HrmpChannelContents)
  • receiver reads relay state proofs + prunes via watermarks

MMD XCMP:

  • relay is a commitment anchor (no payload storage)
  • receiver accepts payload + proof bundle, verifies it, then executes the XCM.

Minimal POC semantics:

Read more...

Hyperbridge ISMP — state vs log, coprocessor GET flow, and relayer queue

This post supplements Hyperbridge ISMP — state_root, overlay_root, and mmr_root with a consolidated “root map + workflow” view, new framing (trie vs MMR as state vs log, not a Substrate-vs-EVM split), and notes from reading pallet_state_coprocessor and Tesseract EVM messaging.

Repo context: polytope-labs/hyperbridge.


TL;DR (one paragraph)

Hyperbridge keeps two “views” of the same ISMP object, keyed by the same commitment hash:

  • a compact ISMP child trie (Patricia / Substrate LayoutV0) for pallet state: commitment metadata, receipt bookkeeping, claim/fee data, and pointers into the offchain log
  • an append-only message MMR (ordered log) for history + succinct inclusion proofs (and relayer/EVM batch verification)

The commitment hash of a request/response is not stored twice as separate unrelated facts: it is used as a key in the trie and as a member of the MMR log, but the stored payloads differ (trie = operational metadata; MMR = message log membership).

Read more...

Hyperbridge ISMP — state_root, overlay_root, and mmr_root

Notes mirrored from Hyperbridge - ISMP Storage Proofs & Substrate Child Trie (Obsidian). Repo context: polytope-labs/hyperbridge. Protocol docs: docs.hyperbridge.network.

When reading pallet-ismp and SubstrateStateMachine, three roots show up: the parachain state_root, the optional overlay_root on StateCommitment, and the mmr_root in the per-block ConsensusDigest. They are not interchangeable; each corresponds to a different data structure and proof type.


What each root is

Name Role
state_root Root of the chain’s main Substrate state trie (Header::state_root). It commits to all pallets. Child tries are still included under this trie.
mmr_root Root of the ISMP MMR after the MMR pallet finalizes the block: an append-only tree over message leaves (full bodies stored off-chain). It appears in the header as part of ConsensusDigest, not as a separate top-level field on StateCommitment by itself.
overlay_root on StateCommitment The ISMP overlay slot carried in consensus proofs. It is not a third independent trie type in the abstract—it is whatever the chain puts in that slot (see packing below).

Each block, on_finalize builds:

Read more...

Merkle 叶子哈希、域分离与稀疏树证明(MerkleDropHelper)

结论速记

  • 关键不是“多 hash 一次更强”keccak256(keccak256(...)) 的主要价值在于域分离(domain separation),让“叶子哈希”和“内部节点哈希”的构造形状不同,避免 Merkle 结构里的“角色混淆”讨论。
  • 更标准:显式前缀(leaf/internal)通常比 ~hash 或双 keccak 更容易被审计/跨语言实现接受。
  • 验证端必须逐字对齐:叶子公式、内部节点哈希顺序(是否排序)、稀疏缺失节点默认值(0)必须完全一致。

keccak256(keccak256(abi.encode(member, amount))) 是否足以避免 second preimage?

在 Merkle 语境里,大家常担心的不是去破 Keccak 的 preimage,而是:

Read more...

Polkadot validate_block, PVF, and relay validators

Companion to Polkadot HRMP protocol (implementation guide).

What implementation.rs is

cumulus/pallets/parachain-system/src/validate_block/implementation.rs implements validate_block: take the PoV’s storage proof, build a sparse in-memory trie, override sp_io::storage (and related) host functions so validation runs inside the Wasm instead of calling the node’s DB, execute the parachain block, then return ValidationResult — head data, horizontal_messages, hrmp_watermark, upward messages, processed downward message count, optional new validation code.

The helper run_with_externalities_and_recorder wraps Substrate Externalities (Ext over proof + OverlayedChanges) so pallet storage reads/writes during execute_verified_block and the follow-up reads for the result see consistent state. That is production PVF behavior, not limited to tests.

Read more...

Polkadot HRMP protocol (implementation guide)

Implementation-oriented notes from the Polkadot SDK: relay pallet polkadot/runtime/parachains/src/hrmp.rs, inclusion wiring, and Cumulus parachain-system. See also validate_block and PVF.

What HRMP is

HRMP (Horizontally Relay-routed Message Passing) lets parachains send bytes to each other using the same conceptual model as XCMP (channels, queues), but full message payloads live in relay-chain storage. That keeps semantics simpler and makes relay resource use higher. It is described as an interim mechanism until XCMP is fully available.

Read more...

Solidity patterns

Solidity 设计模式汇总笔记

本笔记总结了用于优化 Gas 消耗、增强安全性以及改善开发体验的核心 Solidity 编程模式。

1. 重入保护模式 (Reentrancy Protection)

问题:当合约发起外部调用时,执行控制权会转移给另一方。攻击者可以利用此机会在原始操作完成前再次调用合约函数,从而导致资产被超额提取。

Read more...

Terminology in Polkadot

Terminology

PoV (Proof of Validity)

The PoV is the data package produced by parachain collators and sent to Relay Chain validators.

  • Purpose: It acts as the “argument” or evidence that a parachain has transitioned its state correctly

  • Contents: It typically includes the L2’s state proof and the witness data (extra data needed for verification)

  • Size: A PoV block is often around 5MB of untrusted data provided to the validator group

Read more...

Light client bridge

Light client bridge

Light client bridge will relay every block from source chain to target chain, normally for asset transfer just need to lock asset in some backing module or smart contract in source chain and mint the mapping asset in target chain

Components

Since the chain cannot directly access each other, the cross-chain data submission needs to be completed by a third party. This third party is the bridge relayers. Anyone can become a bridge relayer, and the bridge relayer obtains income by completing the relay task between the bridges. This incentive can promote the stable existence of bridge relayers to ensure the bridge’s regular operation.

Read more...

xcmp research

XCMP Research

workflow

xcm types

transact

call data(pallet & call index required)

#[derive(Encode, Decode)]
pub enum RelayTemplatePalletCall {
	#[codec(index = 100)] // the index should match the position of the module in `construct_runtime!`
	DoSomething(DoSomethingCall),
}

#[derive(Encode, Decode)]
pub enum DoSomethingCall {
	#[codec(index = 0)] // the index should match the position of the dispatchable in the target pallet
	Something(u32),
}

#[derive(Encode, Decode)]
pub enum CrowdloanPalletCall {
	#[codec(index = 27)] // the index should match the position of the module in `construct_runtime!`
	CrowdloanContribute(ContributeCall),
}

#[derive(Debug, PartialEq, Encode, Decode)]
pub struct Contribution {
	#[codec(compact)]
	index: ParaId,
	#[codec(compact)]
	value: BalanceOf,
	signature: Option<MultiSignature>,
}

#[derive(Encode, Decode)]
pub enum ContributeCall {
	#[codec(index = 1)] // the index should match the position of the dispatchable in the target pallet
	Contribute(Contribution),
}

format

let call = RelayTemplatePalletCall::DoSomething(DoSomethingCall::Something(some_value)).encode();

let msg = Xcm::Transact {
    origin_type: OriginKind::SovereignAccount,
    require_weight_at_most: u64::MAX,
    call: call.into(),
};

asset transfer

DepositReserveAsset

 Xcm::WithdrawAsset {
 assets: vec![MultiAsset::ConcreteFungible {
     id: location,
     amount: amount.into(),
 }],
 effects: vec![
     Order::BuyExecution {
        fees: MultiAsset::All,
        weight: 0,
        debt,
        halt_on_error: false,
        xcm: vec![]
    },
     Order::DepositReserveAsset {
         assets: vec![MultiAsset::All],
         dest: MultiLocation::X1(
             Junction::Parent,
         ),
         effects: vec![
              Order::DepositAsset {
              assets: vec![MultiAsset::All],
              dest: MultiLocation::X1(Junction::AccountId32 {
                    network: NetworkId::Any,
                    id: T::AccountId32Converter::convert(account),
              }),
          }],
     }],
}

Teleport

let msg = Xcm::WithdrawAsset {
    assets:vec![MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: some_value }],
    effects: vec![
        Order::BuyExecution {
            fees: MultiAsset::All,
            weight: 0,
            debt,
            halt_on_error: false,
            xcm: vec![]
        },
        Order::InitiateTeleport {
            assets: vec![MultiAsset::All],
            dest: MultiLocation::X1(Junction::Parachain(para_id)),
            effects: vec![
                Order::BuyExecution {
                    fees: MultiAsset::All,
                    weight: 0,
                    debt,
                    halt_on_error: false,
                    xcm: vec![]
                },
                Order::DepositAsset {
                    assets: vec![MultiAsset::All],
                    dest: MultiLocation::X1(account_32.clone()),
                },
            ]
        }
    ]
};

test code

relax xcm filter

Read more...