Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@ The Bulletin chain consists of a customized node implementation and a single run

## Node implementation

The Bulletin chain node implements IPFS support on top of a regualar Substrate node. Only work with `litep2p` network backend is supported (enabled by default), and in order to use IPFS functionality `--ipfs-server` flag must be passed to the node binary.
The Bulletin chain node implements IPFS support on top of a regular Substrate node. Only work with `litep2p` network backend is supported (enabled by default), and in order to use IPFS functionality `--ipfs-server` flag must be passed to the node binary.

IPFS support comes in two parts:

1. Bitswap protocol implementation. Wire protocol for transferring chunks stored in transaction storage to IPFS clients. This is implemented in `litep2p` networking library and `litep2p` network backend in `sc-network` crate.
2. IPFS Kademlia DHT support. We publish content provider records for our node for CIDs (content identifiers) of transactions stored in transaction storage. Content provider records are only kept for transactions included in the chain during last two weeks, what should agree with block pruning period of the Bulletin nodes. DHT support is provided by `litep2p` networking library and `sc-network` crate. The implementation in the Bulletin node ensures we register as content providers for transactions during last two weeks.
2. IPFS Kademlia DHT support. We publish content provider records for our node for CIDs (content identifiers) of transactions stored in transaction storage. Content provider records are only kept for transactions included in the chain during last two weeks, what should agree with block pruning period of the Bulletin nodes. DHT support is provided by `litep2p` networking library and `sc-network` crate. The implementation in the Bulletin node ensures we register as content providers for transactions during the last two weeks.

Bulletin node also has idle connection timeout set to 1 hour instead of default 10 seconds to allow manually adding the node to the swarm of an IPFS client and ensuring we don't disconnect the IPFS client. This is done to allow IPFS clients to query data over Bitswap protocol before IPFS Kademlia DHT support is implemented (DHT support is planned to be ready by the end of August 2025).
Bulletin node also has an idle connection timeout set to 1 hour instead of the default 10 seconds to allow manually adding the node to the swarm of an IPFS client and ensuring we don't disconnect the IPFS client. This is done to allow IPFS clients to query data over Bitswap protocol before IPFS Kademlia DHT support is implemented (DHT support is planned to be ready by the end of August 2025).

TODO: clarify if we need to store transactiond for two weeks or other period.
TODO: clarify if we need to store transactions for two weeks or another period.

## Runtime functionality

The Bulletin chain runtime is a standard BaBE + GRANDPA chain with a custom validator set pallet which is (currently) controlled by root call (TODO: clarify whether this should be sudo, governance, etc).
It functions to store transactions for a given period of time (currently set at 2 weeks) and provide proofs of storage.
It functions to store transactions for a given period of time (currently set at 2 weeks) and provide proof of storage.

### Core functionality

The main purpose of the Bulletin chain is to provide storage for the People Chain over the bridge.

#### Storage
The core functionality of the bulletin chain is in the transaction-storage pallet, which indexes transcations and manages storage proofs for arbitrary data.
The core functionality of the bulletin chain is in the transaction-storage pallet, which indexes transactions and manages storage proofs for arbitrary data.

Data is added via the `transactionStorage.store` extrinsic, provided the storage of the data is authorized by root call. Authorization is granted either for a specific account via authorize_account or for data with a specific preimage via authorize_preimage. Once data is stored, it can be retrieved from IPFS with the Blake2B hash of the data.

Expand Down
4 changes: 2 additions & 2 deletions pallets/transaction-storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,8 @@ pub mod pallet {
Ok(().into())
}

/// Check storage proof for block number `block_number() - StoragePeriod`. If such block
/// does not exist the proof is expected to be `None`.
/// Check storage proof for block number `block_number() - StoragePeriod`. If such a block
/// does not exist, the proof is expected to be `None`.
///
/// ## Complexity
///
Expand Down
98 changes: 94 additions & 4 deletions runtimes/bulletin-polkadot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -642,20 +642,110 @@ mod benches {
[pallet_relayer_set, RelayerSet]

[pallet_bridge_grandpa, BridgePolkadotGrandpa]
// [pallet_bridge_parachains, BridgeParachainsBench::<Runtime, bridge_config::WithPolkadotBridgeParachainsInstance>]
// [pallet_bridge_messages, BridgeMessagesBench::<Runtime, bridge_config::WithPeoplePolkadotMessagesInstance>]
[pallet_bridge_parachains, PolkadotParachains]
[pallet_bridge_messages, PolkadotMessages]
);

pub use frame_benchmarking::{baseline::Pallet as Baseline, BenchmarkBatch, BenchmarkList};
pub use frame_system_benchmarking::Pallet as SystemBench;

pub use frame_support::traits::{StorageInfoTrait, WhitelistedStorageKeys};
pub use pallet_bridge_messages::benchmarking::Pallet as BridgeMessagesBench;
pub use pallet_bridge_parachains::benchmarking::Pallet as BridgeParachainsBench;
pub use sp_storage::TrackedStorageKey;

impl frame_system_benchmarking::Config for Runtime {}
impl frame_benchmarking::baseline::Config for Runtime {}

