feat(operator): Store message commitments from Snowbrigde Outbound pallet in the Beefy leaf extra field (#61)

This PR implements functionality to store outbound message commitments
in the BEEFY MMR leaf extra field for cross-chain verification. A new
`pallet-outbound-commitment-store` has been introduced to facilitate
this process.

## Changes

- Added a new `pallet-outbound-commitment-store` pallet to capture and
store outbound message commitments
- Implemented the `CommitmentHandler` to receive commitments from the
outbound queue and store them in the new pallet
- Updated the `LeafExtraDataProvider` to include these commitments in
the BEEFY MMR leaf extra field

## Implementation Details

The process works as follows:
1. The outbound queue generates a commitment hash for messages
2. The commitment is stored in the `pallet-outbound-commitment-store`
via the `CommitmentHandler`
3. The `LeafExtraDataProvider` retrieves the latest commitment and
includes it in the BEEFY MMR leaf extra field
4. This commitment can then be verified by other chains using the BEEFY
light client

The new pallet provides the necessary functions to store and retrieve
these commitments.
This commit is contained in:
Ahmad Kaouk 2025-05-06 14:38:53 +03:00 committed by GitHub
parent fa4d3b8391
commit 4265672825
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 121 additions and 6 deletions

12
operator/Cargo.lock generated
View file

@ -2425,6 +2425,7 @@ dependencies = [
"pallet-mmr",
"pallet-multisig",
"pallet-offences",
"pallet-outbound-commitment-store",
"pallet-parameters",
"pallet-preimage",
"pallet-scheduler",
@ -7631,6 +7632,17 @@ dependencies = [
"sp-staking",
]
[[package]]
name = "pallet-outbound-commitment-store"
version = "0.1.0"
dependencies = [
"frame-support",
"frame-system",
"parity-scale-codec",
"scale-info",
"sp-core",
]
[[package]]
name = "pallet-parameters"
version = "0.10.1"

View file

@ -8,6 +8,7 @@ edition = "2021"
[workspace]
members = [
"node",
"pallets/outbound-commitment-store",
"pallets/ethereum-client",
"pallets/inbound-queue-v2",
"pallets/outbound-queue-v2",
@ -28,6 +29,7 @@ datahaven-runtime = { path = "./runtime", default-features = false }
datahaven-runtime-common = { path = "./runtime/common", default-features = false }
dhp-bridge = { path = "./primitives/bridge", default-features = false }
pallet-validator-set = { path = "./pallets/validator-set", default-features = false }
pallet-outbound-commitment-store = { path = "./pallets/outbound-commitment-store", default-features = false }
# Crates.io (wasm)
alloy-core = { version = "0.8.15", default-features = false }

View file

@ -0,0 +1,34 @@
[package]
name = "pallet-outbound-commitment-store"
version = "0.1.0"
description = "Pallet for storing the latest commitment hash from the outbound queue for cross-chain verification"
authors = { workspace = true }
edition = { workspace = true }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { workspace = true, features = ["derive"] }
scale-info = { workspace = true, features = ["derive"] }
frame-support = { workspace = true }
frame-system = { workspace = true }
sp-core = { workspace = true }
[features]
default = ["std"]
std = [
"codec/std",
"frame-support/std",
"frame-system/std",
"scale-info/std",
"sp-core/std",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
]
runtime-benchmarks = [
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
]

View file

@ -0,0 +1,49 @@
#![cfg_attr(not(feature = "std"), no_std)]
use frame_support::{pallet_prelude::*, traits::StorageVersion};
use sp_core::H256;
pub use pallet::*;
/// Current storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
/// A pallet for storing the latest commitment hash from the outbound queue.
///
/// This pallet provides a simple way to track the most recent commitment hash,
/// which can be included in BEEFY MMR leaves for cross-chain verification.
#[frame_support::pallet]
pub mod pallet {
use super::*;
#[pallet::pallet]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
}
#[pallet::storage]
#[pallet::getter(fn latest_commitment)]
pub type LatestCommitment<T> = StorageValue<_, H256, OptionQuery>;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
CommitmentStored { hash: H256 },
}
}
impl<T: Config> Pallet<T> {
pub fn store_commitment(commitment: H256) {
LatestCommitment::<T>::put(commitment);
Self::deposit_event(Event::CommitmentStored { hash: commitment });
}
pub fn get_latest_commitment() -> Option<H256> {
LatestCommitment::<T>::get()
}
}

View file

@ -93,6 +93,7 @@ sp-version = { features = ["serde"], workspace = true }
xcm = { workspace = true }
xcm-builder = { workspace = true }
xcm-executor = { workspace = true }
pallet-outbound-commitment-store = { workspace = true }
[build-dependencies]
substrate-wasm-builder = { optional = true, workspace = true, default-features = true }
@ -171,6 +172,7 @@ std = [
"sp-transaction-pool/std",
"sp-version/std",
"substrate-wasm-builder",
"pallet-outbound-commitment-store/std",
]
runtime-benchmarks = [
@ -206,6 +208,7 @@ runtime-benchmarks = [
"snowbridge-pallet-outbound-queue-v2/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"snowbridge-pallet-system/runtime-benchmarks",
"pallet-outbound-commitment-store/runtime-benchmarks",
]
try-runtime = [
@ -243,6 +246,7 @@ try-runtime = [
"snowbridge-pallet-outbound-queue-v2/try-runtime",
"sp-runtime/try-runtime",
"snowbridge-pallet-system/try-runtime",
"pallet-outbound-commitment-store/try-runtime",
]
fast-runtime = [

View file

@ -28,10 +28,10 @@ mod runtime_params;
use super::{
deposit, AccountId, Babe, Balance, Balances, BeefyMmrLeaf, Block, BlockNumber,
EthereumBeaconClient, EvmChainId, Hash, Historical, ImOnline, MessageQueue, Nonce, Offences,
OriginCaller, OutboundQueueV2, PalletInfo, Preimage, Runtime, RuntimeCall, RuntimeEvent,
RuntimeFreezeReason, RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, SessionKeys,
Signature, System, Timestamp, ValidatorSet, EXISTENTIAL_DEPOSIT, SLOT_DURATION,
STORAGE_BYTE_FEE, SUPPLY_FACTOR, UNIT, VERSION,
OriginCaller, OutboundCommitmentStore, OutboundQueueV2, PalletInfo, Preimage, Runtime,
RuntimeCall, RuntimeEvent, RuntimeFreezeReason, RuntimeHoldReason, RuntimeOrigin, RuntimeTask,
Session, SessionKeys, Signature, System, Timestamp, ValidatorSet, EXISTENTIAL_DEPOSIT,
SLOT_DURATION, STORAGE_BYTE_FEE, SUPPLY_FACTOR, UNIT, VERSION,
};
use codec::{Decode, Encode};
use datahaven_runtime_common::{
@ -78,6 +78,7 @@ use snowbridge_outbound_queue_primitives::{
v2::ConstantGasMeter,
SendError, SendMessageFeeProvider,
};
use snowbridge_pallet_outbound_queue_v2::OnNewCommitment;
use snowbridge_pallet_system::BalanceOf;
use sp_consensus_beefy::{
ecdsa_crypto::AuthorityId as BeefyId,
@ -356,7 +357,7 @@ pub struct LeafExtraDataProvider;
impl BeefyDataProvider<LeafExtraData> for LeafExtraDataProvider {
fn extra_data() -> LeafExtraData {
LeafExtraData {
extra: H256::zero(),
extra: OutboundCommitmentStore::get_latest_commitment().unwrap_or_default(),
}
}
}
@ -805,6 +806,13 @@ parameter_types! {
pub EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 };
}
pub struct CommitmentHandler;
impl OnNewCommitment for CommitmentHandler {
fn on_new_commitment(commitment: H256) {
OutboundCommitmentStore::store_commitment(commitment);
}
}
impl snowbridge_pallet_outbound_queue_v2::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Hashing = Keccak256;
@ -813,7 +821,7 @@ impl snowbridge_pallet_outbound_queue_v2::Config for Runtime {
type Balance = Balance;
type MaxMessagePayloadSize = ConstU32<2048>;
type MaxMessagesPerBlock = ConstU32<32>;
type OnNewCommitment = ();
type OnNewCommitment = CommitmentHandler;
type WeightToFee = IdentityFee<Balance>;
type WeightInfo = ();
type Verifier = EthereumBeaconClient;
@ -860,3 +868,7 @@ pub mod benchmark_helpers {
}
}
}
impl pallet_outbound_commitment_store::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
}

View file

@ -347,5 +347,7 @@ mod runtime {
// ╔═══════════════════ DataHaven-specific Pallets ══════════════════╗
// Start with index 100
#[runtime::pallet_index(100)]
pub type OutboundCommitmentStore = pallet_outbound_commitment_store;
// ╚═══════════════════ DataHaven-specific Pallets ══════════════════╝
}