feat(emission): governance kill-switch — set_emission_paused (FIX-6 Stage 2b)

Añade EmissionPaused (StorageValue<bool>, ValueQuery default false = emisión
ACTIVA, sin migración) + set_emission_paused(paused) Root-gated + guard en
on_initialize. Palanca de governance para pausar la inflación per-block.

Es el kill-switch anti-doble-emisión para la activación de NPoS: cuando
pallet_staking::EraPayout empiece a pagar por-era (en el spec upgrade de
activación que swap-ea SessionManager→Staking + historical + multi-phase/
bags-list), Root pausa esta emisión en el MISMO upgrade. Mientras EraPayout
esté dormido (ForceNone), esta es la única fuente de emisión: cero doble-emisión
posible hoy. TotalEmitted se PRESERVA al pausar (histórico de inflación intacto).
Idempotencia rechazada (EmissionPauseUnchanged) para que cada cambio de
governance sea un evento observable on-chain.

HALLAZGO (audit-before-claims contra la fuente): los Pasos B-E originales asumían
que la activación sería un flag-flip, pero (1) #[frame_support::runtime] ordena
los pallets por índice (Session=6 < Staking=14) y el génesis de Session invoca la
elección de staking → el génesis de Staking debe ir ANTES (requiere legacy_ordering
o renumerar índices); (2) la activación con nominación masiva necesita multi-phase
+ bags-list = spec upgrade de todas formas, donde el session-swap viaja gratis. Por
eso el session-swap se difiere a la activación (decisión David) y aquí shippeo solo
lo seguro e incondicional. EraPayout/RewardRemainder ya probados (Paso A).

RUNTIME_VERSION 3→4 (nuevo call ⇒ metadata cambia; call aditivo en call_index
nuevo ⇒ TRANSACTION_VERSION 1 intacto). 21 suites / 267 workspace verde, 0 regresión.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
davidherranandClaude Opus 4.8 committed 2026-06-17 06:58:35 -05:00
1 parent ca50938495
commit af1c75b329
2 files changed
+153 -8

No files matched your search

+10 -5
View File
@@ -229,7 +229,11 @@ pub const IMPL_NAME: &str = "origin-chain-charon";
/// 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).
pub const RUNTIME_VERSION: u32 = 3;
/// 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.
pub const RUNTIME_VERSION: u32 = 4;
/// Canonical authoring version per Substrate semver canonical.
pub const AUTHORING_VERSION: u32 = 1;
@@ -810,10 +814,11 @@ mod tests {
use super::*;
#[test]
fn runtime_version_v3_npos_staking_dormant() {
// v3 = FIX-6 Stage 2b NPoS Paso A (pallet_staking Index 14, infra
// dormida). El formato de extrinsic NO cambió.
assert_eq!(RUNTIME_VERSION, 3);
fn runtime_version_v4_emission_kill_switch() {
// v4 = FIX-6 Stage 2b governance emission kill-switch (nuevo call en
// Emission Index 13). El formato de extrinsic de los calls EXISTENTES NO
// cambió (call aditivo en call_index nuevo) ⇒ TRANSACTION_VERSION intacto.
assert_eq!(RUNTIME_VERSION, 4);
assert_eq!(TRANSACTION_VERSION, 1);
}