use bridge_runtime_common::parachains_benchmarking::prepare_parachain_heads_proof;
use pallet_bridge_parachains::benchmarking::Config as BridgeParachainsConfig;

impl BridgeParachainsConfig<bridge_config::WithPolkadotBridgeParachainsInstance> for Runtime {
fn parachains() -> Vec<bp_polkadot_core::parachains::ParaId> {
use bp_runtime::Parachain;
vec![bp_polkadot_core::parachains::ParaId(
bridge_config::bp_people_polkadot::PeoplePolkadot::PARACHAIN_ID,
)]
}

fn prepare_parachain_heads_proof(
parachains: &[bp_polkadot_core::parachains::ParaId],
parachain_head_size: u32,
proof_params: bp_runtime::UnverifiedStorageProofParams,
) -> (
bp_parachains::RelayBlockNumber,
bp_parachains::RelayBlockHash,
bp_polkadot_core::parachains::ParaHeadsProof,
Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>,
) {
prepare_parachain_heads_proof::<
Runtime,
bridge_config::WithPolkadotBridgeParachainsInstance,
>(parachains, parachain_head_size, proof_params)
}
}

use bridge_runtime_common::messages_benchmarking::{
generate_xcm_builder_bridge_message_sample, prepare_message_delivery_proof_from_parachain,
prepare_message_proof_from_parachain,
};
use pallet_bridge_messages::{
benchmarking::{
Config as BridgeMessagesConfig, MessageDeliveryProofParams, MessageProofParams,
},
LaneIdOf,
};

impl BridgeMessagesConfig<bridge_config::WithPeoplePolkadotMessagesInstance> for Runtime {
fn is_relayer_rewarded(_relayer: &Self::AccountId) -> bool {
// TODO:
// no rewards, so we don't care
true
}

fn prepare_message_proof(
params: MessageProofParams<
LaneIdOf<Runtime, bridge_config::WithPeoplePolkadotMessagesInstance>,
>,
) -> (bridge_config::benchmarking::FromPeoplePolkadotMessagesProof, Weight) {
prepare_message_proof_from_parachain::<
Runtime,
bridge_config::WithPolkadotBridgeGrandpaInstance,
bridge_config::WithPeoplePolkadotMessagesInstance,
>(
params,
generate_xcm_builder_bridge_message_sample(
bridge_config::PeoplePolkadotLocation::get().interior().clone(),
),
)
}

fn prepare_message_delivery_proof(
params: MessageDeliveryProofParams<
AccountId,
LaneIdOf<Runtime, bridge_config::WithPeoplePolkadotMessagesInstance>,
>,
) -> bridge_config::benchmarking::ToPeoplePolkadotMessagesDeliveryProof {
prepare_message_delivery_proof_from_parachain::<
Runtime,
bridge_config::WithPolkadotBridgeGrandpaInstance,
bridge_config::WithPeoplePolkadotMessagesInstance,
>(params)
}

fn is_message_successfully_dispatched(_nonce: bp_messages::MessageNonce) -> bool {
// TODO:
// currently we have no means to detect that
true
}
}

pub type PolkadotParachains = pallet_bridge_parachains::benchmarking::Pallet<
Runtime,
bridge_config::WithPolkadotBridgeParachainsInstance,
>;
pub type PolkadotMessages = pallet_bridge_messages::benchmarking::Pallet<
Runtime,
bridge_config::WithPeoplePolkadotMessagesInstance,
>;
}

#[cfg(feature = "runtime-benchmarks")]
Expand Down
116 changes: 26 additions & 90 deletions runtimes/bulletin-polkadot/src/polkadot_bridge_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ parameter_types! {
1,
[GlobalConsensus(PolkadotGlobalConsensusNetwork::get())]
);
/// Location of the PeoplePolkadot parachain, relative to this runtime.
pub PeoplePolkadotLocation: Location = Location::new(1, [
GlobalConsensus(BridgedNetwork::get()),
Parachain(bp_people_polkadot::PEOPLE_POLKADOT_PARACHAIN_ID),
]);

/// A number of Polkadot mandatory headers that are accepted for free at every
/// **this chain** block.
Expand Down Expand Up @@ -213,7 +218,7 @@ impl pallet_bridge_grandpa::Config<WithPolkadotBridgeGrandpaInstance> for Runtim
pub type WithPolkadotBridgeParachainsInstance = ();
impl pallet_bridge_parachains::Config<WithPolkadotBridgeParachainsInstance> for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = crate::weights::bridge_polkadot_parachains::WeightInfo<Runtime>;
type WeightInfo = crate::weights::pallet_bridge_parachains::WeightInfo<Runtime>;

type BridgesGrandpaPalletInstance = WithPolkadotBridgeGrandpaInstance;
type ParasPalletName = AtPolkadotParasPalletName;
Expand Down Expand Up @@ -319,7 +324,7 @@ impl<BlobDispatcher: DispatchBlob, Weights: pallet_bridge_messages::WeightInfoEx
pub type WithPeoplePolkadotMessagesInstance = ();
impl pallet_bridge_messages::Config<WithPeoplePolkadotMessagesInstance> for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = crate::weights::bridge_polkadot_messages::WeightInfo<Runtime>;
type WeightInfo = crate::weights::pallet_bridge_messages::WeightInfo<Runtime>;

