Files
arkhe-origin-chain/crates/origin-chain-runtime/src/lib.rs
T
davidherranandClaude Opus 4.8 c7fc6a88fc feat(bench): maquinaria FRAME v2 de benchmarking para los 5 pallets custom (RV 8→9)
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>
2026-07-07 22:48:26 -05:00

1171 lines
54 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;
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>();
}
}