Skip to content

Commit 42dca9b

Browse files
in progress
1 parent fa38ef2 commit 42dca9b

File tree

8 files changed

+653
-0
lines changed

8 files changed

+653
-0
lines changed

Cargo.lock

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ members = [
5656
"toolkit/utils/db-sync-sqlx",
5757
"toolkit/governed-map/primitives",
5858
"toolkit/governed-map/pallet",
59+
"toolkit/cardano-config/pallet",
5960
]
6061
resolver = "2"
6162

@@ -329,5 +330,8 @@ partner-chains-mock-data-sources = { path = "toolkit/data-sources/mock", default
329330
sp-governed-map = { path = "toolkit/governed-map/primitives", default-features = false }
330331
pallet-governed-map = { path = "toolkit/governed-map/pallet", default-features = false }
331332

333+
# Cardano Config
334+
pallet-cardano-config = { path = "toolkit/cardano-config/pallet", default-features = false }
335+
332336
# demo node
333337
partner-chains-demo-runtime = { path = "demo/runtime" }
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
[package]
2+
name = "pallet-cardano-config"
3+
authors.workspace = true
4+
edition.workspace = true
5+
homepage.workspace = true
6+
repository.workspace = true
7+
version.workspace = true
8+
license = "Apache-2.0"
9+
description = "Pallet for storing Cardano configuration parameters in runtime storage"
10+
11+
[package.metadata.docs.rs]
12+
targets = ["x86_64-unknown-linux-gnu"]
13+
14+
[lints]
15+
workspace = true
16+
17+
[dependencies]
18+
frame-benchmarking = { workspace = true, optional = true }
19+
frame-support = { workspace = true }
20+
frame-system = { workspace = true }
21+
log = { workspace = true }
22+
parity-scale-codec = { workspace = true }
23+
scale-info = { workspace = true }
24+
sidechain-domain = { workspace = true }
25+
sp-core = { workspace = true }
26+
sp-runtime = { workspace = true }
27+
28+
[dev-dependencies]
29+
pretty_assertions = { workspace = true }
30+
sp-core = { workspace = true }
31+
sp-io = { workspace = true }
32+
sp-runtime = { workspace = true }
33+
34+
[features]
35+
default = ["std"]
36+
std = [
37+
"frame-benchmarking/std",
38+
"frame-support/std",
39+
"frame-system/std",
40+
"log/std",
41+
"parity-scale-codec/std",
42+
"scale-info/std",
43+
"sidechain-domain/std",
44+
"sp-core/std",
45+
"sp-runtime/std"
46+
]
47+
runtime-benchmarks = [
48+
"frame-benchmarking/runtime-benchmarks",
49+
"frame-support/runtime-benchmarks",
50+
"frame-system/runtime-benchmarks",
51+
]
52+
mock = []
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//! Benchmarking setup for pallet-cardano-config
2+
3+
#![cfg(feature = "runtime-benchmarks")]
4+
5+
use super::*;
6+
use frame_benchmarking::v2::*;
7+
use frame_support::{assert_ok, traits::Get};
8+
use sidechain_domain::{CardanoConfig, MainchainEpochConfig};
9+
use sp_core::offchain::{Duration, Timestamp};
10+
11+
/// Helper trait for benchmarking
12+
pub trait BenchmarkHelper<T: Config> {
13+
/// Returns a sample CardanoConfig for benchmarking
14+
fn cardano_config() -> CardanoConfig;
15+
}
16+
17+
impl<T: Config> BenchmarkHelper<T> for () {
18+
fn cardano_config() -> CardanoConfig {
19+
CardanoConfig {
20+
epoch_config: MainchainEpochConfig {
21+
epoch_duration_millis: Duration::from_millis(432000000), // 5 days
22+
slot_duration_millis: Duration::from_millis(1000), // 1 second
23+
first_epoch_timestamp_millis: Timestamp::from_unix_millis(1596059091000),
24+
first_epoch_number: 208,
25+
first_slot_number: 4492800,
26+
},
27+
cardano_security_parameter: 432,
28+
cardano_active_slots_coeff: 0.05,
29+
}
30+
}
31+
}
32+
33+
#[benchmarks]
34+
mod benchmarks {
35+
use super::*;
36+
37+
#[benchmark]
38+
fn set_cardano_config() {
39+
let config = T::BenchmarkHelper::cardano_config();
40+
41+
#[extrinsic_call]
42+
_(RawOrigin::Root, config.clone());
43+
44+
assert_eq!(CardanoConfiguration::<T>::get(), Some(config.clone()));
45+
assert_eq!(MainchainEpochConfiguration::<T>::get(), Some(config.epoch_config));
46+
assert_eq!(CardanoSecurityParameter::<T>::get(), Some(config.cardano_security_parameter));
47+
assert_eq!(CardanoActiveSlotsCoeff::<T>::get(), Some(config.cardano_active_slots_coeff));
48+
}
49+
50+
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
51+
}
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
//! Pallet for storing Cardano configuration parameters in runtime storage.
2+
//!
3+
//! # Purpose of this pallet
4+
//!
5+
//! This pallet stores Cardano configuration parameters that are essential for Partner Chain operation,
6+
//! including mainchain epoch configuration and consensus parameters. By storing these parameters in
7+
//! runtime storage rather than relying on environment variables, we ensure all nodes have consistent
8+
//! configuration as part of the chain state.
9+
10+
#![cfg_attr(not(feature = "std"), no_std)]
11+
#![deny(missing_docs)]
12+
13+
extern crate alloc;
14+
15+
pub use pallet::*;
16+
17+
use crate::weights::WeightInfo;
18+
use core::marker::PhantomData;
19+
use frame_support::pallet_prelude::*;
20+
use frame_system::pallet_prelude::*;
21+
use sidechain_domain::{
22+
cardano_config::CardanoConfig,
23+
mainchain_epoch::MainchainEpochConfig,
24+
};
25+
use sp_runtime::Perbill;
26+
use sp_core::offchain::{Duration, Timestamp};
27+
28+
pub mod weights;
29+
30+
#[cfg(test)]
31+
mod tests;
32+
33+
#[cfg(test)]
34+
mod mock;
35+
36+
#[cfg(feature = "runtime-benchmarks")]
37+
pub mod benchmarking;
38+
39+
#[frame_support::pallet]
40+
pub mod pallet {
41+
use super::*;
42+
43+
#[pallet::pallet]
44+
pub struct Pallet<T>(_);
45+
46+
/// Current pallet version
47+
pub const PALLET_VERSION: u32 = 1;
48+
49+
#[pallet::config]
50+
pub trait Config: frame_system::Config {
51+
/// Weight functions for the pallet's extrinsics
52+
type WeightInfo: weights::WeightInfo;
53+
54+
/// Helper functions required by the pallet's benchmarks to construct realistic input data.
55+
#[cfg(feature = "runtime-benchmarks")]
56+
type BenchmarkHelper: crate::benchmarking::BenchmarkHelper<Self>;
57+
}
58+
59+
/// Error type used by this pallet's extrinsics
60+
#[pallet::error]
61+
pub enum Error<T> {
62+
/// Configuration has already been set and cannot be changed
63+
ConfigurationAlreadySet,
64+
}
65+
66+
/// Stores the epoch duration in milliseconds
67+
#[pallet::storage]
68+
#[pallet::getter(fn epoch_duration_millis)]
69+
pub type EpochDurationMillis<T: Config> = StorageValue<_, u64, OptionQuery>;
70+
71+
/// Stores the slot duration in milliseconds
72+
#[pallet::storage]
73+
#[pallet::getter(fn slot_duration_millis)]
74+
pub type SlotDurationMillis<T: Config> = StorageValue<_, u64, OptionQuery>;
75+
76+
/// Stores the first epoch timestamp in milliseconds
77+
#[pallet::storage]
78+
#[pallet::getter(fn first_epoch_timestamp_millis)]
79+
pub type FirstEpochTimestampMillis<T: Config> = StorageValue<_, u64, OptionQuery>;
80+
81+
/// Stores the first epoch number
82+
#[pallet::storage]
83+
#[pallet::getter(fn first_epoch_number)]
84+
pub type FirstEpochNumber<T: Config> = StorageValue<_, u32, OptionQuery>;
85+
86+
/// Stores the first slot number
87+
#[pallet::storage]
88+
#[pallet::getter(fn first_slot_number)]
89+
pub type FirstSlotNumber<T: Config> = StorageValue<_, u64, OptionQuery>;
90+
91+
/// Stores the Cardano security parameter (k)
92+
#[pallet::storage]
93+
#[pallet::getter(fn cardano_security_parameter)]
94+
pub type CardanoSecurityParameter<T: Config> = StorageValue<_, u32, OptionQuery>;
95+
96+
/// Stores the Cardano active slots coefficient (f) as parts per billion
97+
#[pallet::storage]
98+
#[pallet::getter(fn cardano_active_slots_coeff)]
99+
pub type CardanoActiveSlotsCoeff<T: Config> = StorageValue<_, Perbill, OptionQuery>;
100+
101+
#[pallet::genesis_config]
102+
#[derive(frame_support::DefaultNoBound)]
103+
pub struct GenesisConfig<T: Config> {
104+
/// Initial Cardano configuration.
105+
pub cardano_config: Option<CardanoConfig>,
106+
/// Phantom data marker
107+
pub _marker: PhantomData<T>,
108+
}
109+
110+
#[pallet::genesis_build]
111+
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
112+
fn build(&self) {
113+
if let Some(config) = &self.cardano_config {
114+
EpochDurationMillis::<T>::put(config.epoch_config.epoch_duration_millis.as_millis());
115+
SlotDurationMillis::<T>::put(config.epoch_config.slot_duration_millis.as_millis());
116+
FirstEpochTimestampMillis::<T>::put(config.epoch_config.first_epoch_timestamp_millis.as_unix_millis());
117+
FirstEpochNumber::<T>::put(config.epoch_config.first_epoch_number);
118+
FirstSlotNumber::<T>::put(config.epoch_config.first_slot_number);
119+
CardanoSecurityParameter::<T>::put(config.cardano_security_parameter);
120+
CardanoActiveSlotsCoeff::<T>::put(Perbill::from_float(config.cardano_active_slots_coeff as f64));
121+
}
122+
}
123+
}
124+
125+
#[pallet::call]
126+
impl<T: Config> Pallet<T> {
127+
/// Set the Cardano configuration. This can only be called once.
128+
#[pallet::call_index(0)]
129+
#[pallet::weight(T::WeightInfo::set_cardano_config())]
130+
pub fn set_cardano_config(
131+
origin: OriginFor<T>,
132+
config: CardanoConfig,
133+
) -> DispatchResult {
134+
ensure_root(origin)?;
135+
136+
ensure!(
137+
!Self::is_configured(),
138+
Error::<T>::ConfigurationAlreadySet
139+
);
140+
141+
EpochDurationMillis::<T>::put(config.epoch_config.epoch_duration_millis.0);
142+
SlotDurationMillis::<T>::put(config.epoch_config.slot_duration_millis.0);
143+
FirstEpochTimestampMillis::<T>::put(config.epoch_config.first_epoch_timestamp_millis.0);
144+
FirstEpochNumber::<T>::put(config.epoch_config.first_epoch_number);
145+
FirstSlotNumber::<T>::put(config.epoch_config.first_slot_number);
146+
CardanoSecurityParameter::<T>::put(config.cardano_security_parameter);
147+
CardanoActiveSlotsCoeff::<T>::put(Perbill::from_float(config.cardano_active_slots_coeff));
148+
149+
log::info!("🔧 Cardano configuration set");
150+
Ok(())
151+
}
152+
}
153+
154+
impl<T: Config> Pallet<T> {
155+
/// Returns the complete Cardano configuration
156+
pub fn get_cardano_config() -> Option<CardanoConfig> {
157+
let epoch_config = Self::get_mainchain_epoch_config()?;
158+
let security_parameter = CardanoSecurityParameter::<T>::get()?;
159+
let active_slots_coeff = CardanoActiveSlotsCoeff::<T>::get()?;
160+
161+
Some(CardanoConfig {
162+
epoch_config,
163+
cardano_security_parameter: security_parameter,
164+
cardano_active_slots_coeff: active_slots_coeff.deconstruct() as f32 / 1_000_000_000.0,
165+
})
166+
}
167+
168+
/// Returns the mainchain epoch configuration
169+
pub fn get_mainchain_epoch_config() -> Option<MainchainEpochConfig> {
170+
let epoch_duration_millis = EpochDurationMillis::<T>::get()?;
171+
let slot_duration_millis = SlotDurationMillis::<T>::get()?;
172+
let first_epoch_timestamp_millis = FirstEpochTimestampMillis::<T>::get()?;
173+
let first_epoch_number = FirstEpochNumber::<T>::get()?;
174+
let first_slot_number = FirstSlotNumber::<T>::get()?;
175+
176+
Some(MainchainEpochConfig {
177+
epoch_duration_millis: Duration::from_millis(epoch_duration_millis),
178+
slot_duration_millis: Duration::from_millis(slot_duration_millis),
179+
first_epoch_timestamp_millis: Timestamp::from_unix_millis(first_epoch_timestamp_millis),
180+
first_epoch_number,
181+
first_slot_number,
182+
})
183+
}
184+
185+
/// Returns the Cardano security parameter (k)
186+
pub fn get_cardano_security_parameter() -> Option<u32> {
187+
CardanoSecurityParameter::<T>::get()
188+
}
189+
190+
/// Returns the Cardano active slots coefficient (f)
191+
pub fn get_cardano_active_slots_coeff() -> Option<f32> {
192+
CardanoActiveSlotsCoeff::<T>::get()
193+
.map(|perbill| perbill.deconstruct() as f32 / 1_000_000_000.0)
194+
}
195+
196+
/// Returns whether the configuration has been set
197+
pub fn is_configured() -> bool {
198+
EpochDurationMillis::<T>::exists() &&
199+
SlotDurationMillis::<T>::exists() &&
200+
FirstEpochTimestampMillis::<T>::exists() &&
201+
FirstEpochNumber::<T>::exists() &&
202+
FirstSlotNumber::<T>::exists() &&
203+
CardanoSecurityParameter::<T>::exists() &&
204+
CardanoActiveSlotsCoeff::<T>::exists()
205+
}
206+
207+
/// Returns current pallet version
208+
pub fn get_version() -> u32 {
209+
PALLET_VERSION
210+
}
211+
}
212+
}

0 commit comments

Comments
 (0)