type ThisChain = bp_polkadot_bulletin::PolkadotBulletin;
type BridgedChain = bp_people_polkadot::PeoplePolkadot;
Expand Down Expand Up @@ -430,97 +435,28 @@ where
pub type ToBridgeHaulBlobExporter = HaulBlobExporter<
XcmBlobHauler<Runtime, WithPeoplePolkadotMessagesInstance>,
PolkadotGlobalConsensusNetworkLocation,
AlwaysV4,
AlwaysV5,
(),
>;

// #[cfg(feature = "runtime-benchmarks")]
// pub mod benchmarking {
// use super::*;
//
// /// Proof of messages, coming from BridgeHubPolkadot.
// pub type FromBridgeHubPolkadotMessagesProof =
// bridge_runtime_common::messages::target::FromBridgedChainMessagesProof<
// bp_people_polkadot::Hash,
// >;
//
// /// Message delivery proof for `BridgeHubPolkadot` messages.
// pub type ToBridgeHubPolkadotMessagesDeliveryProof =
// bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof<
// bp_people_polkadot::Hash,
// >;
//
// use bridge_runtime_common::messages_benchmarking::{
// generate_xcm_builder_bridge_message_sample, prepare_message_delivery_proof_from_parachain,
// prepare_message_proof_from_parachain,
// };
// use pallet_bridge_messages::benchmarking::{
// Config as BridgeMessagesConfig, MessageDeliveryProofParams, MessageProofParams,
// };
//
// impl BridgeMessagesConfig<WithBridgeHubPolkadotMessagesInstance> for Runtime {
// fn is_relayer_rewarded(_relayer: &Self::AccountId) -> bool {
// // no rewards, so we don't care
// true
// }
//
// fn prepare_message_proof(
// params: MessageProofParams,
// ) -> (FromBridgeHubPolkadotMessagesProof, Weight) {
// prepare_message_proof_from_parachain::<
// Runtime,
// WithPolkadotBridgeGrandpaInstance,
// WithBridgeHubPolkadotMessageBridge,
// >(
// params,
// generate_xcm_builder_bridge_message_sample(
// *crate::xcm_config::KawabungaLocation::get().interior(),
// ),
// )
// }
//
// fn prepare_message_delivery_proof(
// params: MessageDeliveryProofParams<AccountId>,
// ) -> ToBridgeHubPolkadotMessagesDeliveryProof {
// prepare_message_delivery_proof_from_parachain::<
// Runtime,
// WithPolkadotBridgeGrandpaInstance,
// WithBridgeHubPolkadotMessageBridge,
// >(params)
// }
//
// fn is_message_successfully_dispatched(_nonce: bp_messages::MessageNonce) -> bool {
// // currently we have no means to detect that
// true
// }
// }
//
// use bridge_runtime_common::parachains_benchmarking::prepare_parachain_heads_proof;
// use pallet_bridge_parachains::benchmarking::Config as BridgeParachainsConfig;
// impl BridgeParachainsConfig<WithPolkadotBridgeParachainsInstance> for Runtime {
// fn parachains() -> Vec<bp_polkadot::parachains::ParaId> {
// use bp_runtime::Parachain;
// vec![bp_polkadot::parachains::ParaId(BridgeHubPolkadotOrPolkadot::PARACHAIN_ID)]
// }
//
// fn prepare_parachain_heads_proof(
// parachains: &[bp_polkadot::parachains::ParaId],
// parachain_head_size: u32,
// proof_size: bp_runtime::StorageProofSize,
// ) -> (
// pallet_bridge_parachains::RelayBlockNumber,
// pallet_bridge_parachains::RelayBlockHash,
// bp_polkadot::parachains::ParaHeadsProof,
// Vec<(bp_polkadot::parachains::ParaId, bp_polkadot::parachains::ParaHash)>,
// ) {
// prepare_parachain_heads_proof::<Runtime, WithPolkadotBridgeParachainsInstance>(
// parachains,
// parachain_head_size,
// proof_size,
// )
// }
// }
// }
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking {
use super::*;

/// Proof of messages, coming from PeoplePolkadot.
pub type FromPeoplePolkadotMessagesProof =
bp_messages::target_chain::FromBridgedChainMessagesProof<
bp_people_polkadot::Hash,
pallet_bridge_messages::LaneIdOf<Runtime, WithPeoplePolkadotMessagesInstance>,
>;

/// Message delivery proof for `PeoplePolkadot` messages.
pub type ToPeoplePolkadotMessagesDeliveryProof =
bp_messages::source_chain::FromBridgedChainMessagesDeliveryProof<
bp_people_polkadot::Hash,
pallet_bridge_messages::LaneIdOf<Runtime, WithPeoplePolkadotMessagesInstance>,
>;
}
//
// #[cfg(test)]
// pub(crate) mod tests {
Expand Down
Loading