Files
arkhe-origin-chain/crates/origin-chain-runtime/src/lib.rs
T
davidherranandClaude Fable 5 3364994cce feat(fees): FIX-6 Stage 2a — fee unificado (cierra V2-CA3)
Pone la fórmula OCAFB-5 en el fee-path VIVO: OriginFeeAdapter
(OnChargeTransaction custom) reemplaza al FungibleAdapter tier-blind.
El firmante paga su fracción según (HardwareTier × ChainAction ×
SubscriptionTier, tiers leídos ON-CHAIN de TierProfiles — jamás
caller-supplied), y el subsidy pool og/subsy (alimentado por la
emisión Stage 1) cubre la fracción subsidiada. Inmutable #16 en cada
transacción. OU=() = burn 100% gas fees (matriz CHN-2).

unified_fee (u128, outcome tipado FeeOutcome — sin el sentinel
u64::MAX in-band): user = fórmula vendor Mathi byte-fiel (test de
paridad grid contra ce4fafb); pool = net × subsidy_bp/1e4 sobre el
COSTO BASE (anti-regresivo, sub_mult ORTOGONAL: un Ultra NO drena el
pool más que un Free — el premium lo paga el usuario, no el commons).

Hallazgos de la verificación adversarial (workflow ultracode, 4
lentes) cerrados de raíz:
- HIGH: clasificador cubre eth_instantiate_with_code (call_index 10)
  — evadía el entitlement-gate DeployContract vía fallback Write.
- MEDIUM ledger envenenable: removido el dispatchable legacy
  compute_fee_for_action (tiers caller-supplied, escribía AccountFees
  sin cobrar). AccountFees ahora escrito SOLO por el fee-path vivo
  (note_settlement). Eventos que nunca se emitían eliminados; el
  preview read-only vive en query_fee / FeesApi.
- MEDIUM drenaje del pool por sub_mult: pool sobre net, no sobre el
  precio premium (Opción B anti-regresiva).
- Dev UX: GenesisConfig siembra perfiles iniciales; dev/local
  arrancan Ultra (los Slices 3.x de contracts no se bloquean por
  Free+DeployContract); mainnet vacío (Default conservador hasta
  attestation).

Decisión de diseño (autoridad Pilar 4): replay de attestation =
RECHAZO explícito, no dedup silencioso (notificado a Ergon para el
reference impl). Orden OCAFB-5 subsidy-antes-de-entitlement preservado
byte-fiel + notificado a Mathi para el ratify 2026-06-21.

set_tier_profile Root-only interim (sunset a attestation-driven vía
Mathi PerceptionAdapter + DID binding FIX-3/FIX-4). spec_version 1→2
(formato de extrinsic intacto, TRANSACTION_VERSION=1).

Tests: 49 crate fees (paridad grid + lobo blanco ortogonalidad +
refund + pool seco + tip passthrough + entitlement blocked) + 21
suites workspace verde. Toolchain cargo +1.88.

Nota WASM: el build local del runtime WASM falla en la
post-validación del substrate-wasm-builder con UnknownOpcode(252)
— límite del toolchain (Rust 1.88 emite opcodes 0xFC que el parser
del builder de stable2509 no deserializa). Reproducido idéntico en
el HEAD intacto (v0.0.57): es ambiental, no de este cambio. El node
real + WASM artifact siguen VPS-gated (toolchain alineado /
wasm32v1-none cuando el wasm-builder lo soporte).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 20:22:14 -05:00

989 lines
44 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;
#[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).
pub const RUNTIME_VERSION: u32 = 2;
/// 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 mintea un
/// block reward 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>;
// 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)
}
}
// ============================================================
// 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)
}
}
// ============================================================
// 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
}
}
*/
}
// ============================================================
// 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_v2_fee_unificado() {
// v2 = FIX-6 Stage 2a (fee unificado). El formato de extrinsic NO
// cambió: solo el associated type OnChargeTransaction.
assert_eq!(RUNTIME_VERSION, 2);
assert_eq!(TRANSACTION_VERSION, 1);
}
#[test]
fn canonical_spec_name_origin_chain() {
assert_eq!(SPEC_NAME, "origin-chain");
assert_eq!(IMPL_NAME, "origin-chain-charon");
}
#[test]
fn balance_type_holds_genesis_supply_canonical_with_safety_margin() {
let genesis_supply: Balance = 1_000_000_000_u128 * Ogc::ONE;
let margin = Balance::MAX / genesis_supply;
assert!(margin > 100, "Balance safety margin canonical >100x");
}
#[test]
fn block_number_overflow_margin_centuries_canonical() {
let seconds_until_overflow: u64 = (BlockNumber::MAX as u64) * 6;
let years_until_overflow = seconds_until_overflow / 31_536_000;
assert!(years_until_overflow > 100, "BlockNumber holds >100 años canonical");
}
#[test]
fn canonical_traits_reexported_for_pallet_consumers() {
let _ogc = Ogc::from_whole(100);
let _hash = AssetHash::ZERO;
let _tier = HardwareTier::Desktop;
let _quality = AssetQualityTier::Standard;
let _reason = SlashReason::TierFraud; // Inmutable #16 enforcement canonical
}
#[test]
fn existential_deposit_canonical_is_one_milli_ogc() {
// Inmutable #16 anti-clasista: ED debe ser trivial para Pi 5 rural users
assert_eq!(EXISTENTIAL_DEPOSIT, MILLI_OGC);
assert_eq!(EXISTENTIAL_DEPOSIT, Ogc::ONE / 1_000);
}
#[test]
fn block_hash_count_aligned_with_chn_1_epoch_canonical() {
// CHN-1 epoch rotation = 4 hours
// BLOCK_HASH_COUNT * 6s = 14400s = 4 hours exact
assert_eq!(BLOCK_HASH_COUNT, 2400);
assert_eq!(BLOCK_HASH_COUNT as u64 * 6, 14_400); // 4 hours = 14400 seconds
}
#[test]
fn slot_duration_canonical_six_seconds() {
// CHN-1 Aura slot duration canonical
assert_eq!(MILLISECS_PER_BLOCK, 6_000);
assert_eq!(SLOT_DURATION, MILLISECS_PER_BLOCK);
}
// ============================================================
// 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_million_canonical() {
// OGC 12 decimals → ETH 18 decimals = ratio 10^6 canonical.
// Mapping balance OGC↔ETH-equivalent units para EVM compat.
use frame_support::traits::Get;
let ratio: u32 = <<Runtime as pallet_revive::Config>::NativeToEthRatio>::get();
assert_eq!(ratio, 1_000_000_u32);
}
#[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>();
}
}