diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c8b0c2..b4206cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,110 @@ by [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow ## [Unreleased] +## [0.0.7] — 2026-05-20 — Phase 1.5 "Session rotation canonical (4h epochs)" + +Charon sesión 1 continuación. **Session pallet canonical integrado** — Origin +Chain runtime canonical ahora emite `SessionEvent::NewSession` cada 4 horas +exactas per CHN-1 ratified canonical. Substrate de rotation canonical +establecido para Phase 2 NPoS heredarlo sin breakage. + +### Pallet añadido canonical (per SBS-4) + +- **Index 6** `Session` (`pallet_session 40.0.1`) — **validator session + rotation canonical** per CHN-1 4h epochs. Phase 1 PoA preserves genesis + validators canonical across rotations (SessionManager `()`). Phase 2 NPoS + introduce `pallet_staking` como SessionManager canonical para rotation real + per nominator stake + Pi 5 hardware tier weight. + +### Configs canonical pallet_session + +```rust +parameter_types! { + /// 2400 bloques × 6s = 14400s = 4 horas exactas per CHN-1 + pub const SessionPeriod: BlockNumber = BLOCK_HASH_COUNT; + pub const SessionOffset: BlockNumber = 0; +} + +type RuntimeEvent = RuntimeEvent; +type ValidatorId = ChainAccountId; +type ValidatorIdOf = AccountIdIsValidatorId; // identity Phase 1 PoA +type ShouldEndSession = pallet_session::PeriodicSessions; +type NextSessionRotation = pallet_session::PeriodicSessions; +type SessionManager = (); // Phase 1 PoA preserves genesis +type SessionHandler = ::KeyTypeIdProviders; +type Keys = opaque::SessionKeys; // aura sr25519 + grandpa Ed25519 +type DisablingStrategy = (); // Phase 2 NPoS introduce real +type WeightInfo = pallet_session::weights::SubstrateWeight; +``` + +### Custom canonical converter + +`AccountIdIsValidatorId` struct nueva canonical (identity mapping AccountId → +ValidatorId Phase 1 PoA trivial). Phase 2 NPoS reemplazará canonical con +`pallet_staking::StashOf` para real Stash/Controller separation. + +### Filosofía canonical incorporada + +Doc cita CHN-1: *"Epoch rotation every 4 hours selecting 100-150 active +validators from millions of Pi 5 nodes eligible"*. Materializa empíricamente: + +- **Phase 1 PoA** (este v0.0.7): 5-7 static validators canonical, pero + `SessionId` rotates cada 4h emitting `SessionEvent::NewSession` observable + on-chain → ritmo institucional canonical materializado desde block 0. +- **Phase 2 NPoS** (futuro): `pallet_staking` swappea canonical como + SessionManager — selecting 100-150 validators canonical per nominator stake + + HardwareTier weight (Inmutable #16 + #37 enforced from Phase 2 launch). + +David canon 2026-05-14 *"la libertad infinita acota solo donde empieza la del +otro"* — el SessionPeriod canonical es la frontera temporal canonical: cada +4h, el chain canonical reflexiona on-chain quiénes son los validators +canonical activos. Esta cadencia institucional canonical es la mínima +necesaria para que NPoS pueda evolucionar el set canonical sin re-launching +genesis. + +### Tour canonical de Origin Chain runtime composition (7 pallets) + +``` +┌────────────────────────────────────────────────────────────┐ +│ Origin Chain Runtime v0.0.7 — frame_support::runtime! │ +├────────────────────────────────────────────────────────────┤ +│ Index 0 System (foundational frame) │ +│ Index 1 Timestamp (block clock → Aura) │ +│ Index 2 Balances (OGC token CHN-2) │ +│ Index 3 TransactionPayment (gas baseline CHN-8) │ +│ Index 4 Aura (PoA block production CHN-1) │ +│ Index 5 Grandpa (finality gadget CHN-1) │ +│ Index 6 Session (4h epoch rotation CHN-1) │ ← NEW +├────────────────────────────────────────────────────────────┤ +│ Opaque SessionKeys: aura (sr25519) + grandpa (Ed25519) │ +│ → consumed canonical by pallet_session::Config::Keys │ ← NEW WIRE +└────────────────────────────────────────────────────────────┘ +``` + +### Phase 1 progress canonical + +- ✅ **1.1** Scaffold (v0.0.2) +- ✅ **1.2** Substrate foundation (v0.0.4) +- ✅ **1.3** Pallets foundation (v0.0.5) +- ✅ **1.4** Consensus PoA Aura+GRANDPA (v0.0.6) +- ✅ **1.5** **Session rotation 4h epochs** (v0.0.7) ← **ESTA** +- ⏳ **1.6** `pallet_identity` Ed25519 DID + `origin-chain-node` real service +- ⏳ **1.7** Genesis `chain_spec.rs` BM V2 allocation (40/25/15/15/5) + +### Build canonical + +- `cargo check --workspace`: **1.63s** (warm cache, pallet_session incremental) +- `cargo build --release`: **7.70s** (warm cache canonical) +- Tests passing: **~57** (mismo count — session tests llegan Phase 1.7 cuando + chain_spec con validators reales se integre) + +### Decision empírica documentada + +`pallet_session::Config::DisablingStrategy` es nuevo en stable2512 canonical +(no estaba en versiones anteriores). Phase 1 PoA: `()` canonical preserva +behavior original. Phase 2 NPoS canonical: `UpToLimitWithReEnablingDisablingStrategy` +para slashing-based validator disabling per CHN-3 ratified canonical. + ## [0.0.6] — 2026-05-20 — Phase 1.4 "Consensus PoA canonical (Aura+GRANDPA)" Charon sesión 1 continuación. **Consensus PoA canonical activado** — Origin diff --git a/Cargo.lock b/Cargo.lock index f2c62b4..7a9fefd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2088,6 +2088,7 @@ dependencies = [ "pallet-aura", "pallet-balances", "pallet-grandpa", + "pallet-session", "pallet-timestamp", "pallet-transaction-payment", "parity-scale-codec", diff --git a/Cargo.toml b/Cargo.toml index c6fc69d..0f00590 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,9 @@ pallet-transaction-payment = { version = "40.0.0", default-features = false } pallet-aura = { version = "39.0.0", default-features = false } pallet-grandpa = { version = "40.0.0", default-features = false } +# FRAME pallets canonical Phase 1.5 — Session rotation per CHN-1 4h epochs +pallet-session = { version = "40.0.1", default-features = false } + # SCALE codec canonical (canonical Substrate serialization) parity-scale-codec = { version = "3.7", default-features = false, features = ["derive"] } scale-info = { version = "2.11", default-features = false, features = ["derive"] } diff --git a/crates/origin-chain-runtime/Cargo.toml b/crates/origin-chain-runtime/Cargo.toml index 90c80cb..644285a 100644 --- a/crates/origin-chain-runtime/Cargo.toml +++ b/crates/origin-chain-runtime/Cargo.toml @@ -41,6 +41,9 @@ pallet-transaction-payment.workspace = true pallet-aura.workspace = true pallet-grandpa.workspace = true +# FRAME pallets Phase 1.5 — Session rotation per CHN-1 4h epochs +pallet-session.workspace = true + # SCALE codec canonical parity-scale-codec.workspace = true scale-info.workspace = true @@ -72,6 +75,7 @@ std = [ "pallet-transaction-payment/std", "pallet-aura/std", "pallet-grandpa/std", + "pallet-session/std", "parity-scale-codec/std", "scale-info/std", "serde", diff --git a/crates/origin-chain-runtime/src/configs.rs b/crates/origin-chain-runtime/src/configs.rs index 0da8d64..14ef803 100644 --- a/crates/origin-chain-runtime/src/configs.rs +++ b/crates/origin-chain-runtime/src/configs.rs @@ -229,3 +229,78 @@ impl pallet_grandpa::Config for Runtime { /// reports not handled. Phase 2 NPoS introduces real handler canonical. type EquivocationReportSystem = (); } + +// ============================================================ +// pallet_session::Config canonical (CHN-1 — 4h epoch rotation) +// ============================================================ +// +// Filosofía canonical: PoA Phase 1 preserva el mismo validator set canonical +// genesis através de cada session rotation (SessionManager = `()`). El "epoch +// rotation" canonical materializa el ritmo institucional canonical (cada 4h se +// emite SessionEvent canonical observable on-chain) sin cambiar canonical el +// validator set hasta Phase 2 NPoS — cuando pallet_staking introduce dynamic +// validator selection basado en stake + nominator delegation. +// +// CHN-1 ratificado canonical: "Epoch rotation every 4 hours selecting 100-150 +// active validators from millions of Pi 5 nodes eligible". Phase 1 PoA tiene +// 5-7 static validators canonical; el "selecting 100-150" materializa Phase 2 +// NPoS canonical. Esta integration Phase 1.5 establece el substrate canonical +// para que Phase 2 NPoS herede el rotation mechanism sin breakage. + +parameter_types! { + /// Canonical session period: 2400 bloques × 6s = 14400s = **4 horas exactas** + /// per CHN-1 ratified canonical. Alineado canonical con BLOCK_HASH_COUNT + /// (mismo valor) — block hash proof valid durante todo el epoch en curso. + pub const SessionPeriod: BlockNumber = BLOCK_HASH_COUNT; + /// Canonical session offset: 0 — sesiones canonical start at block 0 (sin + /// offset canonical). Phase 2 NPoS puede introducir offset si necesario + /// para alinear con extramo institucional (e.g. UTC midnight epoch starts). + pub const SessionOffset: BlockNumber = 0; +} + +/// Canonical converter `ChainAccountId → Option`. +/// +/// Phase 1 PoA simple: cada AccountId IS a ValidatorId canonical (identidad +/// trivial). Phase 2 NPoS introduces real Stash/Controller separation canonical +/// where ValidatorId derives from Stash account via pallet_staking::StashOf. +pub struct AccountIdIsValidatorId; + +impl sp_runtime::traits::Convert> + for AccountIdIsValidatorId +{ + fn convert(account: ChainAccountId) -> Option { + Some(account) + } +} + +impl pallet_session::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + /// ValidatorId canonical = ChainAccountId (Phase 1 PoA identidad trivial). + type ValidatorId = ChainAccountId; + /// ValidatorIdOf canonical: identity mapping AccountId → ValidatorId. + type ValidatorIdOf = AccountIdIsValidatorId; + /// ShouldEndSession canonical: PeriodicSessions every 2400 blocks (4h epoch + /// per CHN-1 canonical). Cada 2400 bloques emite SessionEvent::NewSession. + type ShouldEndSession = pallet_session::PeriodicSessions; + /// NextSessionRotation canonical: same PeriodicSessions — predecible + /// canonical para validators saber cuándo será el next rotation slot. + type NextSessionRotation = pallet_session::PeriodicSessions; + /// SessionManager canonical = `()`: Phase 1 PoA preserves genesis validators + /// canonical across all sessions (no rotation of validator SET, only + /// SessionId increment canonical). Phase 2 NPoS introduces pallet_staking + /// como SessionManager canonical para real rotation per nominator stake. + type SessionManager = (); + /// SessionHandler canonical: deriva desde opaque::SessionKeys (aura sr25519 + /// + grandpa Ed25519). Cuando una nueva session begins canonical, los + /// session keys de cada validator se distribute al consensus pallets canonical + /// (Aura recibe nuevo AuraId set + Grandpa recibe nuevo GrandpaId set). + type SessionHandler = + ::KeyTypeIdProviders; + /// Keys canonical = opaque::SessionKeys struct (defined en opaque.rs). + type Keys = crate::opaque::SessionKeys; + /// DisablingStrategy canonical = `()`: Phase 1 PoA simple — no validator + /// disable mechanism. Phase 2 NPoS introduces `UpToLimitWithReEnablingDisablingStrategy` + /// canonical para slashing-based validator disabling per CHN-3. + type DisablingStrategy = (); + type WeightInfo = pallet_session::weights::SubstrateWeight; +} diff --git a/crates/origin-chain-runtime/src/lib.rs b/crates/origin-chain-runtime/src/lib.rs index 24f2b1f..b9d65bb 100644 --- a/crates/origin-chain-runtime/src/lib.rs +++ b/crates/origin-chain-runtime/src/lib.rs @@ -217,6 +217,13 @@ mod runtime { /// (Aura ~6s) de finality cadence (canonical ~6-12s combined). #[runtime::pallet_index(5)] pub type Grandpa = pallet_grandpa::Pallet; + + /// Session pallet canonical (validator rotation per CHN-1 4h epochs). + /// Phase 1 PoA: preserves genesis validators canonical across rotations. + /// Phase 2 NPoS: pallet_staking will be SessionManager canonical para real + /// rotation per nominator stake + Pi 5 hardware tier weight. + #[runtime::pallet_index(6)] + pub type Session = pallet_session::Pallet; } #[cfg(test)] diff --git a/crates/origin-chain-runtime/src/opaque.rs b/crates/origin-chain-runtime/src/opaque.rs index c3fdffb..c22c936 100644 --- a/crates/origin-chain-runtime/src/opaque.rs +++ b/crates/origin-chain-runtime/src/opaque.rs @@ -15,7 +15,6 @@ //! (puede correr cualquier runtime WASM compatible) + runtime sovereignty (puede //! evolucionar pallets sin breakar node binaries). -use crate::{AuraId, GrandpaId}; use sp_runtime::impl_opaque_keys; impl_opaque_keys! {