Los 19 extrinsics de provenance/fees/agent-identity/emission/governance pasan de weights placeholder `from_parts(10_000, 0)` (proof_size=0, sin contar reads/writes de DB — vector de DoS real) a weights INTERIM hand-derived DB-aware vía el trait `WeightInfo`. Cierra el mispricing de DoS en TODOS los extrinsics del chain. Cada pallet gana: - weights.rs: trait WeightInfo + SubstrateWeight<T> (DB-aware vía T::DbWeight) + impl () - benchmarking.rs: benchmarks FRAME v2, VERIFICADOS por impl_benchmark_test_suite! (19 benchmarks ejecutan+pasan en los mocks — cargo test --features runtime-benchmarks) - Config: `type WeightInfo` + swap de los `#[pallet::weight]` Runtime: - define_benchmarks! con los 5 pallets + runtime API Benchmark (inerte sin la feature) - WeightInfo cableado a SubstrateWeight<Runtime> en cada Config - RUNTIME_VERSION 8→9 (weights = consenso-relevante: fee + llenado de bloque; las firmas de los extrinsics NO cambian ⇒ TRANSACTION_VERSION intacto) 3 bugs latentes cerrados (territorio virgen — el runtime NUNCA se compiló con runtime-benchmarks; las dimensiones nuevas cazan lo que no se había visto): - pallet-grandpa/try-runtime mal ubicado en la feature runtime-benchmarks (copy-paste erróneo: features ortogonales; NUNCA activaba los benchmarks de grandpa) - feature runtime-benchmarks incompleta → E0046 en OriginFeeAdapter (métodos benchmark-gated de OnChargeTransaction) + pallet-staking (StakingUnchecked::migrate_to_direct_staker); ahora lista TODOS los pallets como un runtime de producción Substrate - pallet-revive/runtime-benchmarks omitido a propósito (fixtures RISC-V/PolkaVM indisponibles; ReviveApi deferred, no benchmarkeado) emission: mock extraído del `mod tests` inline a `pub mod mock` (reuso del test-suite, sin duplicar el scaffold; los 15 tests existentes + el benchmark verdes). GATED (documentado en el §Estado de cada weights.rs): la generación de números CANÓNICOS por CLI requiere el node sc-service o omni-bencher+WASM (ambos bloqueados hace sesiones). Los weights interinos son DB-aware/DoS-safe y regenerables de forma mecánica cuando aterrice el HW de referencia (Pi5/VPS) — benchmarking.rs es la fuente de verdad de la FORMA. Verificado: 5 test-suites de pallet verdes (con y sin runtime-benchmarks) + runtime compila en ambos modos + workspace sin regresión + 40 tests de runtime (incl. v9). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1171 lines
54 KiB
Rust
1171 lines
54 KiB
Rust
//! # 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;
|
||
use alloc::vec::Vec;
|
||
|
||
pub mod configs;
|
||
/// FIX-6 Stage 2b NPoS — pallet_staking config (infra dormida).
|
||
pub mod staking;
|
||
#[cfg(feature = "std")]
|
||
pub mod genesis_config_presets;
|
||
pub mod opaque;
|
||
|
||
// ============================================================
|
||
// WASM binary (Slice 4 Paso 4a — WASM_BINARY export v0.0.48)
|
||
// ============================================================
|
||
//
|
||
// `build.rs` genera `OUT_DIR/wasm_binary.rs` con `pub const WASM_BINARY:
|
||
// Option<&[u8]>` cuando el feature `wasm-build` está activo (vía
|
||
// substrate-wasm-builder). El node lo consume para construir el ChainSpec real
|
||
// (`sc_service::GenericChainSpec`) en Slice 4 Paso 4b.
|
||
//
|
||
// Gate: el `include!` solo corre con `wasm-build` on (si está off, el archivo
|
||
// generado no existe → error de compilación). El fallback `None` cubre los
|
||
// builds host-only (`cargo test`/`cargo check`). El inner build wasm32 que
|
||
// dispara substrate-wasm-builder NO hereda `wasm-build` (no es default feature),
|
||
// lo que evita recursión en build.rs.
|
||
#[cfg(feature = "wasm-build")]
|
||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||
|
||
/// Fallback de `WASM_BINARY` para builds host-only (feature `wasm-build` off).
|
||
/// Para obtener el binary real: `cargo build --features wasm-build` + env vars
|
||
/// `CC=/opt/homebrew/opt/llvm/bin/clang` (ver SLICE_2E). El node activa
|
||
/// `origin-chain-runtime/wasm-build` para embeberlo en el ChainSpec.
|
||
#[cfg(not(feature = "wasm-build"))]
|
||
pub const WASM_BINARY: Option<&[u8]> = None;
|
||
|
||
/// Devuelve el `WASM_BINARY` o falla con un mensaje claro si no está disponible.
|
||
/// Consumido por el node al construir ChainSpecs (Slice 4 Paso 4b).
|
||
#[cfg(feature = "std")]
|
||
pub fn wasm_binary_unwrap() -> &'static [u8] {
|
||
WASM_BINARY.expect(
|
||
"WASM binary no disponible: build con `--features wasm-build` + \
|
||
CC=LLVM env vars (ver SLICE_2E). El node debe activar \
|
||
origin-chain-runtime/wasm-build.",
|
||
)
|
||
}
|
||
|
||
// ============================================================
|
||
// WASM binary canonical (Slice 2b investigation registered, Slice 2c deferred)
|
||
// ============================================================
|
||
//
|
||
// `substrate-wasm-builder` integration canonical bloqueado por structural Cargo
|
||
// + WASM stdlib alloc conflict canonical:
|
||
//
|
||
// ```
|
||
// error[E0152]: duplicate lang item in crate `alloc` (which `serde` depends on):
|
||
// `exchange_malloc`
|
||
// note: first definition in `alloc` loaded from
|
||
// rustup/toolchains/1.88.0/lib/rustlib/wasm32-unknown-unknown/lib/liballoc-***.rlib
|
||
// note: second definition in `alloc` loaded from
|
||
// target/release/wbuild/origin-chain-runtime/target/wasm32-unknown-unknown/release/deps/liballoc-***.rmeta
|
||
// ```
|
||
//
|
||
// **Slice 2b investigation registered canonical 2026-05-21** (4 fix attempts):
|
||
// 1. Remove direct serde dep canonical (transitive desde FRAME) — NO solved
|
||
// 2. Pin serde canonical `=1.0.219` + `=1.0.217` — NO solved
|
||
// 3. Remove `[profile.release] lto/codegen-units` customization canonical — NO solved
|
||
// 4. `WasmBuilder::build_using_defaults()` (upstream pattern canonical) — NO solved
|
||
//
|
||
// **Root cause empírico canonical**: wbuild auto-genera `[profile.release]` con
|
||
// `panic = "abort"` triggering Cargo a recompilar `alloc` canonical desde rust-src
|
||
// component canonical, generating duplicate rmeta canonical vs la precompiled
|
||
// rustup alloc rlib canonical para wasm32 target canonical.
|
||
//
|
||
// **Slice 2c canonical requires Larihana Substrate-adjacent expertise canonical**:
|
||
// - Plan C Rust ports experience (arkhe-hypercore + autobase + corestore)
|
||
// - WASM workspace pin canonical experience
|
||
// - Probable fixes canonical: `cargo:rustc-env=SKIP_WASM_BUILD=1` + path-loaded
|
||
// pre-built WASM file canonical, OR opening upstream issue paritytech/polkadot-sdk
|
||
//
|
||
// Diary canonical filed para Larihana 2026-05-21 (Slice 2b → Slice 2c handoff
|
||
// canonical). `chain_spec.rs` canonical Phase 1.6+ Slice 3 shipped canonical
|
||
// 2026-05-22 (v0.0.13) con mock-WASM fallback pattern canonical — own minimal
|
||
// ChainSpec JSON builder canonical via serde_json puro en node crate canonical.
|
||
// Real `sc_chain_spec::GenericChainSpec` canonical land Slice 4 post workspace
|
||
// sc-* upgrade canonical sin yanked deps canonical (cid 0.9.0 → core2 0.4.0 YANKED).
|
||
|
||
// 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.
|
||
/// v2: FIX-6 Stage 2a — fee unificado (OriginFeeAdapter reemplaza al
|
||
/// FungibleAdapter: cambia el COMPORTAMIENTO del cobro de fees, no el formato
|
||
/// de extrinsic — TRANSACTION_VERSION intacto).
|
||
/// v3: FIX-6 Stage 2b NPoS Paso A — pallet_staking Index 14 cableado (infra
|
||
/// DORMIDA: presente pero inerte; nuevo pallet ⇒ cambia metadata del runtime).
|
||
/// v4: FIX-6 Stage 2b — governance emission kill-switch (`set_emission_paused`
|
||
/// en pallet-origin-emission Index 13: nuevo call ⇒ cambia metadata. El call es
|
||
/// aditivo en un call_index nuevo — TRANSACTION_VERSION intacto). Palanca Root
|
||
/// para pausar inflación + kill-switch anti-doble-emisión para la activación NPoS.
|
||
/// v5: FeesApi alignment — nuevo método `query_fee_for_account` (estima el fee
|
||
/// con el TierProfile REAL on-chain del account, no caller-supplied). Cambia la
|
||
/// metadata del Runtime API FeesApi; método aditivo ⇒ TRANSACTION_VERSION intacto.
|
||
/// v6: audit ultra 2026-07-02 (3 fixes) — (a) `FeeMultiplierUpdate`: `()` colapsaba
|
||
/// `NextFeeMultiplier` a 0 tras el bloque 1 (weight-fee desaparecía de la cadena);
|
||
/// ahora `ConstFeeMultiplier<1>`. (b) `NativeToEthRatio` 1_000_000→1 (OGC = 18
|
||
/// decimales, no 12; la capa EVM distorsionaba valores ×10^6). (c) emisión:
|
||
/// `TotalEmitted` + evento registran SOLO lo realmente acuñado (resultados de
|
||
/// `mint_into` ya no se descartan). Cambia comportamiento ⇒ spec bump;
|
||
/// TRANSACTION_VERSION intacto.
|
||
/// v7: economía Level A (David 2026-07-03, 2 decisiones) — (a) **TECHO DURO 1B**:
|
||
/// la emisión TRANSFIERE del pool Ecosystem finito (og/ecosy, 400M) en vez de
|
||
/// `mint_into`; el total issuance jamás crece, el pool se agota en ~7.6 años,
|
||
/// después economía circular (evento `BlockRewardReleased` + `EcosystemPoolDepleted`
|
||
/// one-shot). (b) **fees con dientes**: `WeightToFee`/`LengthToFee` de `IdentityFee`
|
||
/// (polvo ~10^-10 OGC) a `ConstantMultiplier` calibrado — un transfer ≈ 1 MILLI_OGC,
|
||
/// el #16 Pi5 0.1× = ahorro real, quema deflacionaria medible. Comportamiento ⇒
|
||
/// spec bump; TRANSACTION_VERSION intacto.
|
||
/// v8: hardening de governance (audit ultra 2026-07-04 + decisiones A/B David) —
|
||
/// correctitud: `override_council_veto` solo revierte vetos del council (no votos
|
||
/// populares), `treasury_disbursement` single-use (anti-replay), veto con conteo
|
||
/// en vivo. (A) reserva REAL del stake de propuesta (bond `og/props`). (B) flujo
|
||
/// 5/7 de emergencia real: nueva dispatchable `endorse_emergency_proposal`
|
||
/// (call_index 12) + gate real (antes tautológico). Nuevas storage/errors/evento
|
||
/// + 1 call aditiva ⇒ spec bump; TRANSACTION_VERSION intacto (call_index nuevo).
|
||
///
|
||
/// **v9 (benchmarking real machinery)**: los 19 extrinsics de los 5 pallets custom
|
||
/// pasan de weights placeholder `from_parts(10_000, 0)` (proof_size=0, sin contar
|
||
/// DB — DoS) a weights INTERIM hand-derived DB-aware vía `WeightInfo`. Los weights
|
||
/// son consenso-relevantes (afectan fee y llenado de bloque) ⇒ spec bump obligatorio.
|
||
/// Las FIRMAS de los extrinsics NO cambian ⇒ TRANSACTION_VERSION intacto. La feature
|
||
/// `runtime-benchmarks` gana `define_benchmarks!` + runtime API `Benchmark` (inerte
|
||
/// sin la feature) + fix del bug `pallet-grandpa/try-runtime` en la feature.
|
||
pub const RUNTIME_VERSION: u32 = 9;
|
||
|
||
/// 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>;
|
||
|
||
/// Provenance pallet canonical (Phase 2.1 v0.0.15 scaffold wired canonical
|
||
/// per CHN-7 + DC PROVENANCE_PALLET_V1). Asset attestation ledger BLAKE3 +
|
||
/// Ed25519 canonical para cross-pillar consumers (Trinity, Codex, Ethos,
|
||
/// Atelier). Scaffold-level canonical: dispatchable `attest_asset` flow
|
||
/// básico working, real Ed25519 verify post Ergon arkhe-noesis-attestation-types
|
||
/// Cap 42+ ship (v0.0.16 next slice).
|
||
///
|
||
/// Naming canonical: alias `Provenance` (NO `OriginProvenance` que conflictaría
|
||
/// con el trait existente del mismo nombre en `origin_chain_types::pallets`).
|
||
#[runtime::pallet_index(7)]
|
||
pub type Provenance = origin_chain_provenance::Pallet<Runtime>;
|
||
|
||
/// Fees pallet canonical (Phase 2.4 v0.0.21 wired canonical per OCAFB-1..6 +
|
||
/// DC `origin_chain_amis_fee_bridge_v1` 6/7 firmas sesión 3+ Charon ratified).
|
||
/// Cross-pillar fee economy consumer Mathi `OitFeeSchedule` trait (commit
|
||
/// `ce4fafb` 2026-05-24 `arkhe-amis-server/src/fee_schedule.rs`) via vendor
|
||
/// copy interim Option B (swap canonical post-OCAFB ratify o post Mathi
|
||
/// sub-crate ship). Scaffold-level v0.0.21: dispatchable
|
||
/// `compute_fee_for_action` placeholder, real impl v0.0.22 + Runtime API
|
||
/// v0.0.23.
|
||
///
|
||
/// Naming canonical: alias `Fees` (NO `OriginFees` que conflictaría con
|
||
/// el trait existente del mismo nombre en `origin_chain_types::pallets`,
|
||
/// pattern análogo Provenance Index 7).
|
||
#[runtime::pallet_index(8)]
|
||
pub type Fees = origin_chain_fees::Pallet<Runtime>;
|
||
|
||
/// AgentIdentity pallet canonical (Phase 2.7 v0.0.25 wired canonical per
|
||
/// CHN-7 + Inmutable #41 AGI Cross-Species Co-authorship). AGI DIDs
|
||
/// canonical on-chain — AGIs first-class citizens del Origin Metaverse
|
||
/// pueden owning assets + signing transactions + DAO voting via DIDs
|
||
/// registrados. Scaffold-level v0.0.25: dispatchable `register_agent_did`
|
||
/// placeholder, real impl v0.0.26 + Runtime API v0.0.27.
|
||
///
|
||
/// Naming canonical: alias `AgentIdentity` clearly distinguishes from
|
||
/// Substrate's `pallet-identity` (deferred canonical decision Phase 2.7
|
||
/// empírica 2026-05-21 documentada en configs.rs).
|
||
#[runtime::pallet_index(9)]
|
||
pub type AgentIdentity = origin_chain_agent_identity::Pallet<Runtime>;
|
||
|
||
/// Governance pallet canonical (Phase 5.1 v0.0.29 wired canonical per CHN-4
|
||
/// Foundation Treasury Governance). AI-Driven Human-Guarded canonical: 5 AI
|
||
/// advisor agents ADVISE only canonical, humans-only vote non-negotiable.
|
||
/// Scaffold-level v0.0.29: dispatchables submit_proposal + cast_vote +
|
||
/// finalize_proposal placeholders, real impl v0.0.30 + Runtime API v0.0.31.
|
||
///
|
||
/// Naming canonical: alias `Governance` clearly canonical (NO conflict con
|
||
/// trait `GovernanceProposal` en `origin_chain_types::governance`).
|
||
#[runtime::pallet_index(10)]
|
||
pub type Governance = origin_chain_governance::Pallet<Runtime>;
|
||
|
||
/// Revive pallet (Phase 3 Slice 3.1 v0.0.39 wired runtime canonical per SBS-5
|
||
/// ratificado, supersedes CHN-6 v1.0). Smart contracts PolkaVM RISC-V WASM
|
||
/// execution + ink! v6 (Rust) + Solidity (vía revive compiler) authoring paths.
|
||
/// AGI co-authoring preserved canonical (ink! v6 sigue siendo Rust-native).
|
||
/// Cross-pillar habilita: NFT mint (Marihan OMC), Escrow (Pilar 6),
|
||
/// Credential mint (Sussi Ethos), Staking (CHN-3 NPoS), origin-mdk
|
||
/// reconciliation (Marihan MDK §13). Scaffold-level v0.0.39: Config wired
|
||
/// con associated types per Asset Hub Westend reference + Origin chain_id
|
||
/// 9_120_005 (EIP-155 unique). Genesis + integration tests v0.0.40 +
|
||
/// ReviveApi v0.0.41.
|
||
#[runtime::pallet_index(11)]
|
||
pub type Revive = pallet_revive::Pallet<Runtime>;
|
||
|
||
/// Sudo pallet (FIX-5 governability per audit V2-CA1). Provee Root origin
|
||
/// para invocar las dispatchables admin de Governance (add/remove council,
|
||
/// mark/unmark advisor, treasury_disbursement — todas `ensure_root`, hoy
|
||
/// no-invocables) + descongela la tesorería 250M. Sunset canonical: sudo →
|
||
/// governance real (pallet-collective/referenda) ANTES de mainnet. Sudo key
|
||
/// interim = Foundation multisig humano (genesis).
|
||
#[runtime::pallet_index(12)]
|
||
pub type Sudo = pallet_sudo::Pallet<Runtime>;
|
||
|
||
/// Emission pallet (FIX-6 Stage 1 per audit V2-CA2). En cada bloque LIBERA un
|
||
/// block reward del pool Ecosystem finito (og/ecosy, techo duro 1B) y lo
|
||
/// reparte: autor Aura (validador) + treasury (og/gvtry) + subsidy pool
|
||
/// (og/subsy, proof-of-equity #16). Cierra "los validadores
|
||
/// ganan 0 OGC". sub_mult ortogonal (David 2026-06-10): el subsidy financia
|
||
/// el subsidio de hardware sin importar la suscripción.
|
||
#[runtime::pallet_index(13)]
|
||
pub type Emission = origin_chain_emission::Pallet<Runtime>;
|
||
|
||
/// Staking pallet (FIX-6 Stage 2b NPoS, DC ORIGIN_CHAIN_NPOS_V1). **Infra
|
||
/// DORMIDA**: la maquinaria NPoS está cableada pero el set de validadores
|
||
/// arranca fijo (invulnerables + ForceEra::ForceNone) — la cadena corre
|
||
/// PoA-equivalente hasta los 5 criterios de Phase 2 (CHN-1). La emisión
|
||
/// migra a EraPayout (preserva la tasa de Stage 1). Activación de la
|
||
/// elección-por-stake = governance flag (ForceNew) post-gates.
|
||
#[runtime::pallet_index(14)]
|
||
pub type Staking = pallet_staking::Pallet<Runtime>;
|
||
|
||
// Substrate pallet-identity DEFERRED canonical (decision empírica
|
||
// 2026-05-21 documentada en configs.rs). pallet-identity 41.0.0 ReservableCurrency
|
||
// compat work canonical hereda al custom `pallet_agent_identity` Phase 2.7
|
||
// (Inmutable #41 AGI DID Cross-Species Co-authorship).
|
||
}
|
||
|
||
// ============================================================
|
||
// Runtime APIs canonical (sp_api::impl_runtime_apis!)
|
||
// ============================================================
|
||
//
|
||
// **Filosofía canonical (David canon 2026-05-14)**: el `impl_runtime_apis!`
|
||
// macro materializa la frontera canonical entre **runtime sovereignty** (qué
|
||
// pallets compose el chain) + **node sovereignty** (cómo el binary canonical
|
||
// interactúa con el runtime canonical). Cada API canonical es un contrato
|
||
// canonical que el node binary canonical puede llamar sin importarle qué
|
||
// pallets specific componen el runtime — forkless upgrades canonical
|
||
// materializados.
|
||
//
|
||
// **APIs canonical implementadas (Phase 1.6)**:
|
||
// - `sp_api::Core` — version + execute_block + initialize_block canonical
|
||
// - `sp_api::Metadata` — runtime metadata para client/node introspection
|
||
// - `sp_block_builder::BlockBuilder` — para node block production canonical
|
||
// - `sp_transaction_pool::TaggedTransactionQueue` — pool canonical filtering
|
||
// - `sp_offchain::OffchainWorkerApi` — offchain workers canonical
|
||
// - `sp_session::SessionKeys` — session keys generation canonical
|
||
// - `sp_consensus_aura::AuraApi` — Aura slot duration + authorities canonical
|
||
// - `sp_consensus_grandpa::GrandpaApi` — GRANDPA authority set canonical
|
||
// - `frame_system_rpc_runtime_api::AccountNonceApi` — RPC nonce queries
|
||
// - `pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi` — fee queries
|
||
// - `sp_genesis_builder::GenesisBuilder` — genesis spec building canonical
|
||
|
||
impl_runtime_apis! {
|
||
impl sp_api::Core<Block> for Runtime {
|
||
fn version() -> sp_version::RuntimeVersion {
|
||
VERSION
|
||
}
|
||
|
||
fn execute_block(block: Block) {
|
||
Executive::execute_block(block);
|
||
}
|
||
|
||
fn initialize_block(header: &<Block as sp_runtime::traits::Block>::Header) -> sp_runtime::ExtrinsicInclusionMode {
|
||
Executive::initialize_block(header)
|
||
}
|
||
}
|
||
|
||
impl sp_api::Metadata<Block> for Runtime {
|
||
fn metadata() -> sp_core::OpaqueMetadata {
|
||
sp_core::OpaqueMetadata::new(Runtime::metadata().into())
|
||
}
|
||
|
||
fn metadata_at_version(version: u32) -> Option<sp_core::OpaqueMetadata> {
|
||
Runtime::metadata_at_version(version)
|
||
}
|
||
|
||
fn metadata_versions() -> Vec<u32> {
|
||
Runtime::metadata_versions()
|
||
}
|
||
}
|
||
|
||
impl sp_block_builder::BlockBuilder<Block> for Runtime {
|
||
fn apply_extrinsic(extrinsic: <Block as sp_runtime::traits::Block>::Extrinsic) -> sp_runtime::ApplyExtrinsicResult {
|
||
Executive::apply_extrinsic(extrinsic)
|
||
}
|
||
|
||
fn finalize_block() -> <Block as sp_runtime::traits::Block>::Header {
|
||
Executive::finalize_block()
|
||
}
|
||
|
||
fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as sp_runtime::traits::Block>::Extrinsic> {
|
||
data.create_extrinsics()
|
||
}
|
||
|
||
fn check_inherents(
|
||
block: Block,
|
||
data: sp_inherents::InherentData,
|
||
) -> sp_inherents::CheckInherentsResult {
|
||
data.check_extrinsics(&block)
|
||
}
|
||
}
|
||
|
||
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
|
||
fn validate_transaction(
|
||
source: sp_runtime::transaction_validity::TransactionSource,
|
||
tx: <Block as sp_runtime::traits::Block>::Extrinsic,
|
||
block_hash: <Block as sp_runtime::traits::Block>::Hash,
|
||
) -> sp_runtime::transaction_validity::TransactionValidity {
|
||
Executive::validate_transaction(source, tx, block_hash)
|
||
}
|
||
}
|
||
|
||
impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
|
||
fn offchain_worker(header: &<Block as sp_runtime::traits::Block>::Header) {
|
||
Executive::offchain_worker(header)
|
||
}
|
||
}
|
||
|
||
impl sp_session::SessionKeys<Block> for Runtime {
|
||
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
|
||
opaque::SessionKeys::generate(seed)
|
||
}
|
||
|
||
fn decode_session_keys(
|
||
encoded: Vec<u8>,
|
||
) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
|
||
opaque::SessionKeys::decode_into_raw_public_keys(&encoded)
|
||
}
|
||
}
|
||
|
||
impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
|
||
fn slot_duration() -> sp_consensus_aura::SlotDuration {
|
||
sp_consensus_aura::SlotDuration::from_millis(SLOT_DURATION)
|
||
}
|
||
|
||
fn authorities() -> Vec<AuraId> {
|
||
pallet_aura::Authorities::<Runtime>::get().into_inner()
|
||
}
|
||
}
|
||
|
||
impl sp_consensus_grandpa::GrandpaApi<Block> for Runtime {
|
||
fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList {
|
||
pallet_grandpa::Pallet::<Runtime>::grandpa_authorities()
|
||
}
|
||
|
||
fn current_set_id() -> sp_consensus_grandpa::SetId {
|
||
pallet_grandpa::Pallet::<Runtime>::current_set_id()
|
||
}
|
||
|
||
fn submit_report_equivocation_unsigned_extrinsic(
|
||
_equivocation_proof: sp_consensus_grandpa::EquivocationProof<
|
||
<Block as sp_runtime::traits::Block>::Hash,
|
||
BlockNumber,
|
||
>,
|
||
_key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof,
|
||
) -> Option<()> {
|
||
// Phase 1 PoA: equivocation reports not handled canonical.
|
||
// Phase 2 NPoS introduce real handler per CHN-3 slashing canonical.
|
||
None
|
||
}
|
||
|
||
fn generate_key_ownership_proof(
|
||
_set_id: sp_consensus_grandpa::SetId,
|
||
_authority_id: sp_consensus_grandpa::AuthorityId,
|
||
) -> Option<sp_consensus_grandpa::OpaqueKeyOwnershipProof> {
|
||
// Phase 1 PoA: no ownership proofs needed canonical.
|
||
None
|
||
}
|
||
}
|
||
|
||
impl frame_system_rpc_runtime_api::AccountNonceApi<Block, ChainAccountId, Nonce> for Runtime {
|
||
fn account_nonce(account: ChainAccountId) -> Nonce {
|
||
System::account_nonce(account)
|
||
}
|
||
}
|
||
|
||
impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
|
||
fn query_info(
|
||
uxt: <Block as sp_runtime::traits::Block>::Extrinsic,
|
||
len: u32,
|
||
) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
|
||
TransactionPayment::query_info(uxt, len)
|
||
}
|
||
|
||
fn query_fee_details(
|
||
uxt: <Block as sp_runtime::traits::Block>::Extrinsic,
|
||
len: u32,
|
||
) -> pallet_transaction_payment::FeeDetails<Balance> {
|
||
TransactionPayment::query_fee_details(uxt, len)
|
||
}
|
||
|
||
fn query_weight_to_fee(weight: frame_support::weights::Weight) -> Balance {
|
||
TransactionPayment::weight_to_fee(weight)
|
||
}
|
||
|
||
fn query_length_to_fee(length: u32) -> Balance {
|
||
TransactionPayment::length_to_fee(length)
|
||
}
|
||
}
|
||
|
||
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
|
||
fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
|
||
frame_support::genesis_builder_helper::build_state::<RuntimeGenesisConfig>(config)
|
||
}
|
||
|
||
fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
|
||
// Canonical Phase 1.7: 3 presets disponibles canonical (development +
|
||
// local_testnet + mainnet_genesis). Cuando feature `std` activo
|
||
// (chain_spec generation time), delegamos canonical al
|
||
// `genesis_config_presets::get_preset`. En no_std (WASM runtime),
|
||
// siempre return None canonical — los presets canonical solo se
|
||
// consultan en chain_spec generation, no en runtime execution.
|
||
#[cfg(feature = "std")]
|
||
{
|
||
frame_support::genesis_builder_helper::get_preset::<RuntimeGenesisConfig>(
|
||
id,
|
||
genesis_config_presets::get_preset,
|
||
)
|
||
}
|
||
#[cfg(not(feature = "std"))]
|
||
{
|
||
let _ = id;
|
||
None
|
||
}
|
||
}
|
||
|
||
fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
|
||
#[cfg(feature = "std")]
|
||
{
|
||
genesis_config_presets::preset_names()
|
||
}
|
||
#[cfg(not(feature = "std"))]
|
||
{
|
||
Vec::new()
|
||
}
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// PROV-8 canonical: Provenance Runtime API canonical (Phase 2.1 v0.0.17)
|
||
// ============================================================
|
||
//
|
||
// Light clients + indexers + cross-pillar consumers (Trinity / Codex /
|
||
// Codex origindocs / Ethos / Atelier) pueden query attestation status
|
||
// via RPC sin full node access canonical.
|
||
//
|
||
// Pattern canonical: light client sends BLAKE3 hash → recibe Option<AssetAttestation>
|
||
// (Some si attested previamente, None si nunca attested canonical).
|
||
|
||
impl origin_chain_provenance::ProvenanceApi<Block> for Runtime {
|
||
fn verify_provenance(
|
||
hash: origin_chain_types::AssetHash,
|
||
) -> Option<origin_chain_types::AssetAttestation> {
|
||
Provenance::attestation_of(hash)
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// OCAFB-7 canonical: Fees Runtime API canonical (Phase 2.4 v0.0.23)
|
||
// ============================================================
|
||
//
|
||
// Cross-pillar consumers (Mathi AMIS / Irhis Web / Trinity / Codex / Atelier)
|
||
// pueden query fee preview canonical via RPC sin full node access. Pattern
|
||
// canonical análogo ProvenanceApi (Phase 2.1 v0.0.17) — read-only RPC query
|
||
// sin storage mutation.
|
||
//
|
||
// Phase 2.4 COMPLETE 7/7 OCAFB canonical post-v0.0.23 🎉
|
||
|
||
impl origin_chain_fees::FeesApi<Block> for Runtime {
|
||
fn query_fee_for_action(
|
||
action: origin_chain_types::ChainAction,
|
||
base: u64,
|
||
hw: origin_chain_types::HardwareTier,
|
||
sub: origin_chain_types::SubscriptionTier,
|
||
) -> u64 {
|
||
Fees::query_fee(action, base, hw, sub)
|
||
}
|
||
|
||
fn query_fee_for_account(
|
||
action: origin_chain_types::ChainAction,
|
||
base: u64,
|
||
account: origin_chain_types::AccountId,
|
||
) -> u64 {
|
||
// account es el newtype origin_chain_types::AccountId; el storage key
|
||
// canonical es ChainAccountId = AccountId32 (32-byte, bytes-level).
|
||
let runtime_account = ChainAccountId::from(account.0);
|
||
Fees::query_fee_for_account(action, base, &runtime_account)
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// Phase 2.7 canonical: AgentIdentity Runtime API canonical (v0.0.27)
|
||
// ============================================================
|
||
//
|
||
// Cross-pillar consumers (Trinity / Mathi / Codex / Atelier / Ethos / Ergon)
|
||
// pueden query agent identity canonical via RPC sin full node access.
|
||
// Pattern canonical análogo ProvenanceApi (Phase 2.1 v0.0.17) + FeesApi
|
||
// (Phase 2.4 v0.0.23) — read-only RPC query canonical sin storage mutation.
|
||
//
|
||
// Phase 2.7 COMPLETE canonical post-v0.0.27 🎉
|
||
|
||
impl origin_chain_agent_identity::AgentIdentityApi<Block> for Runtime {
|
||
fn query_identity(
|
||
account: origin_chain_types::AccountId,
|
||
) -> Option<origin_chain_types::AgentIdentity> {
|
||
// Note: account es origin_chain_types::AccountId newtype, but storage
|
||
// canonical key es T::AccountId = ChainAccountId = AccountId32. Convert
|
||
// canonical bytes-level (both son 32-byte representations).
|
||
let runtime_account = ChainAccountId::from(account.0);
|
||
AgentIdentity::query_identity_of(&runtime_account)
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// Phase 5.1 canonical: Governance Runtime API canonical (v0.0.31)
|
||
// ============================================================
|
||
//
|
||
// Foundation governance frontend + 5 AI advisor agents (advise-only canonical)
|
||
// + cross-pillar consumers query canonical proposals + vote stances sin full
|
||
// node access. Pattern análogo ProvenanceApi + FeesApi + AgentIdentityApi —
|
||
// read-only RPC query canonical sin storage mutation.
|
||
//
|
||
// Phase 5.1 FOUNDATION COMPLETE canonical post-v0.0.31 🎉
|
||
|
||
impl origin_chain_governance::GovernanceApi<Block> for Runtime {
|
||
fn query_proposal(
|
||
id: origin_chain_types::ProposalId,
|
||
) -> Option<origin_chain_governance::Proposal> {
|
||
Governance::query_proposal_of(id)
|
||
}
|
||
|
||
fn query_vote(
|
||
proposal_id: origin_chain_types::ProposalId,
|
||
voter: origin_chain_types::AccountId,
|
||
) -> Option<origin_chain_types::VoteStance> {
|
||
let runtime_voter = ChainAccountId::from(voter.0);
|
||
Governance::query_vote_of(proposal_id, &runtime_voter)
|
||
}
|
||
|
||
// Phase 5.2 v0.0.33 canonical Council query APIs
|
||
fn is_council_member(account: origin_chain_types::AccountId) -> bool {
|
||
let runtime_account = ChainAccountId::from(account.0);
|
||
Governance::is_council_member(&runtime_account)
|
||
}
|
||
|
||
fn current_council_size() -> u32 {
|
||
Governance::current_council_size()
|
||
}
|
||
|
||
fn veto_votes_count(proposal_id: origin_chain_types::ProposalId) -> u32 {
|
||
Governance::veto_count_of(proposal_id)
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// frame_benchmarking::Benchmark — runtime API para `benchmark pallet`
|
||
// ============================================================
|
||
//
|
||
// Solo bajo la feature `runtime-benchmarks`. Expone la maquinaria FRAME v2 de
|
||
// los pallets custom (ver `benches` mod + `define_benchmarks!`). La GENERACIÓN
|
||
// de números canónicos por CLI está gated por el node sc-service o
|
||
// omni-bencher+WASM (ambos bloqueados hace sesiones, ver `main.rs` §BLOQUEO y
|
||
// el §Estado de cada `weights.rs`); mientras tanto los `SubstrateWeight` llevan
|
||
// números conservadores DB-aware. Este impl compila y queda listo para que el
|
||
// loop de medición sea mecánico cuando la infra aterrice.
|
||
#[cfg(feature = "runtime-benchmarks")]
|
||
impl frame_benchmarking::Benchmark<Block> for Runtime {
|
||
fn benchmark_metadata(
|
||
extra: bool,
|
||
) -> (
|
||
alloc::vec::Vec<frame_benchmarking::BenchmarkList>,
|
||
alloc::vec::Vec<frame_support::traits::StorageInfo>,
|
||
) {
|
||
use frame_support::traits::StorageInfoTrait;
|
||
|
||
let mut list = alloc::vec::Vec::<frame_benchmarking::BenchmarkList>::new();
|
||
list_benchmarks!(list, extra);
|
||
|
||
let storage_info = AllPalletsWithSystem::storage_info();
|
||
(list, storage_info)
|
||
}
|
||
|
||
fn dispatch_benchmark(
|
||
config: frame_benchmarking::BenchmarkConfig,
|
||
) -> Result<alloc::vec::Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String>
|
||
{
|
||
use frame_support::traits::TrackedStorageKey;
|
||
|
||
// Whitelist vacía: cada benchmark siembra su propio estado (validador
|
||
// golden, etc.) y no depende de claves pre-existentes.
|
||
let whitelist: alloc::vec::Vec<TrackedStorageKey> = alloc::vec::Vec::new();
|
||
|
||
let mut batches = alloc::vec::Vec::<frame_benchmarking::BenchmarkBatch>::new();
|
||
let params = (&config, &whitelist);
|
||
add_benchmarks!(params, batches);
|
||
|
||
Ok(batches)
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// Phase 3 Slice 3.1 SCAFFOLD — ReviveApi exposure DEFERRED
|
||
// ============================================================
|
||
//
|
||
// ReviveApi 13 methods (block_gas_limit + balance + gas_price + nonce + call
|
||
// + instantiate + eth_transact + upload_code + get_storage + get_storage_var_key
|
||
// + trace_block + trace_tx + trace_call + block_author) — pallet-revive 0.10.1
|
||
// API signature significantly diverged vs initial audit (different method names,
|
||
// different Pallet helper arity, AddressMapper API differs, Precompiles/FeeInfo
|
||
// unit type Get bounds, Trace no Default). 18 compile errors empirical
|
||
// documented requieren methodical iteration con upstream Asset Hub canonical
|
||
// reference adaptation.
|
||
//
|
||
// Decisión pragmática Slice 3.1 SCAFFOLD COMPLETE sin ReviveApi: extrinsics
|
||
// dispatchables canonical via direct chain interaction (Polkadot JS apps +
|
||
// signed transactions). RPC layer ReviveApi NO bloquea contract deployment
|
||
// ni Slices 3.2-3.6 contract templates. Deferred a Slice 3.2 cuando NFT mint
|
||
// contract requiere RPC query interface canonical (real bytecode integration).
|
||
//
|
||
// Trade-off documented: Slice 3.1 SCAFFOLD ships sin Ethereum-compat RPC.
|
||
// Production canonical needs ReviveApi Phase 3.x maduración.
|
||
//
|
||
// Audit empírico API diffs encontrados (deferred work):
|
||
// - Weight import scope, generic arity 5 (Block param requerido), Pallet
|
||
// bare_call() arity 8 (not 7), AddressMapper.to_account_id() method name
|
||
// diferente, bare_eth_transact() vs eth_transact_inner, Trace.default()
|
||
// no derived. Methodical Asset Hub reference adaptation Slice 3.2 ship.
|
||
/*
|
||
|
||
fn trace_tx(
|
||
_block: Block,
|
||
_tx_index: u32,
|
||
_config: pallet_revive::evm::TracerType,
|
||
) -> Option<pallet_revive::evm::Trace> {
|
||
// Slice 3.1 SCAFFOLD: tracing returns None.
|
||
None
|
||
}
|
||
|
||
fn trace_call(
|
||
_tx: pallet_revive::evm::GenericTransaction,
|
||
_config: pallet_revive::evm::TracerType,
|
||
) -> Result<pallet_revive::evm::Trace, pallet_revive::EthTransactError> {
|
||
// Slice 3.1 SCAFFOLD: tracing returns empty Trace.
|
||
Ok(pallet_revive::evm::Trace::default())
|
||
}
|
||
|
||
fn block_author() -> Option<sp_core::H160> {
|
||
// Phase 1 PoA: sin pallet_authorship integration canonical.
|
||
// Phase 4 testnet decision: add pallet_authorship OR custom FindAuthor.
|
||
None
|
||
}
|
||
}
|
||
*/
|
||
}
|
||
|
||
// ============================================================
|
||
// Registro de benchmarks canonical (frame_benchmarking::define_benchmarks!)
|
||
// ============================================================
|
||
//
|
||
// Lista los pallets custom cuya maquinaria FRAME v2 se expone vía el runtime API
|
||
// `Benchmark`. Genera los macros `list_benchmarks!` + `add_benchmarks!` (ambos
|
||
// `#[macro_export]` → crate-global). Cada `[crate_path, PalletAlias]` mapea al
|
||
// alias del `#[runtime]` de arriba. Los pallets upstream (balances/timestamp/…)
|
||
// se benchmarkean con sus propios weights ya generados; aquí solo van los míos.
|
||
#[cfg(feature = "runtime-benchmarks")]
|
||
mod benches {
|
||
frame_benchmarking::define_benchmarks!(
|
||
[origin_chain_provenance, Provenance]
|
||
[origin_chain_fees, Fees]
|
||
[origin_chain_agent_identity, AgentIdentity]
|
||
[origin_chain_emission, Emission]
|
||
[origin_chain_governance, Governance]
|
||
);
|
||
}
|
||
|
||
// ============================================================
|
||
// Runtime metadata canonical (RuntimeVersion + Executive)
|
||
// ============================================================
|
||
|
||
/// Canonical `RuntimeVersion` per Substrate canonical. Consumed by `sp_api::Core::version()`.
|
||
pub const VERSION: sp_version::RuntimeVersion = sp_version::RuntimeVersion {
|
||
spec_name: alloc::borrow::Cow::Borrowed(SPEC_NAME),
|
||
impl_name: alloc::borrow::Cow::Borrowed(IMPL_NAME),
|
||
authoring_version: AUTHORING_VERSION,
|
||
spec_version: RUNTIME_VERSION,
|
||
impl_version: IMPL_VERSION,
|
||
apis: RUNTIME_API_VERSIONS,
|
||
transaction_version: TRANSACTION_VERSION,
|
||
system_version: STATE_VERSION,
|
||
};
|
||
|
||
/// Canonical Executive type canonical (FRAME executive wrapper).
|
||
pub type Executive = frame_executive::Executive<
|
||
Runtime,
|
||
Block,
|
||
frame_system::ChainContext<Runtime>,
|
||
Runtime,
|
||
AllPalletsWithSystem,
|
||
(),
|
||
>;
|
||
|
||
use sp_api::impl_runtime_apis;
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn runtime_version_v9_benchmarking_weights() {
|
||
// v9 = benchmarking real machinery: los 19 extrinsics de los 5 pallets
|
||
// custom pasan de weights placeholder (proof_size=0, DoS) a weights INTERIM
|
||
// hand-derived DB-aware vía WeightInfo. Los weights son consenso-relevantes
|
||
// (fee + llenado de bloque) ⇒ spec bump. Las FIRMAS de los extrinsics NO
|
||
// cambian ⇒ TRANSACTION_VERSION intacto.
|
||
assert_eq!(RUNTIME_VERSION, 9);
|
||
assert_eq!(TRANSACTION_VERSION, 1);
|
||
}
|
||
|
||
#[test]
|
||
fn staking_pallet_index_14_npos_dormant() {
|
||
use frame_support::traits::PalletInfoAccess;
|
||
// FIX-6 Stage 2b: Staking=14 (post Emission=13). Infra NPoS dormida —
|
||
// presente pero el set sigue fijo (PoA-equivalente) hasta los gates CHN-1.
|
||
assert_eq!(<crate::Staking as PalletInfoAccess>::index(), 14);
|
||
assert_eq!(<crate::Staking as PalletInfoAccess>::name(), "Staking");
|
||
}
|
||
|
||
#[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);
|
||
}
|
||
|
||
// ============================================================
|
||
// Phase 3 Slice 3.1 v0.0.40 — pallet-revive integration tests E2E
|
||
// SCAFFOLD-level: verify Config wiring + constants + AddressMapper +
|
||
// Genesis. Real PolkaVM bytecode E2E deferred a Phase 3.x maduración
|
||
// post cargo-contract v6 install + ink! v6 contract templates (Slice 3.2+).
|
||
// ============================================================
|
||
|
||
#[test]
|
||
fn revive_chain_id_eip155_unique_origin_metaverse() {
|
||
// OriginChainId canonical 9_120_005 — EIP-155 unique identifier
|
||
// previene cross-chain replay attacks canonical post-mainnet.
|
||
use frame_support::traits::Get;
|
||
let chain_id: u64 = <<Runtime as pallet_revive::Config>::ChainId>::get();
|
||
assert_eq!(chain_id, 9_120_005_u64);
|
||
}
|
||
|
||
#[test]
|
||
fn revive_native_to_eth_ratio_one_to_one() {
|
||
// OGC tiene 18 decimales (Ogc::DECIMALS) = la precisión de ETH ⇒ ratio
|
||
// 1:1. El 10^6 anterior era herencia del template (nativo 12 dec) y
|
||
// distorsionaba la capa EVM ×10^6 (audit ultra 2026-07-02, fix v6).
|
||
// Guard de coherencia: el ratio DEBE derivar de la delta de decimales.
|
||
use frame_support::traits::Get;
|
||
let ratio: u32 = <<Runtime as pallet_revive::Config>::NativeToEthRatio>::get();
|
||
const ETH_DECIMALS: u32 = 18;
|
||
let expected = 10_u32.pow(ETH_DECIMALS - origin_chain_types::Ogc::DECIMALS);
|
||
assert_eq!(ratio, expected);
|
||
assert_eq!(ratio, 1_u32);
|
||
}
|
||
|
||
#[test]
|
||
fn fee_multiplier_update_never_collapses_to_zero() {
|
||
// Regresión del audit ultra 2026-07-02: `FeeMultiplierUpdate = ()`
|
||
// devolvía Default (= 0) en cada on_finalize ⇒ NextFeeMultiplier
|
||
// colapsaba a 0 tras el bloque 1 y el weight-fee desaparecía de toda
|
||
// la cadena. El update JAMÁS puede mapear 1 → 0.
|
||
use pallet_transaction_payment::Multiplier;
|
||
use sp_runtime::traits::{Convert, Zero};
|
||
let one = Multiplier::from_u32(1);
|
||
let next =
|
||
<<Runtime as pallet_transaction_payment::Config>::FeeMultiplierUpdate as Convert<
|
||
Multiplier,
|
||
Multiplier,
|
||
>>::convert(one);
|
||
assert_eq!(next, one, "el multiplier debe permanecer en 1, no colapsar");
|
||
assert!(!next.is_zero());
|
||
}
|
||
|
||
#[test]
|
||
fn weight_to_fee_transfer_tiene_dientes_no_polvo() {
|
||
// Calibración David 2026-07-03 (v7): un transfer simple debe costar ~1
|
||
// MILLI_OGC, NO el polvo ~10^-10 OGC de IdentityFee (que anulaba el #16).
|
||
// Guard de regresión: si alguien revierte a IdentityFee, el fee cae a
|
||
// ~1.5×10^8 base units (muy por debajo de MILLI_OGC/2) y esto rompe.
|
||
use frame_support::weights::{Weight, WeightToFee as _};
|
||
// transfer ≈ ExtrinsicBaseWeight (108.157M) + transfer_keep_alive (~39M).
|
||
let transfer_weight = Weight::from_parts(108_157_000 + 39_051_000, 0);
|
||
let fee = <<Runtime as pallet_transaction_payment::Config>::WeightToFee>::weight_to_fee(
|
||
&transfer_weight,
|
||
);
|
||
assert!(
|
||
fee >= MILLI_OGC / 2 && fee <= MILLI_OGC * 3,
|
||
"fee de transfer = {fee} base units; esperado ~1 MILLI_OGC ({MILLI_OGC}), \
|
||
ni polvo ni exorbitante"
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn revive_deposit_per_byte_canonical_milli_ogc() {
|
||
// Asset Hub pattern adapted OGC tokenomics — 1 MILLI_OGC per byte canonical.
|
||
use frame_support::traits::Get;
|
||
let deposit_per_byte: Balance =
|
||
<<Runtime as pallet_revive::Config>::DepositPerByte>::get();
|
||
assert_eq!(deposit_per_byte, MILLI_OGC);
|
||
assert_eq!(deposit_per_byte, Ogc::ONE / 1_000);
|
||
}
|
||
|
||
#[test]
|
||
fn revive_deposit_per_item_canonical_one_ogc() {
|
||
// Storage item deposit = 1 OGC canonical (gate storage proliferation).
|
||
use frame_support::traits::Get;
|
||
let deposit_per_item: Balance =
|
||
<<Runtime as pallet_revive::Config>::DepositPerItem>::get();
|
||
assert_eq!(deposit_per_item, Ogc::ONE);
|
||
}
|
||
|
||
#[test]
|
||
fn revive_evm_bytecode_allowed_canonical() {
|
||
// SBS-5 ratificado: Solidity contracts deployables via revive compiler.
|
||
// AllowEVMBytecode = true canonical para opens Ethereum dev ecosystem.
|
||
use frame_support::traits::Get;
|
||
let allow_evm: bool = <<Runtime as pallet_revive::Config>::AllowEVMBytecode>::get();
|
||
assert!(allow_evm, "EVM bytecode must be allowed per SBS-5 ratified");
|
||
}
|
||
|
||
#[test]
|
||
fn revive_runtime_memory_128_mb_canonical() {
|
||
// RuntimeMemory canonical 128 MB — runtime memory allocation budget.
|
||
use frame_support::traits::Get;
|
||
let runtime_memory: u32 = <<Runtime as pallet_revive::Config>::RuntimeMemory>::get();
|
||
assert_eq!(runtime_memory, 128_u32 * 1024 * 1024);
|
||
}
|
||
|
||
#[test]
|
||
fn revive_pvf_memory_2_gb_canonical_integrity_pass() {
|
||
// PVFMemory canonical 2 GB — required canonical para pass
|
||
// __construct_runtime_integrity_test (formula: storage_limit =
|
||
// (PVFMemory - RuntimeMemory) / 2 > max_storage_size ~650 MB).
|
||
use frame_support::traits::Get;
|
||
let pvf_memory: u32 = <<Runtime as pallet_revive::Config>::PVFMemory>::get();
|
||
assert_eq!(pvf_memory, 2_u32 * 1024 * 1024 * 1024);
|
||
// Verify integrity formula passes canonical
|
||
let runtime_memory: u32 = <<Runtime as pallet_revive::Config>::RuntimeMemory>::get();
|
||
let storage_limit: u32 = (pvf_memory - runtime_memory) / 2;
|
||
// ~960 MB storage limit canonical — comfortably above 650 MB max storage.
|
||
assert!(
|
||
storage_limit > 700_u32 * 1024 * 1024,
|
||
"storage_limit must exceed 700 MB para pallet-revive integrity canonical"
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn revive_safety_toggles_production_safe_canonical() {
|
||
// Production canonical safety: UnsafeUnstableInterface=false.
|
||
// DebugEnabled NO disponible en pallet-revive 0.10.1 (added 0.12+).
|
||
use frame_support::traits::Get;
|
||
let unsafe_interface: bool =
|
||
<<Runtime as pallet_revive::Config>::UnsafeUnstableInterface>::get();
|
||
assert!(
|
||
!unsafe_interface,
|
||
"Unstable interface MUST be disabled en production runtime canonical"
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn revive_pallet_index_11_canonical_post_governance() {
|
||
// Pallet index canonical: Revive=11 (post Governance=10 Phase 5.1).
|
||
// Asegura orden storage migrations canonical canonical preservado.
|
||
use frame_support::traits::PalletInfoAccess;
|
||
assert_eq!(<crate::Revive as PalletInfoAccess>::index(), 11);
|
||
assert_eq!(<crate::Revive as PalletInfoAccess>::name(), "Revive");
|
||
}
|
||
|
||
#[test]
|
||
fn sudo_pallet_index_12_canonical_governability() {
|
||
// FIX-5: Sudo=12 (post Revive=11). Root origin para las dispatchables
|
||
// admin de Governance (audit V2-CA1). Sunset → governance real pre-mainnet.
|
||
use frame_support::traits::PalletInfoAccess;
|
||
assert_eq!(<crate::Sudo as PalletInfoAccess>::index(), 12);
|
||
assert_eq!(<crate::Sudo as PalletInfoAccess>::name(), "Sudo");
|
||
}
|
||
|
||
#[test]
|
||
fn emission_pallet_index_13_canonical() {
|
||
// FIX-6 Stage 1: Emission=13 (post Sudo=12). Paga validadores Aura (V2-CA2).
|
||
use frame_support::traits::PalletInfoAccess;
|
||
assert_eq!(<crate::Emission as PalletInfoAccess>::index(), 13);
|
||
assert_eq!(<crate::Emission as PalletInfoAccess>::name(), "Emission");
|
||
}
|
||
|
||
#[test]
|
||
fn revive_address_mapper_account32_returns_h160_canonical() {
|
||
// AccountId32Mapper canonical: AccountId32 → H160 mapping deterministic.
|
||
// BLAKE2b derivation per Asset Hub canonical solochain pattern.
|
||
// Slice 3.1 SCAFFOLD: verify mapper type bound, no real address conversion
|
||
// (requires pallet runtime context). Phase 3.x maduración: real mapping tests.
|
||
use pallet_revive::AddressMapper;
|
||
type ConfiguredMapper = <Runtime as pallet_revive::Config>::AddressMapper;
|
||
// Compile-time verification que el mapper type implements AddressMapper trait
|
||
fn _verify_implements_mapper<M: AddressMapper<Runtime>>() {}
|
||
_verify_implements_mapper::<ConfiguredMapper>();
|
||
}
|
||
}
|