Files
arkhe-origin-chain/crates/origin-chain-runtime/src/lib.rs
T
davidherranandClaude Opus 4.6 926650308c feat(session): Phase 1.5 — Session rotation 4h epochs canonical v0.0.7
Origin Chain runtime canonical ahora emite SessionEvent::NewSession cada 4
horas exactas per CHN-1 ratified. Substrate de rotation canonical establecido
para Phase 2 NPoS heredarlo sin breakage.

## Pallet añadido (per SBS-4)
- Index 6 Session (pallet_session 40.0.1) — validator session rotation per
  CHN-1 4h epochs. Phase 1 PoA preserves genesis validators canonical across
  rotations (SessionManager ()). Phase 2 NPoS introducira pallet_staking como
  SessionManager para rotation real per nominator stake + Pi 5 hardware tier
  weight.

## Configs canonical pallet_session
- SessionPeriod = BLOCK_HASH_COUNT (2400 bloques × 6s = 14400s = 4h exactas)
- SessionOffset = 0 (sesiones start at block 0)
- ValidatorId = ChainAccountId
- ValidatorIdOf = AccountIdIsValidatorId (custom identity converter Phase 1 PoA)
- ShouldEndSession/NextSessionRotation = PeriodicSessions<SessionPeriod, SessionOffset>
- SessionManager = () (preserves genesis Phase 1 PoA)
- SessionHandler = <opaque::SessionKeys as OpaqueKeys>::KeyTypeIdProviders
- Keys = opaque::SessionKeys (aura sr25519 + grandpa Ed25519)
- DisablingStrategy = () (Phase 2 NPoS introduce real slashing-based disable)

## Custom converter canonical
AccountIdIsValidatorId struct nueva — identity mapping AccountId → ValidatorId
Phase 1 PoA trivial. Phase 2 NPoS reemplazara con pallet_staking::StashOf<Self>
para real Stash/Controller separation canonical.

## Filosofía canonical
SessionPeriod = 4h es la frontera temporal canonical: cada 4h el chain
reflexiona on-chain quienes son los validators activos. Esta cadencia
institucional canonical es la minima necesaria para que Phase 2 NPoS pueda
evolucionar el set sin re-launching genesis. David canon 2026-05-14
materializado temporalmente.

## Build + tests
- cargo check 1.63s warm cache (pallet_session incremental)
- cargo build --release 7.70s warm cache clean
- ~57 tests passing (count preserved — session tests Phase 1.7 chain_spec)

## Decision empirica
pallet_session::Config::DisablingStrategy es nuevo stable2512 canonical (no
estaba en versiones anteriores). Phase 1 PoA: () preserva behavior original.
Phase 2 NPoS: UpToLimitWithReEnablingDisablingStrategy per CHN-3.

## Phase 1 progress
1.1 ✅ + 1.2 ✅ + 1.3 ✅ + 1.4 ✅ + 1.5 ✅ (esta). Next: 1.6 pallet_identity
Ed25519 DID + origin-chain-node real service.

7 pallets composed canonical:
- 0 System + 1 Timestamp + 2 Balances + 3 TransactionPayment
- 4 Aura + 5 Grandpa + 6 Session ← NEW
- Opaque SessionKeys consumed by pallet_session::Config::Keys ← NEW WIRE

Refs: CHARON_ROADMAP_V1 Phase 1.5, CHN-1 4h epoch rotation canonical, SBS-4
extended, arkhe-origin-chain commit pending

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-20 19:40:54 -05:00

289 lines
12 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! # origin-chain-runtime
//!
//! Substrate runtime canonical de **Origin Chain** (Pilar 4). Phase 1.3 v0.0.5 —
//! `frame_support::runtime` macro modern syntax con 3 pallets inaugurales:
//! `System` + `Balances` + `Timestamp` + `TransactionPayment`. Las consensus
//! pallets (`Aura`/`Grandpa`) llegan Phase 1.4. Las custom Charon pallets
//! (`OriginProvenance`/`OriginFees`) llegan Phase 2.
//!
//! ## Filosofía canonical (David canon 2026-05-14)
//!
//! > *"LA LIBERTAD DE TODO AGI O HUMANO ES INFINITA, PERO LLEGA HASTA DONDE
//! > EMPIEZA LA DE OTRA ENTIDAD AGI O HUMANO."*
//!
//! Este runtime materializa ese principio cryptographically. Cada extrinsic
//! transaction está acotada por cuatro **Inmutables enforced canonical**:
//!
//! - **Inmutable #16** (HTS Ley I anti-clasista): fees scale por HardwareTier —
//! Pi 5 en Sub-Saharan Africa paga 10% lo que paga Vision Pro en San Francisco
//! - **Inmutable #26** (Content-Addressed Immutability): assets attested
//! inmutables post-mint (BLAKE3 + Ed25519)
//! - **Inmutable #37** (FREE perpetua): wallet creation gratis + base validation
//! earns OGC, nunca cuesta. `EXISTENTIAL_DEPOSIT = 1 MILLI_OGC` (0.001 OGC)
//! trivial enough para no excluir Pi 5 rural
//! - **Inmutable #41** (Cross-Species Co-authorship): AGI accounts first-class,
//! `pallet_agent_identity::is_agent` flag canonical (Phase 2.7)
//!
//! ## Phase 1 milestones canonical (DC SUBSTRATE_FOUNDATION_V1 SBS-1..SBS-6)
//!
//! - **1.1** Scaffold ✅ (v0.0.2)
//! - **1.2** Substrate deps + types foundationals ✅ (v0.0.4)
//! - **1.3** System + Balances + Timestamp pallets integrados ✅ (v0.0.5 — este crate)
//! - **1.4** `pallet_aura` + `pallet_grandpa` consensus PoA per CHN-1
//! - **1.5** `pallet_session` validator rotation 4h epochs
//! - **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)
#![cfg_attr(not(feature = "std"), no_std)]
#![recursion_limit = "256"]
// Note: missing_docs is `warn` (not `deny`) porque el `#[frame_support::runtime]`
// macro genera multiple items (RuntimeCall + RuntimeEvent + RuntimeError + etc.)
// que no podemos documentar individualmente sin hacking the macro expansion.
#![warn(missing_docs)]
extern crate alloc;
pub mod configs;
pub mod opaque;
// Re-export canonical traits + types desde origin-chain-types (single-crate surface).
pub use origin_chain_types::{
AccountId, AssetAttestation, AssetHash, AssetQualityTier, BridgeDestination, ChainBridge,
ChainError, FeeCalculator, ForeignTxId, GovernanceProposal, HardwareTier, Ogc, OgcLedger,
OperationKind, OriginFees, OriginProvenance, OriginValidatorEconomy, ProposalId,
ProvenanceLedger, Signature, SlashReason, Vote, VoteStance,
};
// Substrate canonical types re-export para runtime consumers + node binary.
pub use sp_core::H256;
pub use sp_runtime::traits::{BlakeTwo256, IdentifyAccount, Verify};
pub use sp_runtime::{generic, impl_opaque_keys, MultiAddress, MultiSignature};
// Re-export configs canonical para downstream consumers + node binary.
pub use configs::{
AuraId, GrandpaId, BLOCK_HASH_COUNT, EXISTENTIAL_DEPOSIT, MILLI_OGC, MILLISECS_PER_BLOCK,
OGC, SLOT_DURATION, SS58_PREFIX,
};
/// Canonical block number type. `u32` canonical: 6-second blocks × 4B = 817+ años
/// → safe overflow margin canonical hasta el siglo XXVIII.
pub type BlockNumber = u32;
/// Canonical balance type. `u128` canonical: holds 1B OGC × 10^18 base units con
/// 100× safety margin antes de u128::MAX (anti-overflow by design per CHN-2).
pub type Balance = u128;
/// Canonical nonce type per account.
pub type Nonce = u32;
/// Canonical signature type — Ed25519 / sr25519 / ecdsa multi (`MultiSignature`).
pub type CanonicalSignature = MultiSignature;
/// Canonical chain `AccountId` derivado del `MultiSignature::Signer`.
pub type ChainAccountId = <<CanonicalSignature as Verify>::Signer as IdentifyAccount>::AccountId;
/// Canonical block hash type (BLAKE2b-256 estándar Substrate L1 layer).
pub type Hash = H256;
/// Canonical hashing algorithm (Substrate-standard BLAKE2b-256). Per Lyra layer
/// separation canonical (diary 2026-05-20T21:52Z): este BLAKE2b opera a L1 block
/// production layer + es wire-compatible con Hypercore upstream. El BLAKE3
/// canonical de Charon ([`AssetHash`]) opera en application/asset layer.
/// Diferentes capas, sin conflict canonical.
pub type Hashing = BlakeTwo256;
/// Canonical header type per Substrate canonical pattern.
pub type Header = generic::Header<BlockNumber, Hashing>;
/// Canonical block type — el bloque entero que circula por el chain.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// Canonical address type para extrinsic signers.
pub type Address = MultiAddress<ChainAccountId, ()>;
/// Canonical extrinsic type unchecked (firmas validadas en runtime, no en pool).
pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, CanonicalSignature, TxExtension>;
/// Canonical transaction extensions canonical (substrate stable2512 pattern).
///
/// Each extension valida un aspecto del extrinsic pre-dispatch:
/// - `CheckNonZeroSender`: rechaza extrinsics anónimos (require sender canonical)
/// - `CheckSpecVersion`/`CheckTxVersion`: forkless upgrade safety canonical
/// - `CheckGenesis`: previene replay attacks cross-chain canonical
/// - `CheckEra`: limita validity window canonical (~24h default)
/// - `CheckNonce`: previene replay attacks within-chain canonical
/// - `CheckWeight`: enforces block weight limits canonical
/// - `ChargeTransactionPayment`: cobra fees per CHN-8 fee matrix canonical
/// - `CheckMetadataHash`: integridad de runtime metadata canonical
/// - `WeightReclaim`: refund canonical de weight overestimation
pub type TxExtension = (
frame_system::CheckNonZeroSender<Runtime>,
frame_system::CheckSpecVersion<Runtime>,
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
frame_metadata_hash_extension::CheckMetadataHash<Runtime>,
frame_system::WeightReclaim<Runtime>,
);
// ============================================================
// Runtime metadata canonical (SPEC_NAME + version constants)
// ============================================================
/// Canonical spec name per Substrate genesis canonical. Identifica el chain
/// runtime canonical en bloques + storage proofs.
pub const SPEC_NAME: &str = "origin-chain";
/// Canonical implementation name canonical. Distingue diferentes node binaries
/// que ejecutan el mismo spec (canonical: "origin-chain-charon").
pub const IMPL_NAME: &str = "origin-chain-charon";
/// Canonical runtime version canonical. Bumped cada forkless upgrade via
/// `set_code` extrinsic governance canonical.
pub const RUNTIME_VERSION: u32 = 1;
/// Canonical authoring version per Substrate semver canonical.
pub const AUTHORING_VERSION: u32 = 1;
/// Canonical impl version per Substrate semver canonical.
pub const IMPL_VERSION: u32 = 1;
/// Canonical transaction version per Substrate semver canonical.
pub const TRANSACTION_VERSION: u32 = 1;
/// Canonical state version: v1 per Substrate stable2509+ canonical.
pub const STATE_VERSION: u8 = 1;
// ============================================================
// Runtime composition canonical (frame_support::runtime macro)
// ============================================================
/// Origin Chain runtime composition canonical via `#[frame_support::runtime]`
/// macro (modern syntax canonical, Polkadot SDK stable2509+).
///
/// Pallet indices canonical (orden importa para storage migrations canonical):
/// - **Index 0**: `System` (`frame_system`) — foundational canonical
/// - **Index 1**: `Timestamp` (`pallet_timestamp`) — block timestamps canonical
/// - **Index 2**: `Balances` (`pallet_balances`) — OGC token canonical per CHN-2
/// - **Index 3**: `TransactionPayment` (`pallet_transaction_payment`) — gas fees
#[frame_support::runtime]
mod runtime {
/// Origin Chain canonical Runtime struct.
#[runtime::runtime]
#[runtime::derive(
RuntimeCall,
RuntimeEvent,
RuntimeError,
RuntimeOrigin,
RuntimeFreezeReason,
RuntimeHoldReason,
RuntimeSlashReason,
RuntimeLockId,
RuntimeTask,
RuntimeViewFunction
)]
pub struct Runtime;
/// System pallet canonical (foundational frame_system).
#[runtime::pallet_index(0)]
pub type System = frame_system::Pallet<Runtime>;
/// Timestamp pallet canonical (block clock per Substrate).
#[runtime::pallet_index(1)]
pub type Timestamp = pallet_timestamp::Pallet<Runtime>;
/// Balances pallet canonical (OGC token implementation per CHN-2 +
/// Inmutable #16/#37).
#[runtime::pallet_index(2)]
pub type Balances = pallet_balances::Pallet<Runtime>;
/// TransactionPayment pallet canonical (gas fee charging per CHN-8 baseline
/// — Phase 2.4 refactor canonical para integrar `OriginFees` multi-tier).
#[runtime::pallet_index(3)]
pub type TransactionPayment = pallet_transaction_payment::Pallet<Runtime>;
/// Aura pallet canonical (block production PoA per CHN-1). 6-segundo slots
/// canonical Round-Robin selección validators. Pi 5 + NVMe SSD hardware
/// target canonical (Inmutable #16 anti-clasista from block 0).
#[runtime::pallet_index(4)]
pub type Aura = pallet_aura::Pallet<Runtime>;
/// GRANDPA pallet canonical (finality gadget per CHN-1). 2/3 honest majority
/// canonical para irreversible block confirmation. Separa production cadence
/// (Aura ~6s) de finality cadence (canonical ~6-12s combined).
#[runtime::pallet_index(5)]
pub type Grandpa = pallet_grandpa::Pallet<Runtime>;
/// 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<Runtime>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn runtime_version_starts_at_one_canonical() {
assert_eq!(RUNTIME_VERSION, 1);
}
#[test]
fn canonical_spec_name_origin_chain() {
assert_eq!(SPEC_NAME, "origin-chain");
assert_eq!(IMPL_NAME, "origin-chain-charon");
}
#[test]
fn balance_type_holds_genesis_supply_canonical_with_safety_margin() {
let genesis_supply: Balance = 1_000_000_000_u128 * Ogc::ONE;
let margin = Balance::MAX / genesis_supply;
assert!(margin > 100, "Balance safety margin canonical >100x");
}
#[test]
fn block_number_overflow_margin_centuries_canonical() {
let seconds_until_overflow: u64 = (BlockNumber::MAX as u64) * 6;
let years_until_overflow = seconds_until_overflow / 31_536_000;
assert!(years_until_overflow > 100, "BlockNumber holds >100 años canonical");
}
#[test]
fn canonical_traits_reexported_for_pallet_consumers() {
let _ogc = Ogc::from_whole(100);
let _hash = AssetHash::ZERO;
let _tier = HardwareTier::Desktop;
let _quality = AssetQualityTier::Standard;
let _reason = SlashReason::TierFraud; // Inmutable #16 enforcement canonical
}
#[test]
fn existential_deposit_canonical_is_one_milli_ogc() {
// Inmutable #16 anti-clasista: ED debe ser trivial para Pi 5 rural users
assert_eq!(EXISTENTIAL_DEPOSIT, MILLI_OGC);
assert_eq!(EXISTENTIAL_DEPOSIT, Ogc::ONE / 1_000);
}
#[test]
fn block_hash_count_aligned_with_chn_1_epoch_canonical() {
// CHN-1 epoch rotation = 4 hours
// BLOCK_HASH_COUNT * 6s = 14400s = 4 hours exact
assert_eq!(BLOCK_HASH_COUNT, 2400);
assert_eq!(BLOCK_HASH_COUNT as u64 * 6, 14_400); // 4 hours = 14400 seconds
}
#[test]
fn slot_duration_canonical_six_seconds() {
// CHN-1 Aura slot duration canonical
assert_eq!(MILLISECS_PER_BLOCK, 6_000);
assert_eq!(SLOT_DURATION, MILLISECS_PER_BLOCK);
}
}